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