Example #1
0
/* Callback function to try the unprotection from the passpharse query
   code. */
static int
try_unprotect_cb (struct pin_entry_info_s *pi)
{
  struct try_unprotect_arg_s *arg = pi->check_cb_arg;
  size_t dummy;
  gpg_error_t err;
  gnupg_isotime_t now, protected_at, tmptime;
  char *desc = NULL;

  assert (!arg->unprotected_key);

  arg->change_required = 0;
  err = agent_unprotect (arg->protected_key, pi->pin, protected_at,
                         &arg->unprotected_key, &dummy);
  if (err)
    return err;
  if (!opt.max_passphrase_days || arg->ctrl->in_passwd)
    return 0;  /* No regular passphrase change required.  */

  if (!*protected_at)
    {
      /* No protection date known - must force passphrase change.  */
      desc = xtrystrdup (_("Note: This passphrase has never been changed.%0A"
                           "Please change it now."));
      if (!desc)
        return gpg_error_from_syserror ();
    }
  else
    {
      gnupg_get_isotime (now);
      gnupg_copy_time (tmptime, protected_at);
      err = add_days_to_isotime (tmptime, opt.max_passphrase_days);
      if (err)
        return err;
      if (strcmp (now, tmptime) > 0 )
        {
          /* Passphrase "expired".  */
          desc = xtryasprintf
            (_("This passphrase has not been changed%%0A"
               "since %.4s-%.2s-%.2s.  Please change it now."),
             protected_at, protected_at+4, protected_at+6);
          if (!desc)
            return gpg_error_from_syserror ();
        }
    }

  if (desc)
    {
      /* Change required.  */
      if (opt.enforce_passphrase_constraints)
        {
          err = agent_get_confirmation (arg->ctrl, desc,
                                        _("Change passphrase"), NULL, 0);
          if (!err)
            arg->change_required = 1;
        }
      else
        {
          err = agent_get_confirmation (arg->ctrl, desc,
                                        _("Change passphrase"),
                                        _("I'll change it later"), 0);
          if (!err)
            arg->change_required = 1;
          else if (gpg_err_code (err) == GPG_ERR_CANCELED)
            err = 0;
        }
      xfree (desc);
    }

  return 0;
}
Example #2
0
/* Validate the certificate CHAIN up to the trust anchor. Optionally
   return the closest expiration time in R_EXPTIME (this is useful for
   caching issues).  MODE is one of the VALIDATE_MODE_* constants.

   If R_TRUST_ANCHOR is not NULL and the validation would fail only
   because the root certificate is not trusted, the hexified
   fingerprint of that root certificate is stored at R_TRUST_ANCHOR
   and success is returned.  The caller needs to free the value at
   R_TRUST_ANCHOR; in all other cases NULL is stored there.  */
