diff options
Diffstat (limited to 'src/pluto/ocsp.c')
-rw-r--r-- | src/pluto/ocsp.c | 441 |
1 files changed, 224 insertions, 217 deletions
diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c index 8e428a759..b1f558ebf 100644 --- a/src/pluto/ocsp.c +++ b/src/pluto/ocsp.c @@ -67,19 +67,19 @@ static const char *const response_status_names[] = { typedef struct response response_t; struct response { - chunk_t tbs; - chunk_t responder_id_name; - chunk_t responder_id_key; - time_t produced_at; - chunk_t responses; - chunk_t nonce; - int algorithm; - chunk_t signature; + chunk_t tbs; + identification_t *responder_id_name; + chunk_t responder_id_key; + time_t produced_at; + chunk_t responses; + chunk_t nonce; + int algorithm; + chunk_t signature; }; const response_t empty_response = { { NULL, 0 } , /* tbs */ - { NULL, 0 } , /* responder_id_name */ + NULL , /* responder_id_name */ { NULL, 0 } , /* responder_id_key */ UNDEFINED_TIME, /* produced_at */ { NULL, 0 } , /* single_response */ @@ -105,16 +105,16 @@ struct single_response { }; const single_response_t empty_single_response = { - NULL , /* *next */ - OID_UNKNOWN , /* hash_algorithm */ - { NULL, 0 } , /* issuer_name_hash */ - { NULL, 0 } , /* issuer_key_hash */ - { NULL, 0 } , /* serial_number */ - CERT_UNDEFINED , /* status */ - UNDEFINED_TIME , /* revocationTime */ - REASON_UNSPECIFIED, /* revocationReason */ - UNDEFINED_TIME , /* this_update */ - UNDEFINED_TIME /* next_update */ + NULL , /* *next */ + OID_UNKNOWN , /* hash_algorithm */ + { NULL, 0 } , /* issuer_name_hash */ + { NULL, 0 } , /* issuer_key_hash */ + { NULL, 0 } , /* serial_number */ + CERT_UNDEFINED , /* status */ + UNDEFINED_TIME , /* revocationTime */ + CRL_REASON_UNSPECIFIED, /* revocationReason */ + UNDEFINED_TIME , /* this_update */ + UNDEFINED_TIME /* next_update */ }; @@ -126,26 +126,17 @@ struct request_list { }; /* some OCSP specific prefabricated ASN.1 constants */ - -static u_char ASN1_nonce_oid_str[] = { +static const chunk_t ASN1_nonce_oid = chunk_from_chars( 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 -}; - -static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); - -static u_char ASN1_response_oid_str[] = { +); +static const chunk_t ASN1_response_oid = chunk_from_chars( 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 -}; - -static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); - -static u_char ASN1_response_content_str[] = { +); +static const chunk_t ASN1_response_content = chunk_from_chars( 0x04, 0x0D, 0x30, 0x0B, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 -}; - -static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); +); /* default OCSP uri */ static chunk_t ocsp_default_uri; @@ -154,7 +145,7 @@ static chunk_t ocsp_default_uri; static ocsp_location_t *ocsp_cache = NULL; /* static temporary storage for ocsp requestor information */ -static x509cert_t *ocsp_requestor_cert = NULL; +static cert_t *ocsp_requestor_cert = NULL; static smartcard_t *ocsp_requestor_sc = NULL; @@ -290,27 +281,38 @@ static const asn1Object_t singleResponseObjects[] = { * Build an ocsp location from certificate information * without unsharing its contents */ -static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location) +static bool build_ocsp_location(const cert_t *cert, ocsp_location_t *location) { + certificate_t *certificate = cert->cert; + identification_t *issuer = certificate->get_issuer(certificate); + x509_t *x509 = (x509_t*)certificate; + chunk_t issuer_dn = issuer->get_encoding(issuer); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); hasher_t *hasher; static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */ - - location->uri = cert->accessLocation; - if (location->uri.ptr == NULL) + enumerator_t *enumerator = x509->create_ocsp_uri_enumerator(x509); + + location->uri = NULL; + while (enumerator->enumerate(enumerator, &location->uri)) + { + break; + } + enumerator->destroy(enumerator); + + if (location->uri == NULL) { - ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID); - if (ca != NULL && ca->ocspuri != NULL) + ca_info_t *ca = get_ca_info(issuer, authKeyID); + if (ca && ca->ocspuri) { - location->uri = chunk_create(ca->ocspuri, strlen(ca->ocspuri)); + location->uri = ca->ocspuri; } else { /* abort if no ocsp location uri is defined */ return FALSE; } } - + /* compute authNameID from as SHA-1 hash of issuer DN */ location->authNameID = chunk_create(digest, HASH_SIZE_SHA1); hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); @@ -318,23 +320,22 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio { return FALSE; } - hasher->get_hash(hasher, cert->issuer, digest); + hasher->get_hash(hasher, issuer_dn, digest); hasher->destroy(hasher); location->next = NULL; - location->issuer = cert->issuer; - location->authKeyID = cert->authKeyID; - location->authKeySerialNumber = cert->authKeySerialNumber; - - if (cert->authKeyID.ptr == NULL) + location->issuer = issuer; + location->authKeyID = authKeyID; + + if (authKeyID.ptr == NULL) { - x509cert_t *authcert = get_authcert(cert->issuer - , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA); + cert_t *authcert = get_authcert(issuer, authKeyID, X509_CA); - if (authcert != NULL) + if (authcert) { - location->authKeyID = authcert->subjectKeyID; - location->authKeySerialNumber = authcert->serialNumber; + x509_t *x509 = (x509_t*)authcert->cert; + + location->authKeyID = x509->get_subjectKeyIdentifier(x509); } } @@ -349,11 +350,10 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio */ static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b) { - return ((a->authKeyID.ptr != NULL) + return ((a->authKeyID.ptr) ? same_keyid(a->authKeyID, b->authKeyID) - : (same_dn(a->issuer, b->issuer) - && same_serial(a->authKeySerialNumber, b->authKeySerialNumber))) - && chunk_equals(a->uri, b->uri); + : a->issuer->equals(a->issuer, b->issuer)) + && streq(a->uri, b->uri); } /** @@ -362,7 +362,7 @@ static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t * ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain) { - while (chain != NULL) + while (chain) { if (same_ocsp_location(loc, chain)) return chain; @@ -393,7 +393,7 @@ static cert_status_t get_ocsp_status(const ocsp_location_t *loc, certinfop = &location->certinfo; certinfo = *certinfop; - while (certinfo != NULL) + while (certinfo) { cmp = chunk_compare(serialNumber, certinfo->serialNumber); if (cmp <= 0) @@ -416,30 +416,34 @@ static cert_status_t get_ocsp_status(const ocsp_location_t *loc, /** * Verify the ocsp status of a certificate */ -cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until, +cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until, time_t *revocationDate, crl_reason_t *revocationReason) { + x509_t *x509 = (x509_t*)cert->cert; + chunk_t serialNumber = x509->get_serial(x509); cert_status_t status; ocsp_location_t location; - time_t nextUpdate = 0; + time_t nextUpdate = UNDEFINED_TIME; *revocationDate = UNDEFINED_TIME; - *revocationReason = REASON_UNSPECIFIED; - + *revocationReason = CRL_REASON_UNSPECIFIED; + /* is an ocsp location defined? */ if (!build_ocsp_location(cert, &location)) + { return CERT_UNDEFINED; + } lock_ocsp_cache("verify_by_ocsp"); - status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate + status = get_ocsp_status(&location, serialNumber, &nextUpdate , revocationDate, revocationReason); unlock_ocsp_cache("verify_by_ocsp"); if (status == CERT_UNDEFINED || nextUpdate < time(NULL)) { plog("ocsp status is stale or not in cache"); - add_ocsp_fetch_request(&location, cert->serialNumber); + add_ocsp_fetch_request(&location, serialNumber); /* inititate fetching of ocsp status */ wake_fetch_thread("verify_by_ocsp"); @@ -457,14 +461,14 @@ void check_ocsp(void) lock_ocsp_cache("check_ocsp"); location = ocsp_cache; - - while (location != NULL) + + while (location) { char buf[BUF_LEN]; bool first = TRUE; ocsp_certinfo_t *certinfo = location->certinfo; - while (certinfo != NULL) + while (certinfo) { if (!certinfo->once) { @@ -473,9 +477,8 @@ void check_ocsp(void) DBG(DBG_CONTROL, if (first) { - dntoa(buf, BUF_LEN, location->issuer); - DBG_log("issuer: '%s'", buf); - if (location->authKeyID.ptr != NULL) + DBG_log("issuer: \"%Y\"", location->issuer); + if (location->authKeyID.ptr) { datatot(location->authKeyID.ptr, location->authKeyID.len , ':', buf, BUF_LEN); @@ -514,7 +517,7 @@ static void free_certinfos(ocsp_certinfo_t *chain) { ocsp_certinfo_t *certinfo; - while (chain != NULL) + while (chain) { certinfo = chain; chain = chain->next; @@ -527,11 +530,10 @@ static void free_certinfos(ocsp_certinfo_t *chain) */ static void free_ocsp_location(ocsp_location_t* location) { - free(location->issuer.ptr); + DESTROY_IF(location->issuer); free(location->authNameID.ptr); free(location->authKeyID.ptr); - free(location->authKeySerialNumber.ptr); - free(location->uri.ptr); + free(location->uri); free_certinfos(location->certinfo); free(location); } @@ -541,7 +543,7 @@ static void free_ocsp_location(ocsp_location_t* location) */ void free_ocsp_locations(ocsp_location_t **chain) { - while (*chain != NULL) + while (*chain) { ocsp_location_t *location = *chain; *chain = location->next; @@ -576,73 +578,55 @@ void list_ocsp_locations(ocsp_location_t *location, bool requests, { bool first = TRUE; - while (location != NULL) + while (location) { ocsp_certinfo_t *certinfo = location->certinfo; - if (certinfo != NULL) + if (certinfo) { - u_char buf[BUF_LEN]; - if (first) { whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of OCSP %s:", requests? - "fetch requests":"responses"); + whack_log(RC_COMMENT, "List of OCSP %s:", requests ? + "Fetch Requests" : "Responses"); first = FALSE; } whack_log(RC_COMMENT, " "); - if (location->issuer.ptr != NULL) - { - dntoa(buf, BUF_LEN, location->issuer); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - } - whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len - , location->uri.ptr); - if (location->authNameID.ptr != NULL) + if (location->issuer) { - datatot(location->authNameID.ptr, location->authNameID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authname: %s", buf); + whack_log(RC_COMMENT, " issuer: \"%Y\"", location->issuer); } - if (location->authKeyID.ptr != NULL) + whack_log(RC_COMMENT, " uri: '%s'", location->uri); + if (location->authNameID.ptr) { - datatot(location->authKeyID.ptr, location->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " authname: %#B", &location->authNameID); } - if (location->authKeySerialNumber.ptr != NULL) + if (location->authKeyID.ptr) { - datatot(location->authKeySerialNumber.ptr - , location->authKeySerialNumber.len, ':', buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " authkey: %#B", &location->authKeyID); } - while (certinfo != NULL) + while (certinfo) { - char thisUpdate[BUF_LEN]; - - snprintf(thisUpdate, BUF_LEN, "%T", &certinfo->thisUpdate, utc); - if (requests) { - whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate - , certinfo->trials); + whack_log(RC_COMMENT, " serial: %#B, %d trials", + &certinfo->serialNumber, certinfo->trials); } else if (certinfo->once) { - whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate - , (certinfo->nextUpdate < time(NULL))? " (expired)": ""); + whack_log(RC_COMMENT, " serial: %#B, %s, once%s", + &certinfo->serialNumber, + cert_status_names[certinfo->status], + (certinfo->nextUpdate < time(NULL))? " (expired)": ""); } else { - whack_log(RC_COMMENT, "%s, until %T %s", thisUpdate - , &certinfo->nextUpdate, utc - , check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict)); + whack_log(RC_COMMENT, " serial: %#B, %s, until %T %s", + &certinfo->serialNumber, + cert_status_names[certinfo->status], + &certinfo->nextUpdate, utc, + check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict)); } - datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s, %s", buf - , cert_status_names[certinfo->status]); certinfo = certinfo->next; } } @@ -662,7 +646,7 @@ void list_ocsp_cache(bool utc, bool strict) static bool get_ocsp_requestor_cert(ocsp_location_t *location) { - x509cert_t *cert = NULL; + cert_t *cert = NULL; /* initialize temporary static storage */ ocsp_requestor_cert = NULL; @@ -671,17 +655,17 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) for (;;) { - char buf[BUF_LEN]; + certificate_t *certificate; /* looking for a certificate from the same issuer */ - cert = get_x509cert(location->issuer, location->authKeySerialNumber - ,location->authKeyID, cert); + cert = get_x509cert(location->issuer, location->authKeyID, cert); if (cert == NULL) + { break; - + } + certificate = cert->cert; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("candidate: '%s'", buf); + DBG_log("candidate: '%Y'", certificate->get_subject(certificate)); ) if (cert->smartcard) @@ -689,7 +673,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) /* look for a matching private key on a smartcard */ smartcard_t *sc = scx_get(cert); - if (sc != NULL) + if (sc) { DBG(DBG_CONTROL, DBG_log("matching smartcard found") @@ -708,7 +692,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) /* look for a matching private key in the chained list */ private_key_t *private = get_x509_private_key(cert); - if (private != NULL) + if (private) { DBG(DBG_CONTROL, DBG_log("matching private key found") @@ -726,8 +710,7 @@ static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) { hasher_t *hasher; u_char *pos; - u_char digest_buf[HASH_SIZE_SHA1]; - chunk_t digest = chunk_from_buf(digest_buf); + chunk_t digest; chunk_t digest_info, sigdata; size_t siglen = 0; @@ -756,15 +739,15 @@ static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) { return chunk_empty; } - hasher->get_hash(hasher, tbs, digest_buf); + hasher->allocate_hash(hasher, tbs, &digest); hasher->destroy(hasher); /* according to PKCS#1 v2.1 digest must be packaged into * an ASN.1 structure for encryption */ - digest_info = asn1_wrap(ASN1_SEQUENCE, "cm" + digest_info = asn1_wrap(ASN1_SEQUENCE, "mm" , asn1_algorithmIdentifier(OID_SHA1) - , asn1_simple_object(ASN1_OCTET_STRING, digest)); + , asn1_wrap(ASN1_OCTET_STRING, "m", digest)); pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); *pos++ = 0x00; @@ -784,9 +767,9 @@ static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) */ static chunk_t build_signature(chunk_t tbsRequest) { - chunk_t sigdata, certs; + chunk_t sigdata, cert, certs; - if (ocsp_requestor_sc != NULL) + if (ocsp_requestor_sc) { /* RSA signature is done on smartcard */ sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc); @@ -803,15 +786,13 @@ static chunk_t build_signature(chunk_t tbsRequest) } /* include our certificate */ - certs = asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_simple_object(ASN1_SEQUENCE - , ocsp_requestor_cert->certificate - ) - ); + cert = ocsp_requestor_cert->cert->get_encoding(ocsp_requestor_cert->cert); + certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_SEQUENCE, "m", cert)); /* build signature comprising algorithm, signature and cert */ return asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_wrap(ASN1_SEQUENCE, "cmm" + , asn1_wrap(ASN1_SEQUENCE, "mmm" , asn1_algorithmIdentifier(OID_SHA1_WITH_RSA) , sigdata , certs @@ -825,7 +806,7 @@ static chunk_t build_signature(chunk_t tbsRequest) */ static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo) { - chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm" + chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "mmmm" , asn1_algorithmIdentifier(OID_SHA1) , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID) , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID) @@ -847,7 +828,7 @@ static chunk_t build_request_list(ocsp_location_t *location) size_t datalen = 0; /* build content */ - while (certinfo != NULL) + while (certinfo) { /* build request for every certificate in list * and store them in a chained list @@ -865,7 +846,7 @@ static chunk_t build_request_list(ocsp_location_t *location) pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen); /* copy all in chained list, free list afterwards */ - while (reqs != NULL) + while (reqs) { request_list_t *req = reqs; @@ -882,9 +863,12 @@ static chunk_t build_request_list(ocsp_location_t *location) */ static chunk_t build_requestor_name(void) { + certificate_t *certificate = ocsp_requestor_cert->cert; + identification_t *subject = certificate->get_subject(certificate); + return asn1_wrap(ASN1_CONTEXT_C_1, "m" , asn1_simple_object(ASN1_CONTEXT_C_4 - , ocsp_requestor_cert->subject)); + , subject->get_encoding(subject))); } /** @@ -944,17 +928,13 @@ chunk_t build_ocsp_request(ocsp_location_t *location) { bool has_requestor_cert; chunk_t tbsRequest, signature; - char buf[BUF_LEN]; DBG(DBG_CONTROL, DBG_log("assembling ocsp request"); - dntoa(buf, BUF_LEN, location->issuer); - DBG_log("issuer: '%s'", buf); - if (location->authKeyID.ptr != NULL) + DBG_log("issuer: \"%Y\"", location->issuer); + if (location->authKeyID.ptr) { - datatot(location->authKeyID.ptr, location->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &location->authKeyID); } ) lock_certs_and_keys("build_ocsp_request"); @@ -981,14 +961,13 @@ chunk_t build_ocsp_request(ocsp_location_t *location) */ static bool valid_ocsp_response(response_t *res) { - int pathlen; - x509cert_t *authcert; + int pathlen, pathlen_constraint; + cert_t *authcert; lock_authcert_list("valid_ocsp_response"); - authcert = get_authcert(res->responder_id_name, chunk_empty - , res->responder_id_key, AUTH_OCSP | AUTH_CA); - + authcert = get_authcert(res->responder_id_name, res->responder_id_key, + X509_OCSP_SIGNER | X509_CA); if (authcert == NULL) { plog("no matching ocsp signer cert found"); @@ -999,7 +978,8 @@ static bool valid_ocsp_response(response_t *res) DBG_log("ocsp signer cert found") ) - if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert)) + if (!x509_check_signature(res->tbs, res->signature, res->algorithm, + authcert->cert)) { plog("signature of ocsp response is invalid"); unlock_authcert_list("valid_ocsp_response"); @@ -1010,43 +990,38 @@ static bool valid_ocsp_response(response_t *res) ) - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) + for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) { - u_char buf[BUF_LEN]; - err_t ugh = NULL; - time_t until; - - x509cert_t *cert = authcert; + cert_t *cert = authcert; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); + time_t not_before, not_after; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("subject: '%s'",buf); - dntoa(buf, BUF_LEN, cert->issuer); - DBG_log("issuer: '%s'",buf); - if (cert->authKeyID.ptr != NULL) + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } ) - ugh = check_validity(authcert, &until); - - if (ugh != NULL) + if (!certificate->get_validity(certificate, NULL, ¬_before, ¬_after)) { - plog("%s", ugh); + plog("certificate is invalid (valid from %T to %T)", + ¬_before, FALSE, ¬_after, FALSE); + unlock_authcert_list("valid_ocsp_response"); return FALSE; } - DBG(DBG_CONTROL, DBG_log("certificate is valid") ) - - authcert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); + authcert = get_authcert(issuer, authKeyID, X509_CA); if (authcert == NULL) { plog("issuer cacert not found"); @@ -1057,8 +1032,7 @@ static bool valid_ocsp_response(response_t *res) DBG_log("issuer cacert found") ) - if (!x509_check_signature(cert->tbsCertificate, cert->signature, - cert->algorithm, authcert)) + if (!certificate->issued_by(certificate, authcert->cert)) { plog("certificate signature is invalid"); unlock_authcert_list("valid_ocsp_response"); @@ -1068,17 +1042,28 @@ static bool valid_ocsp_response(response_t *res) DBG_log("certificate signature is valid") ) + /* check path length constraint */ + pathlen_constraint = x509->get_pathLenConstraint(x509); + if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT && + pathlen > pathlen_constraint) + { + plog("path length of %d violates constraint of %d", + pathlen, pathlen_constraint); + return FALSE; + } + /* check if cert is self-signed */ - if (same_dn(cert->issuer, cert->subject)) + if (x509->get_flags(x509) & X509_SELF_SIGNED) { DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") + DBG_log("reached self-signed root ca with a path length of %d", + pathlen) ) unlock_authcert_list("valid_ocsp_response"); return TRUE; } } - plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); unlock_authcert_list("valid_ocsp_response"); return FALSE; } @@ -1091,7 +1076,6 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) asn1_parser_t *parser; chunk_t object; u_int version; - u_char buf[BUF_LEN]; int objectID; int extn_oid = OID_UNKNOWN; bool success = FALSE; @@ -1116,10 +1100,10 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) } break; case BASIC_RESPONSE_ID_BY_NAME: - res->responder_id_name = object; + res->responder_id_name = identification_create_from_encoding( + ID_DER_ASN1_DN, object); DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) + DBG_log(" '%Y'", res->responder_id_name) ) break; case BASIC_RESPONSE_ID_BY_KEY: @@ -1153,23 +1137,35 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) break; case BASIC_RESPONSE_CERTIFICATE: { - chunk_t blob = chunk_clone(object); - x509cert_t *cert = malloc_thing(x509cert_t); - - *cert = empty_x509cert; - - if (parse_x509cert(blob, parser->get_level(parser)+1, cert) - && cert->isOcspSigner - && trust_authcert_candidate(cert, NULL)) + cert_t *cert = malloc_thing(cert_t); + x509_t *x509; + + *cert = cert_empty; + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (cert->cert == NULL) + { + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log("parsing of embedded ocsp certificate failed") + ) + cert_free(cert); + break; + } + x509 = (x509_t*)cert->cert; + + if ((x509->get_flags(x509) & X509_OCSP_SIGNER) && + trust_authcert_candidate(cert, NULL)) { - add_authcert(cert, AUTH_OCSP); + add_authcert(cert, X509_OCSP_SIGNER); } else { DBG(DBG_CONTROL | DBG_PARSING, DBG_log("embedded ocsp certificate rejected") ) - free_x509cert(cert); + cert_free(cert); } } break; @@ -1292,7 +1288,7 @@ static bool parse_ocsp_single_response(chunk_t blob, int level0, break; case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: sres->revocationReason = (object.len == 1) - ? *object.ptr : REASON_UNSPECIFIED; + ? *object.ptr : CRL_REASON_UNSPECIFIED; break; case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: sres->status = CERT_UNKNOWN; @@ -1329,11 +1325,10 @@ ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t *location = malloc_thing(ocsp_location_t); /* unshare location fields */ - location->issuer = chunk_clone(loc->issuer); + location->issuer = loc->issuer->clone(loc->issuer); location->authNameID = chunk_clone(loc->authNameID); location->authKeyID = chunk_clone(loc->authKeyID); - location->authKeySerialNumber = chunk_clone(loc->authKeySerialNumber); - location->uri = chunk_clone(loc->uri); + location->uri = strdup(loc->uri); location->certinfo = NULL; /* insert new ocsp location in front of chain */ @@ -1369,7 +1364,7 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, certinfop = &location->certinfo; certinfo = *certinfop; - while (certinfo != NULL) + while (certinfo) { cmp = chunk_compare(info->serialNumber, certinfo->serialNumber); if (cmp <= 0) @@ -1385,10 +1380,11 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, cnew->serialNumber = chunk_clone(info->serialNumber); cnew->next = certinfo; + cnew->trials = 0; *certinfop = cnew; certinfo = cnew; } - + DBG(DBG_CONTROL, datatot(info->serialNumber.ptr, info->serialNumber.len, ':' , buf, BUF_LEN); @@ -1403,7 +1399,7 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, if (request) { certinfo->status = CERT_UNDEFINED; - + if (cmp != 0) { certinfo->thisUpdate = now; @@ -1415,7 +1411,7 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, certinfo->status = info->status; certinfo->revocationTime = info->revocationTime; certinfo->revocationReason = info->revocationReason; - + certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)? info->thisUpdate : now; @@ -1446,12 +1442,12 @@ static void process_single_response(ocsp_location_t *location, plog("ocsp single response has wrong issuer"); return; } - + /* traverse list of certinfos in increasing order */ certinfop = &location->certinfo; certinfo = *certinfop; - while (certinfo != NULL) + while (certinfo) { cmp = chunk_compare(sres->serialNumber, certinfo->serialNumber); if (cmp <= 0) @@ -1468,14 +1464,14 @@ static void process_single_response(ocsp_location_t *location, /* unlink cert from ocsp fetch request list */ *certinfop = certinfo->next; - + /* update certinfo using the single response information */ certinfo->thisUpdate = sres->thisUpdate; certinfo->nextUpdate = sres->nextUpdate; certinfo->status = sres->status; certinfo->revocationTime = sres->revocationTime; certinfo->revocationReason = sres->revocationReason; - + /* add or update certinfo in ocsp cache */ lock_ocsp_cache("process_single_response"); add_certinfo(location, certinfo, &ocsp_cache, FALSE); @@ -1486,6 +1482,14 @@ static void process_single_response(ocsp_location_t *location, } /** + * Destroy a response_t object + */ +static void free_response(response_t *res) +{ + DESTROY_IF(res->responder_id_name); +} + +/** * Parse and verify ocsp response and update the ocsp cache */ void parse_ocsp(ocsp_location_t *location, chunk_t blob) @@ -1498,24 +1502,24 @@ void parse_ocsp(ocsp_location_t *location, chunk_t blob) if (status != STATUS_SUCCESSFUL) { plog("error in ocsp response"); - return; + goto free; } /* check if there was a nonce in the request */ - if (location->nonce.ptr != NULL && res.nonce.ptr == NULL) + if (location->nonce.ptr && res.nonce.ptr == NULL) { plog("ocsp response contains no nonce, replay attack possible"); } /* check if the nonce is identical */ - if (res.nonce.ptr != NULL && !chunk_equals(res.nonce, location->nonce)) + if (res.nonce.ptr && !chunk_equals(res.nonce, location->nonce)) { plog("invalid nonce in ocsp response"); - return; + goto free; } /* check if the response is signed by a trusted key */ if (!valid_ocsp_response(&res)) { plog("invalid ocsp response"); - return; + goto free; } DBG(DBG_CONTROL, DBG_log("valid ocsp response") @@ -1536,7 +1540,7 @@ void parse_ocsp(ocsp_location_t *location, chunk_t blob) single_response_t sres = empty_single_response; if (!parse_ocsp_single_response(object, - parser->get_level(parser)+1, &sres)) + parser->get_level(parser)+1, &sres)) { goto end; } @@ -1546,4 +1550,7 @@ void parse_ocsp(ocsp_location_t *location, chunk_t blob) end: parser->destroy(parser); } + +free: + free_response(&res); } |