Пример #1
0
/* Given PATTERN, which is a string as used by GnuPG to specify a
   certificate, return all matching certificates by calling the
   supplied function RETFNC.  */
gpg_error_t
get_certs_bypattern (const char *pattern,
                     gpg_error_t (*retfnc)(void*,ksba_cert_t),
                     void *retfnc_data)
{
  gpg_error_t err = GPG_ERR_BUG;
  enum pattern_class class;
  size_t offset, sn_offset;
  const char *hexserialno;
  ksba_sexp_t serialno = NULL;
  ksba_cert_t cert = NULL;
  unsigned int seq;

  if (!pattern || !retfnc)
    return gpg_error (GPG_ERR_INV_ARG);

  class = classify_pattern (pattern, &offset, &sn_offset);
  hexserialno = pattern + sn_offset;
  pattern += offset;
  switch (class)
    {
    case PATTERN_UNKNOWN:
      err = gpg_error (GPG_ERR_INV_NAME);
      break;

    case PATTERN_FINGERPRINT20:
      cert = get_cert_byhexfpr (pattern);
      err = cert? 0 : gpg_error (GPG_ERR_NOT_FOUND);
      break;

    case PATTERN_SERIALNO_ISSUER:
      serialno = hexsn_to_sexp (hexserialno);
      if (!serialno)
        err = gpg_error_from_syserror ();
      else
        {
          cert = get_cert_bysn (pattern, serialno);
          err = cert? 0 : gpg_error (GPG_ERR_NOT_FOUND);
        }
      break;

    case PATTERN_ISSUER:
      for (seq=0,err=0; !err && (cert = get_cert_byissuer (pattern, seq)); seq++)
        {
          err = retfnc (retfnc_data, cert);
          ksba_cert_release (cert);
          cert = NULL;
        }
      if (!err && !seq)
        err = gpg_error (GPG_ERR_NOT_FOUND);
      break;

    case PATTERN_SUBJECT:
      for (seq=0,err=0; !err && (cert = get_cert_bysubject (pattern, seq));seq++)
        {
          err = retfnc (retfnc_data, cert);
          ksba_cert_release (cert);
          cert = NULL;
        }
      if (!err && !seq)
        err = gpg_error (GPG_ERR_NOT_FOUND);
      break;

    case PATTERN_EMAIL:
    case PATTERN_EMAIL_SUBSTR:
    case PATTERN_FINGERPRINT16:
    case PATTERN_SHORT_KEYID:
    case PATTERN_LONG_KEYID:
    case PATTERN_SUBSTR:
    case PATTERN_SERIALNO:
      /* Not supported.  */
      err = gpg_error (GPG_ERR_INV_NAME);
    }


  if (!err && cert)
    err = retfnc (retfnc_data, cert);
  ksba_cert_release (cert);
  xfree (serialno);
  return err;
}
Пример #2
0
/* Check the signature of an OCSP repsonse.  OCSP is the context,
   S_SIG the signature value and MD the handle of the hash we used for
   the response.  This function automagically finds the correct public
   key.  If SIGNER_FPR_LIST is not NULL, the default OCSP reponder has been
   used and thus the certificate is one of those identified by
   the fingerprints. */
static gpg_error_t
check_signature (ctrl_t ctrl,
                 ksba_ocsp_t ocsp, gcry_sexp_t s_sig, gcry_md_hd_t md,
                 fingerprint_list_t signer_fpr_list)
{
  gpg_error_t err;
  int algo, cert_idx;
  gcry_sexp_t s_hash;
  ksba_cert_t cert;

  /* Create a suitable S-expression with the hash value of our response. */
  gcry_md_final (md);
  algo = gcry_md_get_algo (md);
  if (algo != GCRY_MD_SHA1 )
    {
      log_error (_("only SHA-1 is supported for OCSP responses\n"));
      return gpg_error (GPG_ERR_DIGEST_ALGO);
    }
  err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))",
                         gcry_md_get_algo_dlen (algo),
                         gcry_md_read (md, algo));
  if (err)
    {
      log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
      return err;
    }

  /* Get rid of old OCSP specific certificate references. */
  release_ctrl_ocsp_certs (ctrl);

  if (signer_fpr_list && !signer_fpr_list->next)
    {
      /* There is exactly one signer fingerprint given. Thus we use
         the default OCSP responder's certificate and instantly know
         the certificate to use.  */
      cert = get_cert_byhexfpr (signer_fpr_list->hexfpr);
      if (!cert)
        cert = get_cert_local (ctrl, signer_fpr_list->hexfpr);
      if (cert)
        {
          err = check_signature_core (ctrl, cert, s_sig, s_hash,
                                      signer_fpr_list);
          ksba_cert_release (cert);
          cert = NULL;
          if (!err)
            {
              gcry_sexp_release (s_hash);
              return 0; /* Successfully verified the signature. */
            }
        }
    }
  else
    {
      char *name;
      ksba_sexp_t keyid;

      /* Put all certificates included in the response into the cache
         and setup a list of those certificate which will later be
         preferred used when locating certificates.  */
      for (cert_idx=0; (cert = ksba_ocsp_get_cert (ocsp, cert_idx));
           cert_idx++)
        {
          cert_ref_t cref;

          cref = xtrymalloc (sizeof *cref);
          if (!cref)
            log_error (_("allocating list item failed: %s\n"),
                       gcry_strerror (err));
          else if (!cache_cert_silent (cert, &cref->fpr))
            {
              cref->next = ctrl->ocsp_certs;
              ctrl->ocsp_certs = cref;
            }
          else
            xfree (cref);
        }

      /* Get the certificate by means of the responder ID. */
      err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
      if (err)
        {
          log_error (_("error getting responder ID: %s\n"),
                     gcry_strerror (err));
          return err;
        }
      cert = find_cert_bysubject (ctrl, name, keyid);
      if (!cert)
        {
          log_error ("responder certificate ");
          if (name)
            log_printf ("'/%s' ", name);
          if (keyid)
            {
              log_printf ("{");
              dump_serial (keyid);
              log_printf ("} ");
            }
          log_printf ("not found\n");
        }
      ksba_free (name);
      ksba_free (keyid);

      if (cert)
        {
          err = check_signature_core (ctrl, cert, s_sig, s_hash,
                                      signer_fpr_list);
          ksba_cert_release (cert);
          if (!err)
            {
              gcry_sexp_release (s_hash);
              return 0; /* Successfully verified the signature. */
            }
        }
    }

  gcry_sexp_release (s_hash);
  log_error (_("no suitable certificate found to verify the OCSP response\n"));
  return gpg_error (GPG_ERR_NO_PUBKEY);
}