static int match_localkeyid(hx509_context context, struct private_key *value, hx509_certs certs) { hx509_cert cert; hx509_query q; int ret; if (value->localKeyId.length == 0) { hx509_set_error_string(context, 0, HX509_LOCAL_ATTRIBUTE_MISSING, "No local key attribute on private key"); return HX509_LOCAL_ATTRIBUTE_MISSING; } _hx509_query_clear(&q); q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID; q.local_key_id = &value->localKeyId; ret = hx509_certs_find(context, certs, &q, &cert); if (ret == 0) { if (value->private_key) _hx509_cert_assign_key(cert, value->private_key); hx509_cert_free(cert); } return ret; }
static int find_CMSIdentifier(hx509_context context, CMSIdentifier *client, hx509_certs certs, time_t time_now, hx509_cert *signer_cert, int match) { hx509_query q; hx509_cert cert; Certificate c; int ret; memset(&c, 0, sizeof(c)); _hx509_query_clear(&q); *signer_cert = NULL; switch (client->element) { case choice_CMSIdentifier_issuerAndSerialNumber: q.serial = &client->u.issuerAndSerialNumber.serialNumber; q.issuer_name = &client->u.issuerAndSerialNumber.issuer; q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; break; case choice_CMSIdentifier_subjectKeyIdentifier: q.subject_id = &client->u.subjectKeyIdentifier; q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; break; default: hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE, "unknown CMS identifier element"); return HX509_CMS_NO_RECIPIENT_CERTIFICATE; } q.match |= match; q.match |= HX509_QUERY_MATCH_TIME; if (time_now) q.timenow = time_now; else q.timenow = time(NULL); ret = hx509_certs_find(context, certs, &q, &cert); if (ret == HX509_CERT_NOT_FOUND) { char *str; ret = unparse_CMSIdentifier(context, client, &str); if (ret == 0) { hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE, "Failed to find %s", str); } else hx509_clear_error_string(context); return HX509_CMS_NO_RECIPIENT_CERTIFICATE; } else if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, HX509_CMS_NO_RECIPIENT_CERTIFICATE, "Failed to find CMS id in cert store"); return HX509_CMS_NO_RECIPIENT_CERTIFICATE; } *signer_cert = cert; return 0; }
static int add_to_req(hx509_context context, void *ptr, hx509_cert cert) { struct ocsp_add_ctx *ctx = ptr; OCSPInnerRequest *one; hx509_cert parent = NULL; Certificate *p, *c = _hx509_get_cert(cert); heim_octet_string os; int ret; hx509_query q; void *d; d = realloc(ctx->req->requestList.val, sizeof(ctx->req->requestList.val[0]) * (ctx->req->requestList.len + 1)); if (d == NULL) return ENOMEM; ctx->req->requestList.val = d; one = &ctx->req->requestList.val[ctx->req->requestList.len]; memset(one, 0, sizeof(*one)); _hx509_query_clear(&q); q.match |= HX509_QUERY_FIND_ISSUER_CERT; q.subject = c; ret = hx509_certs_find(context, ctx->certs, &q, &parent); if (ret) goto out; if (ctx->parent) { if (hx509_cert_cmp(ctx->parent, parent) != 0) { ret = HX509_REVOKE_NOT_SAME_PARENT; hx509_set_error_string(context, 0, ret, "Not same parent certifate as " "last certificate in request"); goto out; } } else ctx->parent = hx509_cert_ref(parent); p = _hx509_get_cert(parent); ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); if (ret) goto out; ret = _hx509_create_signature(context, NULL, &one->reqCert.hashAlgorithm, &c->tbsCertificate.issuer._save, NULL, &one->reqCert.issuerNameHash); if (ret) goto out; os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; ret = _hx509_create_signature(context, NULL, &one->reqCert.hashAlgorithm, &os, NULL, &one->reqCert.issuerKeyHash); if (ret) goto out; ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, &one->reqCert.serialNumber); if (ret) goto out; ctx->req->requestList.len++; out: hx509_cert_free(parent); if (ret) { free_OCSPInnerRequest(one); memset(one, 0, sizeof(*one)); } return ret; }
static int verify_crl(hx509_context context, hx509_revoke_ctx ctx, CRLCertificateList *crl, time_t time_now, hx509_certs certs, hx509_cert parent) { hx509_cert signer; hx509_query q; time_t t; int ret; t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate); if (t > time_now) { hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME, "CRL used before time"); return HX509_CRL_USED_BEFORE_TIME; } if (crl->tbsCertList.nextUpdate == NULL) { hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT, "CRL missing nextUpdate"); return HX509_CRL_INVALID_FORMAT; } t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate); if (t < time_now) { hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME, "CRL used after time"); return HX509_CRL_USED_AFTER_TIME; } _hx509_query_clear(&q); /* * If it's the signer have CRLSIGN bit set, use that as the signer * cert for the certificate, otherwise, search for a certificate. */ if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) { signer = hx509_cert_ref(parent); } else { q.match = HX509_QUERY_MATCH_SUBJECT_NAME; q.match |= HX509_QUERY_KU_CRLSIGN; q.subject_name = &crl->tbsCertList.issuer; ret = hx509_certs_find(context, certs, &q, &signer); if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "Failed to find certificate for CRL"); return ret; } } ret = _hx509_verify_signature_bitstring(context, signer, &crl->signatureAlgorithm, &crl->tbsCertList._save, &crl->signatureValue); if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "CRL signature invalid"); goto out; } /* * If signer is not CA cert, need to check revoke status of this * CRL signing cert too, this include all parent CRL signer cert * up to the root *sigh*, assume root at least hve CERTSIGN flag * set. */ while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) { hx509_cert crl_parent; _hx509_query_clear(&q); q.match = HX509_QUERY_MATCH_SUBJECT_NAME; q.match |= HX509_QUERY_KU_CRLSIGN; q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer; ret = hx509_certs_find(context, certs, &q, &crl_parent); if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "Failed to find parent of CRL signer"); goto out; } ret = hx509_revoke_verify(context, ctx, certs, time_now, signer, crl_parent); hx509_cert_free(signer); signer = crl_parent; if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "Failed to verify revoke " "status of CRL signer"); goto out; } } out: hx509_cert_free(signer); return ret; }
static int verify_ocsp(hx509_context context, struct revoke_ocsp *ocsp, time_t time_now, hx509_certs certs, hx509_cert parent) { hx509_cert signer = NULL; hx509_query q; int ret; _hx509_query_clear(&q); /* * Need to match on issuer too in case there are two CA that have * issued the same name to a certificate. One example of this is * the www.openvalidation.org test's ocsp validator. */ q.match = HX509_QUERY_MATCH_ISSUER_NAME; q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer; switch(ocsp->ocsp.tbsResponseData.responderID.element) { case choice_OCSPResponderID_byName: q.match |= HX509_QUERY_MATCH_SUBJECT_NAME; q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName; break; case choice_OCSPResponderID_byKey: q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1; q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey; break; } ret = hx509_certs_find(context, certs, &q, &signer); if (ret && ocsp->certs) ret = hx509_certs_find(context, ocsp->certs, &q, &signer); if (ret) goto out; /* * If signer certificate isn't the CA certificate, lets check the * it is the CA that signed the signer certificate and the OCSP EKU * is set. */ if (hx509_cert_cmp(signer, parent) != 0) { Certificate *p = _hx509_get_cert(parent); Certificate *s = _hx509_get_cert(signer); ret = _hx509_cert_is_parent_cmp(s, p, 0); if (ret != 0) { ret = HX509_PARENT_NOT_CA; hx509_set_error_string(context, 0, ret, "Revoke OCSP signer is " "doesn't have CA as signer certificate"); goto out; } ret = _hx509_verify_signature_bitstring(context, parent, &s->signatureAlgorithm, &s->tbsCertificate._save, &s->signatureValue); if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "OCSP signer signature invalid"); goto out; } ret = hx509_cert_check_eku(context, signer, &asn1_oid_id_pkix_kp_OCSPSigning, 0); if (ret) goto out; } ret = _hx509_verify_signature_bitstring(context, signer, &ocsp->ocsp.signatureAlgorithm, &ocsp->ocsp.tbsResponseData._save, &ocsp->ocsp.signature); if (ret) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "OCSP signature invalid"); goto out; } ocsp->signer = signer; signer = NULL; out: if (signer) hx509_cert_free(signer); return ret; }