| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| /* |
| * pkix_pl_ocsprequest.c |
| * |
| */ |
| |
| #include "pkix_pl_ocsprequest.h" |
| |
| /* --Private-OcspRequest-Functions------------------------------------- */ |
| |
| /* |
| * FUNCTION: pkix_pl_OcspRequest_Destroy |
| * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_pl_OcspRequest_Destroy( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_PL_OcspRequest *ocspReq = NULL; |
| |
| PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Destroy"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), |
| PKIX_OBJECTNOTOCSPREQUEST); |
| |
| ocspReq = (PKIX_PL_OcspRequest *)object; |
| |
| if (ocspReq->decoded != NULL) { |
| CERT_DestroyOCSPRequest(ocspReq->decoded); |
| } |
| |
| if (ocspReq->encoded != NULL) { |
| SECITEM_FreeItem(ocspReq->encoded, PR_TRUE); |
| } |
| |
| if (ocspReq->location != NULL) { |
| PORT_Free(ocspReq->location); |
| } |
| |
| PKIX_DECREF(ocspReq->cert); |
| PKIX_DECREF(ocspReq->validity); |
| PKIX_DECREF(ocspReq->signerCert); |
| |
| cleanup: |
| |
| PKIX_RETURN(OCSPREQUEST); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_OcspRequest_Hashcode |
| * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_pl_OcspRequest_Hashcode( |
| PKIX_PL_Object *object, |
| PKIX_UInt32 *pHashcode, |
| void *plContext) |
| { |
| PKIX_UInt32 certHash = 0; |
| PKIX_UInt32 dateHash = 0; |
| PKIX_UInt32 extensionHash = 0; |
| PKIX_UInt32 signerHash = 0; |
| PKIX_PL_OcspRequest *ocspRq = NULL; |
| |
| PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Hashcode"); |
| PKIX_NULLCHECK_TWO(object, pHashcode); |
| |
| PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), |
| PKIX_OBJECTNOTOCSPREQUEST); |
| |
| ocspRq = (PKIX_PL_OcspRequest *)object; |
| |
| *pHashcode = 0; |
| |
| PKIX_HASHCODE(ocspRq->cert, &certHash, plContext, |
| PKIX_CERTHASHCODEFAILED); |
| |
| PKIX_HASHCODE(ocspRq->validity, &dateHash, plContext, |
| PKIX_DATEHASHCODEFAILED); |
| |
| if (ocspRq->addServiceLocator == PKIX_TRUE) { |
| extensionHash = 0xff; |
| } |
| |
| PKIX_HASHCODE(ocspRq->signerCert, &signerHash, plContext, |
| PKIX_CERTHASHCODEFAILED); |
| |
| *pHashcode = (((((extensionHash << 8) | certHash) << 8) | |
| dateHash) << 8) | signerHash; |
| |
| cleanup: |
| |
| PKIX_RETURN(OCSPREQUEST); |
| |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_OcspRequest_Equals |
| * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_pl_OcspRequest_Equals( |
| PKIX_PL_Object *firstObj, |
| PKIX_PL_Object *secondObj, |
| PKIX_Boolean *pResult, |
| void *plContext) |
| { |
| PKIX_Boolean match = PKIX_FALSE; |
| PKIX_UInt32 secondType = 0; |
| PKIX_PL_OcspRequest *firstReq = NULL; |
| PKIX_PL_OcspRequest *secondReq = NULL; |
| |
| PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Equals"); |
| PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); |
| |
| /* test that firstObj is a OcspRequest */ |
| PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPREQUEST_TYPE, plContext), |
| PKIX_FIRSTOBJARGUMENTNOTOCSPREQUEST); |
| |
| /* |
| * Since we know firstObj is a OcspRequest, if both references are |
| * identical, they must be equal |
| */ |
| if (firstObj == secondObj){ |
| match = PKIX_TRUE; |
| goto cleanup; |
| } |
| |
| /* |
| * If secondObj isn't a OcspRequest, we don't throw an error. |
| * We simply return a Boolean result of FALSE |
| */ |
| PKIX_CHECK(PKIX_PL_Object_GetType |
| (secondObj, &secondType, plContext), |
| PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); |
| if (secondType != PKIX_OCSPREQUEST_TYPE) { |
| goto cleanup; |
| } |
| |
| firstReq = (PKIX_PL_OcspRequest *)firstObj; |
| secondReq = (PKIX_PL_OcspRequest *)secondObj; |
| |
| if (firstReq->addServiceLocator != secondReq->addServiceLocator) { |
| goto cleanup; |
| } |
| |
| PKIX_EQUALS(firstReq->cert, secondReq->cert, &match, plContext, |
| PKIX_CERTEQUALSFAILED); |
| |
| if (match == PKIX_FALSE) { |
| goto cleanup; |
| } |
| |
| PKIX_EQUALS(firstReq->validity, secondReq->validity, &match, plContext, |
| PKIX_DATEEQUALSFAILED); |
| |
| if (match == PKIX_FALSE) { |
| goto cleanup; |
| } |
| |
| PKIX_EQUALS |
| (firstReq->signerCert, secondReq->signerCert, &match, plContext, |
| PKIX_CERTEQUALSFAILED); |
| |
| cleanup: |
| |
| *pResult = match; |
| |
| PKIX_RETURN(OCSPREQUEST); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_OcspRequest_RegisterSelf |
| * DESCRIPTION: |
| * Registers PKIX_OCSPREQUEST_TYPE and its related functions with |
| * systemClasses[] |
| * PARAMETERS: |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Not Thread Safe - for performance and complexity reasons |
| * |
| * Since this function is only called by PKIX_PL_Initialize, which should |
| * only be called once, it is acceptable that this function is not |
| * thread-safe. |
| */ |
| PKIX_Error * |
| pkix_pl_OcspRequest_RegisterSelf(void *plContext) |
| { |
| extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; |
| pkix_ClassTable_Entry entry; |
| |
| PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_RegisterSelf"); |
| |
| entry.description = "OcspRequest"; |
| entry.objCounter = 0; |
| entry.typeObjectSize = sizeof(PKIX_PL_OcspRequest); |
| entry.destructor = pkix_pl_OcspRequest_Destroy; |
| entry.equalsFunction = pkix_pl_OcspRequest_Equals; |
| entry.hashcodeFunction = pkix_pl_OcspRequest_Hashcode; |
| entry.toStringFunction = NULL; |
| entry.comparator = NULL; |
| entry.duplicateFunction = pkix_duplicateImmutable; |
| |
| systemClasses[PKIX_OCSPREQUEST_TYPE] = entry; |
| |
| PKIX_RETURN(OCSPREQUEST); |
| } |
| |
| /* --Public-Functions------------------------------------------------------- */ |
| |
| /* |
| * FUNCTION: pkix_pl_OcspRequest_Create |
| * DESCRIPTION: |
| * |
| * This function creates an OcspRequest to be used in validating the Cert |
| * pointed to by "cert" and storing the result at "pRequest". If a URI |
| * is found for an OCSP responder, PKIX_TRUE is stored at "pURIFound". If no |
| * URI is found, PKIX_FALSE is stored. |
| * |
| * If a Date is provided in "validity" it may be used in the search for the |
| * issuer of "cert" but has no effect on the request itself. If |
| * "addServiceLocator" is TRUE, the AddServiceLocator extension will be |
| * included in the Request. If "signerCert" is provided it will be used to sign |
| * the Request. (Note: this signed request feature is not currently supported.) |
| * |
| * PARAMETERS: |
| * "cert" |
| * Address of the Cert for which an OcspRequest is to be created. Must be |
| * non-NULL. |
| * "validity" |
| * Address of the Date for which the Cert's validity is to be determined. |
| * May be NULL. |
| * "signerCert" |
| * Address of the Cert to be used, if present, in signing the request. |
| * May be NULL. |
| * "pRequest" |
| * Address at which the result is stored. Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns an OcspRequest Error if the function fails in a non-fatal way. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| PKIX_Error * |
| pkix_pl_OcspRequest_Create( |
| PKIX_PL_Cert *cert, |
| PKIX_PL_OcspCertID *cid, |
| PKIX_PL_Date *validity, |
| PKIX_PL_Cert *signerCert, |
| PKIX_UInt32 methodFlags, |
| PKIX_Boolean *pURIFound, |
| PKIX_PL_OcspRequest **pRequest, |
| void *plContext) |
| { |
| PKIX_PL_OcspRequest *ocspRequest = NULL; |
| |
| CERTCertDBHandle *handle = NULL; |
| SECStatus rv = SECFailure; |
| SECItem *encoding = NULL; |
| CERTOCSPRequest *certRequest = NULL; |
| PRTime time = 0; |
| PRBool addServiceLocatorExtension = PR_FALSE; |
| CERTCertificate *nssCert = NULL; |
| CERTCertificate *nssSignerCert = NULL; |
| char *location = NULL; |
| PRErrorCode locError = 0; |
| PKIX_Boolean canUseDefaultSource = PKIX_FALSE; |
| |
| PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Create"); |
| PKIX_NULLCHECK_TWO(cert, pRequest); |
| |
| /* create a PKIX_PL_OcspRequest object */ |
| PKIX_CHECK(PKIX_PL_Object_Alloc |
| (PKIX_OCSPREQUEST_TYPE, |
| sizeof (PKIX_PL_OcspRequest), |
| (PKIX_PL_Object **)&ocspRequest, |
| plContext), |
| PKIX_COULDNOTCREATEOBJECT); |
| |
| PKIX_INCREF(cert); |
| ocspRequest->cert = cert; |
| |
| PKIX_INCREF(validity); |
| ocspRequest->validity = validity; |
| |
| PKIX_INCREF(signerCert); |
| ocspRequest->signerCert = signerCert; |
| |
| ocspRequest->decoded = NULL; |
| ocspRequest->encoded = NULL; |
| |
| ocspRequest->location = NULL; |
| |
| nssCert = cert->nssCert; |
| |
| /* |
| * Does this Cert have an Authority Information Access extension with |
| * the URI of an OCSP responder? |
| */ |
| handle = CERT_GetDefaultCertDB(); |
| |
| if (!(methodFlags & PKIX_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE)) { |
| canUseDefaultSource = PKIX_TRUE; |
| } |
| location = ocsp_GetResponderLocation(handle, nssCert, |
| canUseDefaultSource, |
| &addServiceLocatorExtension); |
| if (location == NULL) { |
| locError = PORT_GetError(); |
| if (locError == SEC_ERROR_EXTENSION_NOT_FOUND || |
| locError == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) { |
| PORT_SetError(0); |
| *pURIFound = PKIX_FALSE; |
| goto cleanup; |
| } |
| PKIX_ERROR(PKIX_ERRORFINDINGORPROCESSINGURI); |
| } |
| |
| ocspRequest->location = location; |
| *pURIFound = PKIX_TRUE; |
| |
| if (signerCert != NULL) { |
| nssSignerCert = signerCert->nssCert; |
| } |
| |
| if (validity != NULL) { |
| PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), |
| PKIX_DATEGETPRTIMEFAILED); |
| } else { |
| time = PR_Now(); |
| } |
| |
| certRequest = cert_CreateSingleCertOCSPRequest( |
| cid->certID, cert->nssCert, time, |
| addServiceLocatorExtension, nssSignerCert); |
| |
| ocspRequest->decoded = certRequest; |
| |
| if (certRequest == NULL) { |
| PKIX_ERROR(PKIX_UNABLETOCREATECERTOCSPREQUEST); |
| } |
| |
| rv = CERT_AddOCSPAcceptableResponses( |
| certRequest, SEC_OID_PKIX_OCSP_BASIC_RESPONSE); |
| |
| if (rv == SECFailure) { |
| PKIX_ERROR(PKIX_UNABLETOADDACCEPTABLERESPONSESTOREQUEST); |
| } |
| |
| encoding = CERT_EncodeOCSPRequest(NULL, certRequest, NULL); |
| |
| ocspRequest->encoded = encoding; |
| |
| *pRequest = ocspRequest; |
| ocspRequest = NULL; |
| |
| cleanup: |
| PKIX_DECREF(ocspRequest); |
| |
| PKIX_RETURN(OCSPREQUEST); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_OcspRequest_GetEncoded |
| * DESCRIPTION: |
| * |
| * This function obtains the encoded message from the OcspRequest pointed to |
| * by "request", storing the result at "pRequest". |
| * |
| * PARAMETERS |
| * "request" |
| * The address of the OcspRequest whose encoded message is to be |
| * retrieved. Must be non-NULL. |
| * "pRequest" |
| * The address at which is stored the address of the encoded message. Must |
| * be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| PKIX_Error * |
| pkix_pl_OcspRequest_GetEncoded( |
| PKIX_PL_OcspRequest *request, |
| SECItem **pRequest, |
| void *plContext) |
| { |
| PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetEncoded"); |
| PKIX_NULLCHECK_TWO(request, pRequest); |
| |
| *pRequest = request->encoded; |
| |
| PKIX_RETURN(OCSPREQUEST); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_OcspRequest_GetLocation |
| * DESCRIPTION: |
| * |
| * This function obtains the location from the OcspRequest pointed to |
| * by "request", storing the result at "pLocation". |
| * |
| * PARAMETERS |
| * "request" |
| * The address of the OcspRequest whose encoded message is to be |
| * retrieved. Must be non-NULL. |
| * "pLocation" |
| * The address at which is stored the address of the location. Must |
| * be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns NULL if the function succeeds. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| PKIX_Error * |
| pkix_pl_OcspRequest_GetLocation( |
| PKIX_PL_OcspRequest *request, |
| char **pLocation, |
| void *plContext) |
| { |
| PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetLocation"); |
| PKIX_NULLCHECK_TWO(request, pLocation); |
| |
| *pLocation = request->location; |
| |
| PKIX_RETURN(OCSPREQUEST); |
| } |