gpg_error_t
validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
                     int mode, char **r_trust_anchor)
{
  gpg_error_t err = 0;
  int depth, maxdepth;
  char *issuer = NULL;
  char *subject = NULL;
  ksba_cert_t subject_cert = NULL, issuer_cert = NULL;
  ksba_isotime_t current_time;
  ksba_isotime_t exptime;
  int any_expired = 0;
  int any_no_policy_match = 0;
  chain_item_t chain;


  if (r_exptime)
    *r_exptime = 0;
  *exptime = 0;

  if (r_trust_anchor)
    *r_trust_anchor = NULL;

  if (!opt.system_daemon)
    {
      /* For backward compatibility we only do this in daemon mode.  */
      log_info (_("running in compatibility mode - "
                  "certificate chain not checked!\n"));
      return 0; /* Okay. */
    }

  if (DBG_X509)
    dump_cert ("subject", cert);

  /* May the target certificate be used for this purpose?  */
  switch (mode)
    {
    case VALIDATE_MODE_OCSP:
      err = cert_use_ocsp_p (cert);
      break;
    case VALIDATE_MODE_CRL:
    case VALIDATE_MODE_CRL_RECURSIVE:
      err = cert_use_crl_p (cert);
      break;
    default:
      err = 0;
      break;
    }
  if (err)
    return err;

  /* If we already validated the certificate not too long ago, we can
     avoid the excessive computations and lookups unless the caller
     asked for the expiration time.  */
  if (!r_exptime)
    {
      size_t buflen;
      time_t validated_at;

      err = ksba_cert_get_user_data (cert, "validated_at",
                                     &validated_at, sizeof (validated_at),
                                     &buflen);
      if (err || buflen != sizeof (validated_at) || !validated_at)
        err = 0; /* Not available or other error. */
      else
        {
          /* If the validation is not older than 30 minutes we are ready. */
          if (validated_at < gnupg_get_time () + (30*60))
            {
              if (opt.verbose)
                log_info ("certificate is good (cached)\n");
              /* Note, that we can't jump to leave here as this would
                 falsely updated the validation timestamp.  */
              return 0;
            }
        }
    }

  /* Get the current time. */
  gnupg_get_isotime (current_time);

  /* We walk up the chain until we find a trust anchor. */
  subject_cert = cert;
  maxdepth = 10;
  chain = NULL;
  depth = 0;
  for (;;)
    {
      /* Get the subject and issuer name from the current
         certificate.  */
      ksba_free (issuer);
      ksba_free (subject);
      issuer = ksba_cert_get_issuer (subject_cert, 0);
      subject = ksba_cert_get_subject (subject_cert, 0);

      if (!issuer)
        {
          log_error (_("no issuer found in certificate\n"));
          err = gpg_error (GPG_ERR_BAD_CERT);
          goto leave;
        }

      /* Handle the notBefore and notAfter timestamps.  */
      {
        ksba_isotime_t not_before, not_after;

        err = ksba_cert_get_validity (subject_cert, 0, not_before);
        if (!err)
          err = ksba_cert_get_validity (subject_cert, 1, not_after);
        if (err)
          {
            log_error (_("certificate with invalid validity: %s"),
                       gpg_strerror (err));
            err = gpg_error (GPG_ERR_BAD_CERT);
            goto leave;
          }

        /* Keep track of the nearest expiration time in EXPTIME.  */
        if (*not_after)
          {
            if (!*exptime)
              gnupg_copy_time (exptime, not_after);
            else if (strcmp (not_after, exptime) < 0 )
              gnupg_copy_time (exptime, not_after);
          }

        /* Check whether the certificate is already valid.  */
        if (*not_before && strcmp (current_time, not_before) < 0 )
          {
            log_error (_("certificate not yet valid"));
            log_info ("(valid from ");
            dump_isotime (not_before);
            log_printf (")\n");
            err = gpg_error (GPG_ERR_CERT_TOO_YOUNG);
            goto leave;
          }

        /* Now check whether the certificate has expired.  */
        if (*not_after && strcmp (current_time, not_after) > 0 )
          {
            log_error (_("certificate has expired"));
            log_info ("(expired at ");
            dump_isotime (not_after);
            log_printf (")\n");
            any_expired = 1;
          }
      }

      /* Do we have any critical extensions in the certificate we
         can't handle? */
      err = unknown_criticals (subject_cert);
      if (err)
        goto leave; /* yes. */

      /* Check that given policies are allowed.  */
      err = check_cert_policy (subject_cert);
      if (gpg_err_code (err) == GPG_ERR_NO_POLICY_MATCH)
        {
          any_no_policy_match = 1;
          err = 0;
        }
      else if (err)
        goto leave;

      /* Is this a self-signed certificate? */
      if (is_root_cert ( subject_cert, issuer, subject))
        {
          /* Yes, this is our trust anchor.  */
          if (check_cert_sig (subject_cert, subject_cert) )
            {
              log_error (_("selfsigned certificate has a BAD signature"));
              err = gpg_error (depth? GPG_ERR_BAD_CERT_CHAIN
                                    : GPG_ERR_BAD_CERT);
              goto leave;
            }

          /* Is this certificate allowed to act as a CA.  */
          err = allowed_ca (subject_cert, NULL);
          if (err)
            goto leave;  /* No. */

          err = is_trusted_cert (subject_cert);
          if (!err)
            ; /* Yes we trust this cert.  */
          else if (gpg_err_code (err) == GPG_ERR_NOT_TRUSTED)
            {
              char *fpr;

              log_error (_("root certificate is not marked trusted"));
              fpr = get_fingerprint_hexstring (subject_cert);
              log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
              dump_cert ("issuer", subject_cert);
              if (r_trust_anchor)
                {
                  /* Caller wants to do another trustiness check.  */
                  *r_trust_anchor = fpr;
                  err = 0;
                }
              else
                xfree (fpr);
            }
          else
            {
              log_error (_("checking trustworthiness of "
                           "root certificate failed: %s\n"),
                         gpg_strerror (err));
            }
          if (err)
            goto leave;

          /* Prepend the certificate to our list.  */
          {
            chain_item_t ci;

            ci = xtrycalloc (1, sizeof *ci);
            if (!ci)
              {
                err = gpg_error_from_errno (errno);
                goto leave;
              }
            ksba_cert_ref (subject_cert);
            ci->cert = subject_cert;
            cert_compute_fpr (subject_cert, ci->fpr);
            ci->next = chain;
            chain = ci;
          }

          if (opt.verbose)
            {
              if (r_trust_anchor && *r_trust_anchor)
                log_info ("root certificate is good but not trusted\n");
              else
                log_info ("root certificate is good and trusted\n");
            }

          break;  /* Okay: a self-signed certicate is an end-point. */
        }

      /* To avoid loops, we use an arbitrary limit on the length of
         the chain. */
      depth++;
      if (depth > maxdepth)
        {
          log_error (_("certificate chain too long\n"));
          err = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
          goto leave;
        }

      /* Find the next cert up the tree. */
      ksba_cert_release (issuer_cert); issuer_cert = NULL;
      err = find_issuing_cert (ctrl, subject_cert, &issuer_cert);
      if (err)
        {
          if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
            {
              log_error (_("issuer certificate not found"));
              log_info ("issuer certificate: #/");
              dump_string (issuer);
              log_printf ("\n");
            }
          else
            log_error (_("issuer certificate not found: %s\n"),
                         gpg_strerror (err));
          /* Use a better understandable error code.  */
          err = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
          goto leave;
        }

/*     try_another_cert: */
      if (DBG_X509)
        {
          log_debug ("got issuer's certificate:\n");
          dump_cert ("issuer", issuer_cert);
        }

      /* Now check the signature of the certificate.  Well, we
         should delay this until later so that faked certificates
         can't be turned into a DoS easily.  */
      err = check_cert_sig (issuer_cert, subject_cert);
      if (err)
        {
          log_error (_("certificate has a BAD signature"));
#if 0
          if (gpg_err_code (err) == GPG_ERR_BAD_SIGNATURE)
            {
              /* We now try to find other issuer certificates which
                 might have been used.  This is required because some
                 CAs are reusing the issuer and subject DN for new
                 root certificates without using a  authorityKeyIdentifier. */
              rc = find_up (kh, subject_cert, issuer, 1);
              if (!rc)
                {
                  ksba_cert_t tmp_cert;

                  rc = keydb_get_cert (kh, &tmp_cert);
                  if (rc || !compare_certs (issuer_cert, tmp_cert))
                    {
                      /* The find next did not work or returned an
                         identical certificate.  We better stop here
                         to avoid infinite checks. */
                      rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
                      ksba_cert_release (tmp_cert);
                    }
                  else
                    {
                      do_list (0, lm, fp, _("found another possible matching "
                                            "CA certificate - trying again"));
                      ksba_cert_release (issuer_cert);
                      issuer_cert = tmp_cert;
                      goto try_another_cert;
                    }
                }
            }
#endif
          /* We give a more descriptive error code than the one
             returned from the signature checking. */
          err = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
          goto leave;
        }

      /* Check that the length of the chain is not longer than allowed
         by the CA.  */
      {
        int chainlen;

        err = allowed_ca (issuer_cert, &chainlen);
        if (err)
          goto leave;
        if (chainlen >= 0 && (depth - 1) > chainlen)
          {
            log_error (_("certificate chain longer than allowed by CA (%d)"),
                       chainlen);
            err = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
            goto leave;
          }
      }

      /* May that certificate be used for certification? */
      err = cert_use_cert_p (issuer_cert);
      if (err)
        goto leave;  /* No.  */

      /* Prepend the certificate to our list.  */
      {
        chain_item_t ci;

        ci = xtrycalloc (1, sizeof *ci);
        if (!ci)
          {
            err = gpg_error_from_errno (errno);
            goto leave;
          }
        ksba_cert_ref (subject_cert);
        ci->cert = subject_cert;
        cert_compute_fpr (subject_cert, ci->fpr);
        ci->next = chain;
        chain = ci;
      }

      if (opt.verbose)
        log_info (_("certificate is good\n"));

      /* Now to the next level up.  */
      subject_cert = issuer_cert;
      issuer_cert = NULL;
    }

  if (!err)
    { /* If we encountered an error somewhere during the checks, set
         the error code to the most critical one */
      if (any_expired)
        err = gpg_error (GPG_ERR_CERT_EXPIRED);
      else if (any_no_policy_match)
        err = gpg_error (GPG_ERR_NO_POLICY_MATCH);
    }

  if (!err && opt.verbose)
    {
      chain_item_t citem;

      log_info (_("certificate chain is good\n"));
      for (citem = chain; citem; citem = citem->next)
        cert_log_name ("  certificate", citem->cert);
    }

  if (!err && mode != VALIDATE_MODE_CRL)
    { /* Now that everything is fine, walk the chain and check each
         certificate for revocations.

         1. item in the chain  - The root certificate.
         2. item               - the CA below the root
         last item             - the target certificate.

         Now for each certificate in the chain check whether it has
         been included in a CRL and thus be revoked.  We don't do OCSP
         here because this does not seem to make much sense.  This
         might become a recursive process and we should better cache
         our validity results to avoid double work.  Far worse a
         catch-22 may happen for an improper setup hierarchy and we
         need a way to break up such a deadlock. */
      err = check_revocations (ctrl, chain);
    }

  if (!err && opt.verbose)
    {
      if (r_trust_anchor && *r_trust_anchor)
        log_info ("target certificate may be valid\n");
      else
        log_info ("target certificate is valid\n");
    }
  else if (err && opt.verbose)
    log_info ("target certificate is NOT valid\n");


 leave:
  if (!err && !(r_trust_anchor && *r_trust_anchor))
    {
      /* With no error we can update the validation cache.  We do this
         for all certificates in the chain.  Note that we can't use
         the cache if the caller requested to check the trustiness of
         the root certificate himself.  Adding such a feature would
         require us to also store the fingerprint of root
         certificate.  */
      chain_item_t citem;
      time_t validated_at = gnupg_get_time ();

      for (citem = chain; citem; citem = citem->next)
        {
          err = ksba_cert_set_user_data (citem->cert, "validated_at",
                                         &validated_at, sizeof (validated_at));
          if (err)
            {
              log_error ("set_user_data(validated_at) failed: %s\n",
                         gpg_strerror (err));
              err = 0;
            }
        }
    }

  if (r_exptime)
    gnupg_copy_time (r_exptime, exptime);
  ksba_free (issuer);
  ksba_free (subject);
  ksba_cert_release (issuer_cert);
  if (subject_cert != cert)
    ksba_cert_release (subject_cert);
  while (chain)
    {
      chain_item_t ci_next = chain->next;
      if (chain->cert)
        ksba_cert_release (chain->cert);
      xfree (chain);
      chain = ci_next;
    }
  if (err && r_trust_anchor && *r_trust_anchor)
    {
      xfree (*r_trust_anchor);
      *r_trust_anchor = NULL;
    }
  return err;
}
Example #3
0
int
main ( int argc, char **argv)
{
  ARGPARSE_ARGS pargs;
  int orig_argc;
  char **orig_argv;
  gpg_error_t err = 0;
  /* const char *fname; */
  int may_coredump;
  FILE *configfp = NULL;
  char *configname = NULL;
  unsigned configlineno;
  int parse_debug = 0;
  int no_more_options = 0;
  int default_config =1;
  char *logfile = NULL;
  /* int debug_wait = 0; */
  int use_random_seed = 1;
  /* int nodetach = 0; */
  /* int nokeysetup = 0; */
  struct server_control_s ctrl;

  /*mtrace();*/

  early_system_init ();
  gnupg_reopen_std (G13_NAME "-syshelp");
  set_strusage (my_strusage);
  gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);

  log_set_prefix (G13_NAME "-syshelp", 1);

  /* Make sure that our subsystems are ready.  */
  i18n_init ();
  init_common_subsystems (&argc, &argv);

  /* Check that the Libgcrypt is suitable.  */
  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
    log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
               NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );

  /* Take extra care of the random pool.  */
  gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);

  may_coredump = disable_core_dumps ();

  g13_init_signals ();

  dotlock_create (NULL, 0); /* Register locking cleanup.  */

  opt.session_env = session_env_new ();
  if (!opt.session_env)
    log_fatal ("error allocating session environment block: %s\n",
               strerror (errno));

  opt.homedir = default_homedir ();
  /* Fixme: We enable verbose mode here because there is currently no
     way to do this when starting g13-syshelp.  To fix that we should
     add a g13-syshelp.conf file in /etc/gnupg.  */
  opt.verbose = 1;

  /* First check whether we have a debug option on the commandline.  */
  orig_argc = argc;
  orig_argv = argv;
  pargs.argc = &argc;
  pargs.argv = &argv;
  pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
  while (arg_parse( &pargs, opts))
    {
      if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
        parse_debug++;
    }

  /* Initialize the secure memory. */
  gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
  maybe_setuid = 0;

  /*
     Now we are now working under our real uid
  */

  /* Setup malloc hooks. */
  {
    struct assuan_malloc_hooks malloc_hooks;

    malloc_hooks.malloc = gcry_malloc;
    malloc_hooks.realloc = gcry_realloc;
    malloc_hooks.free = gcry_free;
    assuan_set_malloc_hooks (&malloc_hooks);
  }

  /* Prepare libassuan.  */
  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
  /*assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);*/
  setup_libassuan_logging (&opt.debug);

  /* Setup a default control structure for command line mode.  */
  memset (&ctrl, 0, sizeof ctrl);
  g13_syshelp_init_default_ctrl (&ctrl);
  ctrl.no_server = 1;
  ctrl.status_fd = -1; /* No status output. */

  if (default_config )
    configname = make_filename (gnupg_sysconfdir (),
                                G13_NAME"-syshelp.conf", NULL);

  argc        = orig_argc;
  argv        = orig_argv;
  pargs.argc  = &argc;
  pargs.argv  = &argv;
  pargs.flags =  1;  /* Do not remove the args.  */

 next_pass:
  if (configname)
    {
      configlineno = 0;
      configfp = fopen (configname, "r");
      if (!configfp)
        {
          if (default_config)
            {
              if (parse_debug)
                log_info (_("NOTE: no default option file '%s'\n"), configname);
            }
          else
            {
              log_error (_("option file '%s': %s\n"),
                         configname, strerror(errno));
              g13_exit(2);
            }
          xfree (configname);
          configname = NULL;
        }
      if (parse_debug && configname)
        log_info (_("reading options from '%s'\n"), configname);
      default_config = 0;
    }

  while (!no_more_options
         && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
    {
      switch (pargs.r_opt)
        {
        case oQuiet: opt.quiet = 1; break;

        case oDryRun: opt.dry_run = 1; break;

        case oVerbose:
          opt.verbose++;
          gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
          break;
        case oNoVerbose:
          opt.verbose = 0;
          gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
          break;

        case oLogFile: logfile = pargs.r.ret_str; break;
        case oNoLogFile: logfile = NULL; break;

        case oNoDetach: /*nodetach = 1; */break;

        case oDebug:
          if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
            {
              pargs.r_opt = ARGPARSE_INVALID_ARG;
              pargs.err = ARGPARSE_PRINT_ERROR;
            }
            break;
        case oDebugAll: debug_value = ~0; break;
        case oDebugNone: debug_value = 0; break;
        case oDebugLevel: debug_level = pargs.r.ret_str; break;
        case oDebugWait: /*debug_wait = pargs.r.ret_int; */break;
        case oDebugAllowCoreDump:
          may_coredump = enable_core_dumps ();
          break;

        case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
        case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;

        case oHomedir: opt.homedir = pargs.r.ret_str; break;

        case oFakedSystemTime:
          {
            time_t faked_time = isotime2epoch (pargs.r.ret_str);
            if (faked_time == (time_t)(-1))
              faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
            gnupg_set_time (faked_time, 0);
          }
          break;

        case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break;

        case oNoRandomSeedFile: use_random_seed = 0; break;

        default:
          pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
          break;
	}
    }

  if (configfp)
    {
      fclose (configfp);
      configfp = NULL;
      /* Keep a copy of the config filename. */
      opt.config_filename = configname;
      configname = NULL;
      goto next_pass;
    }
  xfree (configname);
  configname = NULL;

  if (!opt.config_filename)
    opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);

  if (log_get_errorcount(0))
    g13_exit(2);

  /* Now that we have the options parsed we need to update the default
     control structure.  */
  g13_syshelp_init_default_ctrl (&ctrl);

  if (may_coredump && !opt.quiet)
    log_info (_("WARNING: program may create a core file!\n"));

  if (logfile)
    {
      log_set_file (logfile);
      log_set_prefix (NULL, 1|2|4);
    }

  if (gnupg_faked_time_p ())
    {
      gnupg_isotime_t tbuf;

      log_info (_("WARNING: running with faked system time: "));
      gnupg_get_isotime (tbuf);
      dump_isotime (tbuf);
      log_printf ("\n");
    }

  /* Print any pending secure memory warnings.  */
  gcry_control (GCRYCTL_RESUME_SECMEM_WARN);

  /* Setup the debug flags for all subsystems.  */
  set_debug ();

  /* Install a regular exit handler to make real sure that the secure
     memory gets wiped out.  */
  g13_install_emergency_cleanup ();

  /* Terminate if we found any error until now.  */
  if (log_get_errorcount(0))
    g13_exit (2);

  /* Set the standard GnuPG random seed file.  */
  if (use_random_seed)
    {
      char *p = make_filename (opt.homedir, "random_seed", NULL);
      gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
      xfree(p);
    }

  /* Get the UID of the caller.  */
