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