/* 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); }