#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
  {
    const char *uidstr;
    struct passwd *pwd = NULL;

    uidstr = getenv ("USERV_UID");

    /* Print a quick note if we are not started via userv.  */
    if (!uidstr)
      {
        if (getuid ())
          {
            log_info ("WARNING: Not started via userv\n");
            ctrl.fail_all_cmds = 1;
          }
        ctrl.client.uid = getuid ();
      }
    else
      {
        unsigned long myuid;

        errno = 0;
        myuid = strtoul (uidstr, NULL, 10);
        if (myuid == ULONG_MAX && errno)
          {
            log_info ("WARNING: Started via broken userv: %s\n",
                      strerror (errno));
            ctrl.fail_all_cmds = 1;
            ctrl.client.uid = getuid ();
          }
        else
          ctrl.client.uid = (uid_t)myuid;
      }

    pwd = getpwuid (ctrl.client.uid);
    if (!pwd || !*pwd->pw_name)
      {
        log_info ("WARNING: Name for UID not found: %s\n", strerror (errno));
        ctrl.fail_all_cmds = 1;
        ctrl.client.uname = xstrdup ("?");
      }
    else
      ctrl.client.uname = xstrdup (pwd->pw_name);

    /* Check that the user name does not contain a directory
       separator. */
    if (strchr (ctrl.client.uname, '/'))
      {
        log_info ("WARNING: Invalid user name passed\n");
        ctrl.fail_all_cmds = 1;
      }
  }
