📄 ocsp.c
字号:
extn_oid = known_oid(object); break; case BASIC_RESPONSE_CRITICAL: critical = object.len && *object.ptr; DBG(DBG_PARSING, DBG_log(" %s",(critical)?"TRUE":"FALSE"); ) break; case BASIC_RESPONSE_EXT_VALUE: if (extn_oid == OID_NONCE) res->nonce = object; break; case BASIC_RESPONSE_ALGORITHM: res->algorithm = parse_algorithmIdentifier(object, level+1); break; case BASIC_RESPONSE_SIGNATURE: res->signature = object; break; case BASIC_RESPONSE_CERTIFICATE: { chunk_t blob; x509cert_t *cert = alloc_thing(x509cert_t, "ocspcert"); clonetochunk(blob, object.ptr, object.len, "ocspcert blob"); *cert = empty_x509cert; if (parse_x509cert(blob, level+1, cert) && cert->isOcspSigner && trust_authcert_candidate(cert, NULL)) { add_authcert(cert, AUTH_OCSP); } else { DBG(DBG_CONTROL | DBG_PARSING, DBG_log("embedded ocsp certificate rejected") ) free_x509cert(cert); } } break; } objectID++; } return TRUE;}/* * parse an ocsp response and return the result as a response_t struct */static response_statusparse_ocsp_response(chunk_t blob, response_t * res){ asn1_ctx_t ctx; chunk_t object; u_int level; int objectID = 0; response_status rStatus = STATUS_INTERNALERROR; u_int ocspResponseType = 0; asn1_init(&ctx, blob, 0, FALSE, DBG_RAW); while (objectID < OCSP_RESPONSE_ROOF) { if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx)) return STATUS_INTERNALERROR; switch (objectID) { case OCSP_RESPONSE_STATUS: rStatus = (response_status) *object.ptr; switch (rStatus) { case STATUS_SUCCESSFUL: break; case STATUS_MALFORMEDREQUEST: case STATUS_INTERNALERROR: case STATUS_TRYLATER: case STATUS_SIGREQUIRED: case STATUS_UNAUTHORIZED: plog("ocsp response: server said '%s'" , response_status_names[rStatus]); return rStatus; default: return STATUS_INTERNALERROR; } break; case OCSP_RESPONSE_TYPE: ocspResponseType = known_oid(object); break; case OCSP_RESPONSE: { switch (ocspResponseType) { case OID_BASIC: if (!parse_basic_ocsp_response(object, level+1, res)) return STATUS_INTERNALERROR; break; default: DBG(DBG_CONTROL, DBG_log("ocsp response is not of type BASIC"); DBG_dump_chunk("ocsp response OID: ", object); ) return STATUS_INTERNALERROR; } } break; } objectID++; } return rStatus;}/* * parse a basic OCSP response */static boolparse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres){ u_int level, extn_oid; asn1_ctx_t ctx; bool critical; chunk_t object; int objectID = 0; asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); while (objectID < SINGLE_RESPONSE_ROOF) { if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx)) return FALSE; switch (objectID) { case SINGLE_RESPONSE_ALGORITHM: sres->hash_algorithm = parse_algorithmIdentifier(object, level+1); break; case SINGLE_RESPONSE_ISSUER_NAME_HASH: sres->issuer_name_hash = object; break; case SINGLE_RESPONSE_ISSUER_KEY_HASH: sres->issuer_key_hash = object; break; case SINGLE_RESPONSE_SERIAL_NUMBER: sres->serialNumber = object; break; case SINGLE_RESPONSE_CERT_STATUS_GOOD: sres->status = CERT_GOOD; break; case SINGLE_RESPONSE_CERT_STATUS_REVOKED: sres->status = CERT_REVOKED; break; case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: sres->revocation_time = asn1totime(&object, ASN1_GENERALIZEDTIME); break; case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: sres->reason = *object.ptr; break; case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: sres->status = CERT_UNKNOWN; break; case SINGLE_RESPONSE_THIS_UPDATE: sres->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); break; case SINGLE_RESPONSE_NEXT_UPDATE: sres->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); break; case SINGLE_RESPONSE_EXT_ID: extn_oid = known_oid(object); break; case SINGLE_RESPONSE_CRITICAL: critical = object.len && *object.ptr; DBG(DBG_PARSING, DBG_log(" %s",(critical)?"TRUE":"FALSE"); ) case SINGLE_RESPONSE_EXT_VALUE: break; } objectID++; } return TRUE;}/* * add an ocsp location to a chained list */ocsp_location_t*add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t **chain){ ocsp_location_t *location = alloc_thing(ocsp_location_t, "ocsp location"); /* unshare location fields */ clonetochunk(location->issuer , loc->issuer.ptr, loc->issuer.len , "ocsp issuer"); clonetochunk(location->authNameID , loc->authNameID.ptr, loc->authNameID.len , "ocsp authNameID"); if (loc->authKeyID.ptr == NULL) location->authKeyID = empty_chunk; else clonetochunk(location->authKeyID , loc->authKeyID.ptr, loc->authKeyID.len , "ocsp authKeyID"); if (loc->authKeySerialNumber.ptr == NULL) location->authKeySerialNumber = empty_chunk; else clonetochunk(location->authKeySerialNumber , loc->authKeySerialNumber.ptr, loc->authKeySerialNumber.len , "ocsp authKeySerialNumber"); clonetochunk(location->uri , loc->uri.ptr, loc->uri.len , "ocsp uri"); location->certinfo = NULL; /* insert new ocsp location in front of chain */ location->next = *chain; *chain = location; DBG(DBG_CONTROL, DBG_log("new ocsp location added") ) return location;}/* * add a certinfo struct to a chained list */voidadd_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chain , bool request){ ocsp_location_t *location; ocsp_certinfo_t *certinfo, **certinfop; char buf[BUF_LEN]; time_t now; int cmp = -1; location = get_ocsp_location(loc, *chain); if (location == NULL) location = add_ocsp_location(loc, chain); /* traverse list of certinfos in increasing order */ certinfop = &location->certinfo; certinfo = *certinfop; while (certinfo != NULL) { cmp = cmp_chunk(info->serialNumber, certinfo->serialNumber); if (cmp <= 0) break; certinfop = &certinfo->next; certinfo = *certinfop; } if (cmp != 0) { /* add a new certinfo entry */ ocsp_certinfo_t *cnew = alloc_thing(ocsp_certinfo_t, "ocsp certinfo"); clonetochunk(cnew->serialNumber, info->serialNumber.ptr , info->serialNumber.len, "serialNumber"); cnew->next = certinfo; *certinfop = cnew; certinfo = cnew; } DBG(DBG_CONTROL, datatot(info->serialNumber.ptr, info->serialNumber.len, ':' , buf, BUF_LEN); DBG_log("ocsp %s for serial %s %s" , request?"fetch request":"certinfo" , buf , (cmp == 0)? (request?"already exists":"updated"):"added") ) time(&now); if (request) { certinfo->status = CERT_UNDEFINED; if (cmp != 0) certinfo->thisUpdate = now; certinfo->nextUpdate = UNDEFINED_TIME; } else { certinfo->status = info->status; certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)? info->thisUpdate : now; certinfo->once = (info->nextUpdate == UNDEFINED_TIME); certinfo->nextUpdate = (certinfo->once)? (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate; }}/* * process received ocsp single response and add it to ocsp cache */static voidprocess_single_response(ocsp_location_t *location, single_response_t *sres){ ocsp_certinfo_t *certinfo, **certinfop; int cmp = 0; if (sres->hash_algorithm != OID_SHA1) { plog("only SHA-1 hash supported in OCSP single response"); return; } if (!(same_chunk(sres->issuer_name_hash, location->authNameID) && same_chunk(sres->issuer_key_hash, location->authKeyID))) { plog("ocsp single response has wrong issuer"); return; } /* traverse list of certinfos in increasing order */ certinfop = &location->certinfo; certinfo = *certinfop; while (certinfo != NULL) { cmp = cmp_chunk(sres->serialNumber, certinfo->serialNumber); if (cmp <= 0) break; certinfop = &certinfo->next; certinfo = *certinfop; } if (cmp != 0) { plog("received unrequested cert status from ocsp server"); return; } /* 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; /* add or update certinfo in ocsp cache */ lock_ocsp_cache("process_single_response"); add_certinfo(location, certinfo, &ocsp_cache, FALSE); unlock_ocsp_cache("process_single_response"); /* free certinfo unlinked from ocsp fetch request list */ free_certinfo(certinfo);}/* * parse and verify ocsp response and update the ocsp cache */voidparse_ocsp(ocsp_location_t *location, chunk_t blob){ response_t res = empty_response; /* parse the ocsp response without looking at the single responses yet */ response_status status = parse_ocsp_response(blob, &res); if (status != STATUS_SUCCESSFUL) { plog("error in ocsp response"); return; } /* check if there was a nonce in the request */ if (location->nonce.ptr != NULL && res.nonce.ptr == NULL) { plog("ocsp response contains no nonce, replay attack possible"); } /* check if the nonce is identical */ if (res.nonce.ptr != NULL && !same_chunk(res.nonce, location->nonce)) { plog("invalid nonce in ocsp response"); return; } /* check if the response is signed by a trusted key */ if (!valid_ocsp_response(&res)) { plog("invalid ocsp response"); return; } DBG(DBG_CONTROL, DBG_log("valid ocsp response") ) /* now parse the single responses one at a time */ { u_int level; asn1_ctx_t ctx; chunk_t object; int objectID = 0; asn1_init(&ctx, res.responses, 0, FALSE, DBG_RAW); while (objectID < RESPONSES_ROOF) { if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx)) return; if (objectID == RESPONSES_SINGLE_RESPONSE) { single_response_t sres = empty_single_response; if (parse_ocsp_single_response(object, level+1, &sres)) { process_single_response(location, &sres); } } objectID++; } }}/* * Local Variables: * c-basic-offset:4 * c-style: pluto * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -