ocsp.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,187 行 · 第 1/5 页
C
2,187 行
static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = { { SEC_ASN1_POINTER, offsetof(ocspCertStatus, certStatusInfo.otherInfo), SEC_AnyTemplate }};/* * RevokedInfo ::= SEQUENCE { * revocationTime GeneralizedTime, * revocationReason [0] EXPLICIT CRLReason OPTIONAL } * * Note: this should be static but the AIX compiler doesn't like it (because it * was forward-declared above); it is not meant to be exported, but this * is the only way it will compile. */const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ocspRevokedInfo) }, { SEC_ASN1_GENERALIZED_TIME, offsetof(ocspRevokedInfo, revocationTime) }, { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(ocspRevokedInfo, revocationReason), SEC_PointerToEnumeratedTemplate }, { 0 }};/* * OCSP-specific extension templates: *//* * ServiceLocator ::= SEQUENCE { * issuer Name, * locator AuthorityInfoAccessSyntax OPTIONAL } */static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ocspServiceLocator) }, { SEC_ASN1_POINTER, offsetof(ocspServiceLocator, issuer), CERT_NameTemplate }, { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, offsetof(ocspServiceLocator, locator) }, { 0 }};/* * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy): *//* * FUNCTION: CERT_EncodeOCSPRequest * DER encodes an OCSP Request, possibly adding a signature as well. * XXX Signing is not yet supported, however; see comments in code. * INPUTS: * PRArenaPool *arena * The return value is allocated from here. * If a NULL is passed in, allocation is done from the heap instead. * CERTOCSPRequest *request * The request to be encoded. * void *pwArg * Pointer to argument for password prompting, if needed. (Definitely * not needed if not signing.) * RETURN: * Returns a NULL on error and a pointer to the SECItem with the * encoded value otherwise. Any error is likely to be low-level * (e.g. no memory). */SECItem *CERT_EncodeOCSPRequest(PRArenaPool *arena, CERTOCSPRequest *request, void *pwArg){ ocspTBSRequest *tbsRequest; SECStatus rv; /* XXX All of these should generate errors if they fail. */ PORT_Assert(request); PORT_Assert(request->tbsRequest); tbsRequest = request->tbsRequest; if (request->tbsRequest->extensionHandle != NULL) { rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle); request->tbsRequest->extensionHandle = NULL; if (rv != SECSuccess) return NULL; } /* * XXX When signed requests are supported and request->optionalSignature * is not NULL: * - need to encode tbsRequest->requestorName * - need to encode tbsRequest * - need to sign that encoded result (using cert in sig), filling in the * request->optionalSignature structure with the result, the signing * algorithm and (perhaps?) the cert (and its chain?) in derCerts */ return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate);}/* * FUNCTION: CERT_DecodeOCSPRequest * Decode a DER encoded OCSP Request. * INPUTS: * SECItem *src * Pointer to a SECItem holding DER encoded OCSP Request. * RETURN: * Returns a pointer to a CERTOCSPRequest containing the decoded request. * On error, returns NULL. Most likely error is trouble decoding * (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory). */CERTOCSPRequest *CERT_DecodeOCSPRequest(SECItem *src){ PRArenaPool *arena = NULL; SECStatus rv = SECFailure; CERTOCSPRequest *dest = NULL; int i; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { goto loser; } dest = (CERTOCSPRequest *) PORT_ArenaZAlloc(arena, sizeof(CERTOCSPRequest)); if (dest == NULL) { goto loser; } dest->arena = arena; rv = SEC_ASN1DecodeItem(arena, dest, ocsp_OCSPRequestTemplate, src); if (rv != SECSuccess) { if (PORT_GetError() == SEC_ERROR_BAD_DER) PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST); goto loser; } /* * XXX I would like to find a way to get rid of the necessity * of doing this copying of the arena pointer. */ for (i = 0; dest->tbsRequest->requestList[i] != NULL; i++) { dest->tbsRequest->requestList[i]->arena = arena; } return dest;loser: if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } return NULL;}/* * Create and fill-in a CertID. This function fills in the hash values * (issuerNameHash and issuerKeyHash), and is hardwired to use SHA1. * Someday it might need to be more flexible about hash algorithm, but * for now we have no intention/need to create anything else, and until * we have more flexible underlying interfaces, it's just not as easy * as it should be to just take an algorithm id and call some helper * functions to do all the work (no algid->length translation, no function * to hash from and into a SECItem, etc.). * * Error causes a null to be returned; most likely cause is trouble * finding the certificate issuer (SEC_ERROR_UNKNOWN_ISSUER). * Other errors are low-level problems (no memory, bad database, etc.). */static CERTOCSPCertID *ocsp_CreateCertID(PRArenaPool *arena, CERTCertificate *cert, int64 time){ CERTOCSPCertID *certID; CERTCertificate *issuerCert = NULL; SECItem *tempItem = NULL; void *mark = PORT_ArenaMark(arena); SECStatus rv; PORT_Assert(arena != NULL); certID = PORT_ArenaZNew(arena, CERTOCSPCertID); if (certID == NULL) { goto loser; } rv = SECOID_SetAlgorithmID(arena, &certID->hashAlgorithm, SEC_OID_SHA1, NULL); if (rv != SECSuccess) { goto loser; } issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); if (issuerCert == NULL) { goto loser; } tempItem = SEC_ASN1EncodeItem(NULL, NULL, &issuerCert->subject, CERT_NameTemplate); if (tempItem == NULL) { goto loser; } if (SECITEM_AllocItem(arena, &(certID->issuerNameHash), SHA1_LENGTH) == NULL) { goto loser; } rv = PK11_HashBuf(SEC_OID_SHA1, certID->issuerNameHash.data, tempItem->data, tempItem->len); if (rv != SECSuccess) { goto loser; } SECITEM_FreeItem(tempItem, PR_TRUE); tempItem = NULL; if (CERT_SPKDigestValueForCert(arena, issuerCert, SEC_OID_SHA1, &(certID->issuerKeyHash)) == NULL) { goto loser; } /* now we are done with issuerCert */ CERT_DestroyCertificate(issuerCert); issuerCert = NULL; rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber); if (rv != SECSuccess) { goto loser; } PORT_ArenaUnmark(arena, mark); return certID;loser: if (issuerCert != NULL) { CERT_DestroyCertificate(issuerCert); } if (tempItem != NULL) { SECITEM_FreeItem(tempItem, PR_TRUE); } PORT_ArenaRelease(arena, mark); return NULL;}/* * Callback to set Extensions in request object */void SetSingleReqExts(void *object, CERTCertExtension **exts){ ocspSingleRequest *singleRequest = (ocspSingleRequest *)object; singleRequest->singleRequestExtensions = exts;}/* * Add the Service Locator extension to the singleRequestExtensions * for the given singleRequest. * * All errors are internal or low-level problems (e.g. no memory). */static SECStatusocsp_AddServiceLocatorExtension(ocspSingleRequest *singleRequest, CERTCertificate *cert){ ocspServiceLocator *serviceLocator = NULL; void *extensionHandle = NULL; SECStatus rv = SECFailure; serviceLocator = PORT_ZNew(ocspServiceLocator); if (serviceLocator == NULL) goto loser; /* * Normally it would be a bad idea to do a direct reference like * this rather than allocate and copy the name *or* at least dup * a reference of the cert. But all we need is to be able to read * the issuer name during the encoding we are about to do, so a * copy is just a waste of time. */ serviceLocator->issuer = &cert->issuer; rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS, &serviceLocator->locator); if (rv != SECSuccess) { if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) goto loser; } /* prepare for following loser gotos */ rv = SECFailure; extensionHandle = cert_StartExtensions(singleRequest, singleRequest->arena, SetSingleReqExts); if (extensionHandle == NULL) goto loser; rv = CERT_EncodeAndAddExtension(extensionHandle, SEC_OID_PKIX_OCSP_SERVICE_LOCATOR, serviceLocator, PR_FALSE, ocsp_ServiceLocatorTemplate);loser: if (extensionHandle != NULL) { /* * Either way we have to finish out the extension context (so it gets * freed). But careful not to override any already-set bad status. */ SECStatus tmprv = CERT_FinishExtensions(extensionHandle); if (rv == SECSuccess) rv = tmprv; } /* * Finally, free the serviceLocator structure itself and we are done. */ if (serviceLocator != NULL) { if (serviceLocator->locator.data != NULL) SECITEM_FreeItem(&serviceLocator->locator, PR_FALSE); PORT_Free(serviceLocator); } return rv;}/* * Creates an array of ocspSingleRequest based on a list of certs. * Note that the code which later compares the request list with the * response expects this array to be in the exact same order as the * certs are found in the list. It would be harder to change that * order than preserve it, but since the requirement is not obvious, * it deserves to be mentioned. * * Any problem causes a null return and error set: * SEC_ERROR_UNKNOWN_ISSUER * Other errors are low-level problems (no memory, bad database, etc.). */static ocspSingleRequest **ocsp_CreateSingleRequestList(PRArenaPool *arena, CERTCertList *certList, int64 time, PRBool includeLocator){ ocspSingleRequest **requestList = NULL; CERTCertListNode *node; int i, count; void *mark = PORT_ArenaMark(arena); node = CERT_LIST_HEAD(certList); for (count = 0; !CERT_LIST_END(node, certList); count++) { node = CERT_LIST_NEXT(node); } if (count == 0) goto loser; requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, count + 1); if (requestList == NULL) goto loser; node = CERT_LIST_HEAD(certList); for (i = 0; !CERT_LIST_END(node, certList); i++) { requestList[i] = PORT_ArenaZNew(arena, ocspSingleRequest); if (requestList[i] == NULL) goto loser; requestList[i]->arena = arena; requestList[i]->reqCert = ocsp_CreateCertID(arena, node->cert, time); if (requestList[i]->reqCert == NULL) goto loser; if (includeLocator == PR_TRUE) { SECStatus rv; rv = ocsp_AddServiceLocatorExtension(requestList[i], node->cert); if (rv != SECSuccess) goto loser; } node = CERT_LIST_NEXT(node); } PORT_Assert(i == count); PORT_ArenaUnmark(arena, mark); requestList[i] = NULL; return requestList;loser: PORT_ArenaRelease(arena, mark); return NULL;}/* * FUNCTION: CERT_CreateOCSPRequest * Creates a CERTOCSPRequest, requesting the status of the certs in * the given list. * INPUTS: * CERTCertList *certList * A list of certs for which status will be requested. * Note that all of these certificates should have the same issuer, * or it's expected the response will be signed by a trusted responder. * If the certs need to be broken up into multiple requests, that * must be handled by the caller (and thus by having multiple calls * to this routine), who knows about where the request(s) are being * sent and whether there are any trusted responders in place. * int64 time * Indicates the time for which the certificate status is to be * determined -- this may be used in the search for the cert's issuer * but has no effect on the request itself. * PRBool addServiceLocator * If true, the Service Locator extension should be added to the * single request(s) for each cert. * CERTCertificate *signerCert * If non-NULL, means sign the request using this cert. Otherwise, * do not sign. * XXX note that request signing is not yet supported; see comment in code * RETURN: * A pointer to a CERTOCSPRequest structure containing an OCSP request * for the cert list. On error, null is returned, with an error set * indicating the reason. This is likely SEC_ERROR_UNKNOWN_ISSUER. * (The issuer is needed to create a request for the certificate.) * Other errors are low-level problems (no memory, bad database, etc.). */CERTOCSPRequest *CERT_CreateOCSPRequest(CERTCertList *certList, int64 time, PRBool addServiceLocator, CERTCertificate *signerCert){ PRArenaPool *arena = NULL; CERTOCSPRequest *request = NULL; ocspTBSRequest *tbsRequest = NULL; /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?