#else /*!HAVE_PWD_H || !HAVE_GETPWUID*/
  log_info ("WARNING: System does not support required syscalls\n");
  ctrl.fail_all_cmds = 1;
  ctrl.client.uid = getuid ();
  ctrl.client.uname = xstrdup ("?");
#endif /*!HAVE_PWD_H || !HAVE_GETPWUID*/

  /* Read the table entries for this user.  */
  if (!ctrl.fail_all_cmds
      && !(ctrl.client.tab = parse_g13tab (ctrl.client.uname)))
    ctrl.fail_all_cmds = 1;

  /* Start the server.  */
  err = syshelp_server (&ctrl);
  if (err)
    log_error ("server exited with error: %s <%s>\n",
               gpg_strerror (err), gpg_strsource (err));

  /* Cleanup.  */
  g13_syshelp_deinit_default_ctrl (&ctrl);
  g13_exit (0);
  return 8; /*NOTREACHED*/
}
Example #4
0
File: ocsp.c Project: FMayzek/gnupg
/* Check whether the certificate either given by fingerprint CERT_FPR
   or directly through the CERT object is valid by running an OCSP
   transaction.  With FORCE_DEFAULT_RESPONDER set only the configured
   default responder is used. */
gpg_error_t
ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
              int force_default_responder)
{
  gpg_error_t err;
  ksba_ocsp_t ocsp = NULL;
  ksba_cert_t issuer_cert = NULL;
  ksba_sexp_t sigval = NULL;
  gcry_sexp_t s_sig = NULL;
  ksba_isotime_t current_time;
  ksba_isotime_t this_update, next_update, revocation_time, produced_at;
  ksba_isotime_t tmp_time;
  ksba_status_t status;
  ksba_crl_reason_t reason;
  char *url_buffer = NULL;
  const char *url;
  gcry_md_hd_t md = NULL;
  int i, idx;
  char *oid;
  ksba_name_t name;
  fingerprint_list_t default_signer = NULL;

  /* Get the certificate.  */
  if (cert)
    {
      ksba_cert_ref (cert);

      err = find_issuing_cert (ctrl, cert, &issuer_cert);
      if (err)
        {
          log_error (_("issuer certificate not found: %s\n"),
                     gpg_strerror (err));
          goto leave;
        }
    }
  else
    {
      cert = get_cert_local (ctrl, cert_fpr);
      if (!cert)
        {
          log_error (_("caller did not return the target certificate\n"));
          err = gpg_error (GPG_ERR_GENERAL);
          goto leave;
        }
      issuer_cert = get_issuing_cert_local (ctrl, NULL);
      if (!issuer_cert)
        {
          log_error (_("caller did not return the issuing certificate\n"));
          err = gpg_error (GPG_ERR_GENERAL);
          goto leave;
        }
    }

  /* Create an OCSP instance.  */
  err = ksba_ocsp_new (&ocsp);
  if (err)
    {
      log_error (_("failed to allocate OCSP context: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }



  /* Figure out the OCSP responder to use.
     1. Try to get the reponder from the certificate.
        We do only take http and https style URIs into account.
     2. If this fails use the default responder, if any.
   */
  url = NULL;
  for (idx=0; !url && !opt.ignore_ocsp_service_url && !force_default_responder
         && !(err=ksba_cert_get_authority_info_access (cert, idx,
                                                       &oid, &name)); idx++)
    {
      if ( !strcmp (oid, oidstr_ocsp) )
        {
          for (i=0; !url && ksba_name_enum (name, i); i++)
            {
              char *p = ksba_name_get_uri (name, i);
              if (p && (!ascii_strncasecmp (p, "http:", 5)
                        || !ascii_strncasecmp (p, "https:", 6)))
                url = url_buffer = p;
              else
                xfree (p);
            }
        }
      ksba_name_release (name);
      ksba_free (oid);
    }
  if (err && gpg_err_code (err) != GPG_ERR_EOF)
    {
      log_error (_("can't get authorityInfoAccess: %s\n"), gpg_strerror (err));
      goto leave;
    }
  if (!url)
    {
      if (!opt.ocsp_responder || !*opt.ocsp_responder)
        {
          log_info (_("no default OCSP responder defined\n"));
          err = gpg_error (GPG_ERR_CONFIGURATION);
          goto leave;
        }
      if (!opt.ocsp_signer)
        {
          log_info (_("no default OCSP signer defined\n"));
          err = gpg_error (GPG_ERR_CONFIGURATION);
          goto leave;
        }
      url = opt.ocsp_responder;
      default_signer = opt.ocsp_signer;
      if (opt.verbose)
        log_info (_("using default OCSP responder '%s'\n"), url);
    }
  else
    {
      if (opt.verbose)
        log_info (_("using OCSP responder '%s'\n"), url);
    }

  /* Ask the OCSP responder. */
  err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
  if (err)
    {
      log_error (_("failed to establish a hashing context for OCSP: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }
  err = do_ocsp_request (ctrl, ocsp, md, url, cert, issuer_cert);
  if (err)
    goto leave;

  /* We got a useful answer, check that the answer has a valid signature. */
  sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
  if (!sigval || !*produced_at)
    {
      err = gpg_error (GPG_ERR_INV_OBJ);
      goto leave;
    }
  if ( (err = canon_sexp_to_gcry (sigval, &s_sig)) )
    goto leave;
  xfree (sigval);
  sigval = NULL;
  err = check_signature (ctrl, ocsp, s_sig, md, default_signer);
  if (err)
    goto leave;

  /* We only support one certificate per request.  Check that the
     answer matches the right certificate. */
  err = ksba_ocsp_get_status (ocsp, cert,
                              &status, this_update, next_update,
                              revocation_time, &reason);
  if (err)
    {
      log_error (_("error getting OCSP status for target certificate: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }

  /* In case the certificate has been revoked, we better invalidate
     our cached validation status. */
  if (status == KSBA_STATUS_REVOKED)
    {
      time_t validated_at = 0; /* That is: No cached validation available. */
      err = ksba_cert_set_user_data (cert, "validated_at",
                                     &validated_at, sizeof (validated_at));
      if (err)
        {
          log_error ("set_user_data(validated_at) failed: %s\n",
                     gpg_strerror (err));
          err = 0; /* The certificate is anyway revoked, and that is a
                      more important message than the failure of our
                      cache. */
        }
    }


  if (opt.verbose)
    {
      log_info (_("certificate status is: %s  (this=%s  next=%s)\n"),
                status == KSBA_STATUS_GOOD? _("good"):
                status == KSBA_STATUS_REVOKED? _("revoked"):
                status == KSBA_STATUS_UNKNOWN? _("unknown"):
                status == KSBA_STATUS_NONE? _("none"): "?",
                this_update, next_update);
      if (status == KSBA_STATUS_REVOKED)
        log_info (_("certificate has been revoked at: %s due to: %s\n"),
                  revocation_time,
                  reason == KSBA_CRLREASON_UNSPECIFIED?   "unspecified":
                  reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise":
                  reason == KSBA_CRLREASON_CA_COMPROMISE?   "CA compromise":
                  reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
                                                      "affiliation changed":
                  reason == KSBA_CRLREASON_SUPERSEDED?   "superseeded":
                  reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
                                                  "cessation of operation":
                  reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
                                                  "certificate on hold":
                  reason == KSBA_CRLREASON_REMOVE_FROM_CRL?
                                                  "removed from CRL":
                  reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
                                                  "privilege withdrawn":
                  reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise":
                  reason == KSBA_CRLREASON_OTHER?   "other":"?");

    }


  if (status == KSBA_STATUS_REVOKED)
    err = gpg_error (GPG_ERR_CERT_REVOKED);
  else if (status == KSBA_STATUS_UNKNOWN)
    err = gpg_error (GPG_ERR_NO_DATA);
  else if (status != KSBA_STATUS_GOOD)
    err = gpg_error (GPG_ERR_GENERAL);

  /* Allow for some clock skew. */
  gnupg_get_isotime (current_time);
  add_seconds_to_isotime (current_time, opt.ocsp_max_clock_skew);

  if (strcmp (this_update, current_time) > 0 )
    {
      log_error (_("OCSP responder returned a status in the future\n"));
      log_info ("used now: %s  this_update: %s\n", current_time, this_update);
      if (!err)
        err = gpg_error (GPG_ERR_TIME_CONFLICT);
    }

  /* Check that THIS_UPDATE is not too far back in the past. */
  gnupg_copy_time (tmp_time, this_update);
  add_seconds_to_isotime (tmp_time,
                          opt.ocsp_max_period+opt.ocsp_max_clock_skew);
  if (!*tmp_time || strcmp (tmp_time, current_time) < 0 )
    {
      log_error (_("OCSP responder returned a non-current status\n"));
      log_info ("used now: %s  this_update: %s\n",
                current_time, this_update);
      if (!err)
        err = gpg_error (GPG_ERR_TIME_CONFLICT);
    }

  /* Check that we are not beyound NEXT_UPDATE  (plus some extra time). */
  if (*next_update)
    {
      gnupg_copy_time (tmp_time, next_update);
      add_seconds_to_isotime (tmp_time,
                              opt.ocsp_current_period+opt.ocsp_max_clock_skew);
      if (!*tmp_time && strcmp (tmp_time, current_time) < 0 )
        {
          log_error (_("OCSP responder returned an too old status\n"));
          log_info ("used now: %s  next_update: %s\n",
                    current_time, next_update);
          if (!err)
            err = gpg_error (GPG_ERR_TIME_CONFLICT);
        }
    }


 leave:
  gcry_md_close (md);
  gcry_sexp_release (s_sig);
  xfree (sigval);
  ksba_cert_release (issuer_cert);
  ksba_cert_release (cert);
  ksba_ocsp_release (ocsp);
  xfree (url_buffer);
  return err;
}