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 + -
显示快捷键?