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; }
int hx509_validate_cert(hx509_context context, hx509_validate_ctx ctx, hx509_cert cert) { Certificate *c = _hx509_get_cert(cert); TBSCertificate *t = &c->tbsCertificate; hx509_name issuer, subject; char *str; struct cert_status status; int ret; memset(&status, 0, sizeof(status)); if (_hx509_cert_get_version(c) != 3) validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Not version 3 certificate\n"); if ((t->version == NULL || *t->version < 2) && t->extensions) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Not version 3 certificate with extensions\n"); if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Version 3 certificate without extensions\n"); ret = hx509_cert_get_subject(cert, &subject); if (ret) abort(); hx509_name_to_string(subject, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "subject name: %s\n", str); free(str); ret = hx509_cert_get_issuer(cert, &issuer); if (ret) abort(); hx509_name_to_string(issuer, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "issuer name: %s\n", str); free(str); if (hx509_name_cmp(subject, issuer) == 0) { status.selfsigned = 1; validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tis a self-signed certificate\n"); } validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Validity:\n"); Time2string(&t->validity.notBefore, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str); free(str); Time2string(&t->validity.notAfter, &str); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str); free(str); if (t->extensions) { int i, j; if (t->extensions->len == 0) { validate_print(ctx, HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, "The empty extensions list is not " "allowed by PKIX\n"); } for (i = 0; i < t->extensions->len; i++) { for (j = 0; check_extension[j].name; j++) if (der_heim_oid_cmp(check_extension[j].oid, &t->extensions->val[i].extnID) == 0) break; if (check_extension[j].name == NULL) { int flags = HX509_VALIDATE_F_VERBOSE; if (t->extensions->val[i].critical) flags |= HX509_VALIDATE_F_VALIDATE; validate_print(ctx, flags, "don't know what "); if (t->extensions->val[i].critical) validate_print(ctx, flags, "and is CRITICAL "); if (ctx->flags & flags) hx509_oid_print(&t->extensions->val[i].extnID, validate_vprint, ctx); validate_print(ctx, flags, " is\n"); continue; } validate_print(ctx, HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, "checking extention: %s\n", check_extension[j].name); (*check_extension[j].func)(ctx, &status, check_extension[j].cf, &t->extensions->val[i]); } } else validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n"); if (status.isca) { if (!status.haveSKI) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "CA certificate have no SubjectKeyIdentifier\n"); } else { if (!status.haveAKI) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Is not CA and doesn't have " "AuthorityKeyIdentifier\n"); } if (!status.haveSKI) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Doesn't have SubjectKeyIdentifier\n"); if (status.isproxy && status.isca) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Proxy and CA at the same time!\n"); if (status.isproxy) { if (status.haveSAN) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Proxy and have SAN\n"); if (status.haveIAN) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Proxy and have IAN\n"); } if (hx509_name_is_null_p(subject) && !status.haveSAN) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "NULL subject DN and doesn't have a SAN\n"); if (!status.selfsigned && !status.haveCRLDP) validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Not a CA nor PROXY and doesn't have" "CRL Dist Point\n"); if (status.selfsigned) { ret = _hx509_verify_signature_bitstring(context, cert, &c->signatureAlgorithm, &c->tbsCertificate._save, &c->signatureValue); if (ret == 0) validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Self-signed certificate was self-signed\n"); else validate_print(ctx, HX509_VALIDATE_F_VALIDATE, "Self-signed certificate NOT really self-signed!\n"); } hx509_name_free(&subject); hx509_name_free(&issuer); return 0; }
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; }