Beispiel #1
0
/* Given the certificate CERT locate the issuer for this certificate
   and return it at R_CERT.  Returns 0 on success or
   GPG_ERR_NOT_FOUND.  */
gpg_error_t
find_issuing_cert (ctrl_t ctrl, ksba_cert_t cert, ksba_cert_t *r_cert)
{
  gpg_error_t err;
  char *issuer_dn;
  ksba_cert_t issuer_cert = NULL;
  ksba_name_t authid;
  ksba_sexp_t authidno;
  ksba_sexp_t keyid;

  *r_cert = NULL;

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

  /* First we need to check whether we can return that certificate
     using the authorithyKeyIdentifier.  */
  err = ksba_cert_get_auth_key_id (cert, &keyid, &authid, &authidno);
  if (err)
    {
      log_info (_("error getting authorityKeyIdentifier: %s\n"),
                gpg_strerror (err));
    }
  else
    {
      const char *s = ksba_name_enum (authid, 0);
      if (s && *authidno)
        {
          issuer_cert = find_cert_bysn (ctrl, s, authidno);
        }
      if (!issuer_cert && keyid)
        {
          /* Not found by issuer+s/n.  Now that we have an AKI
             keyIdentifier look for a certificate with a matching
             SKI. */
          issuer_cert = find_cert_bysubject (ctrl, issuer_dn, keyid);
        }
      /* Print a note so that the user does not feel too helpless when
         an issuer certificate was found and gpgsm prints BAD
         signature because it is not the correct one. */
      if (!issuer_cert)
        {
          log_info ("issuer certificate ");
          if (keyid)
            {
              log_printf ("{");
              dump_serial (keyid);
              log_printf ("} ");
            }
          if (authidno)
            {
              log_printf ("(#");
              dump_serial (authidno);
              log_printf ("/");
              dump_string (s);
              log_printf (") ");
            }
          log_printf ("not found using authorityKeyIdentifier\n");
        }
      ksba_name_release (authid);
      xfree (authidno);
      xfree (keyid);
    }

  /* If this did not work, try just with the issuer's name and assume
     that there is only one such certificate.  We only look into our
     cache then. */
  if (err || !issuer_cert)
    {
      issuer_cert = get_cert_bysubject (issuer_dn, 0);
      if (issuer_cert)
        err = 0;
    }

 leave:
  if (!err && !issuer_cert)
    err = gpg_error (GPG_ERR_NOT_FOUND);

  xfree (issuer_dn);

  if (err)
    ksba_cert_release (issuer_cert);
  else
    *r_cert = issuer_cert;

  return err;
}
Beispiel #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);
}