/* 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; }
/* 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); }