diff nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,1067 @@
+/* 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_ocspresponse.c
+ *
+ */
+
+#include "pkix_pl_ocspresponse.h"
+
+/* ----Public functions------------------------------------- */
+/*
+ * This is the libpkix replacement for CERT_VerifyOCSPResponseSignature.
+ * It is used if it has been set as the verifyFcn member of ocspChecker.
+ */
+PKIX_Error *
+PKIX_PL_OcspResponse_UseBuildChain(
+        PKIX_PL_Cert *signerCert,
+	PKIX_PL_Date *producedAt,
+        PKIX_ProcessingParams *procParams,
+        void **pNBIOContext,
+        void **pState,
+        PKIX_BuildResult **pBuildResult,
+        PKIX_VerifyNode **pVerifyTree,
+	void *plContext)
+{
+        PKIX_ProcessingParams *caProcParams = NULL;
+        PKIX_PL_Date *date = NULL;
+        PKIX_ComCertSelParams *certSelParams = NULL;
+        PKIX_CertSelector *certSelector = NULL;
+        void *nbioContext = NULL;
+        PKIX_Error *buildError = NULL;
+
+        PKIX_ENTER(OCSPRESPONSE, "pkix_OcspResponse_UseBuildChain");
+        PKIX_NULLCHECK_THREE(signerCert, producedAt, procParams);
+        PKIX_NULLCHECK_THREE(pNBIOContext, pState, pBuildResult);
+
+        nbioContext = *pNBIOContext;
+        *pNBIOContext = NULL;
+
+        /* Are we resuming after a WOULDBLOCK return, or starting anew ? */
+        if (nbioContext == NULL) {
+                /* Starting anew */
+		PKIX_CHECK(PKIX_PL_Object_Duplicate
+                        ((PKIX_PL_Object *)procParams,
+                        (PKIX_PL_Object **)&caProcParams,
+                        plContext),
+        	        PKIX_OBJECTDUPLICATEFAILED);
+
+		PKIX_CHECK(PKIX_ProcessingParams_SetDate(procParams, date, plContext),
+	                PKIX_PROCESSINGPARAMSSETDATEFAILED);
+
+	        /* create CertSelector with target certificate in params */
+
+		PKIX_CHECK(PKIX_CertSelector_Create
+	                (NULL, NULL, &certSelector, plContext),
+	                PKIX_CERTSELECTORCREATEFAILED);
+
+		PKIX_CHECK(PKIX_ComCertSelParams_Create
+	                (&certSelParams, plContext),
+	                PKIX_COMCERTSELPARAMSCREATEFAILED);
+
+	        PKIX_CHECK(PKIX_ComCertSelParams_SetCertificate
+        	        (certSelParams, signerCert, plContext),
+                	PKIX_COMCERTSELPARAMSSETCERTIFICATEFAILED);
+
+	        PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
+	                (certSelector, certSelParams, plContext),
+	                PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
+
+	        PKIX_CHECK(PKIX_ProcessingParams_SetTargetCertConstraints
+        	        (caProcParams, certSelector, plContext),
+                	PKIX_PROCESSINGPARAMSSETTARGETCERTCONSTRAINTSFAILED);
+	}
+
+        buildError = PKIX_BuildChain
+                (caProcParams,
+                &nbioContext,
+                pState,
+                pBuildResult,
+		pVerifyTree,
+                plContext);
+
+        /* non-null nbioContext means the build would block */
+        if (nbioContext != NULL) {
+
+                *pNBIOContext = nbioContext;
+
+        /* no buildResult means the build has failed */
+        } else if (buildError) {
+                pkixErrorResult = buildError;
+                buildError = NULL;
+        } else {
+                PKIX_DECREF(*pState);
+        }
+
+cleanup:
+
+        PKIX_DECREF(caProcParams);
+        PKIX_DECREF(date);
+        PKIX_DECREF(certSelParams);
+        PKIX_DECREF(certSelector);
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/* --Private-OcspResponse-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspResponse_Destroy(
+        PKIX_PL_Object *object,
+        void *plContext)
+{
+        PKIX_PL_OcspResponse *ocspRsp = NULL;
+        const SEC_HttpClientFcn *httpClient = NULL;
+        const SEC_HttpClientFcnV1 *hcv1 = NULL;
+
+        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Destroy");
+        PKIX_NULLCHECK_ONE(object);
+
+        PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
+                    PKIX_OBJECTNOTANOCSPRESPONSE);
+
+        ocspRsp = (PKIX_PL_OcspResponse *)object;
+
+        if (ocspRsp->nssOCSPResponse != NULL) {
+                CERT_DestroyOCSPResponse(ocspRsp->nssOCSPResponse);
+                ocspRsp->nssOCSPResponse = NULL;
+        }
+
+        if (ocspRsp->signerCert != NULL) {
+                CERT_DestroyCertificate(ocspRsp->signerCert);
+                ocspRsp->signerCert = NULL;
+        }
+
+        httpClient = (const SEC_HttpClientFcn *)(ocspRsp->httpClient);
+
+        if (httpClient && (httpClient->version == 1)) {
+
+                hcv1 = &(httpClient->fcnTable.ftable1);
+
+                if (ocspRsp->sessionRequest != NULL) {
+                    (*hcv1->freeFcn)(ocspRsp->sessionRequest);
+                    ocspRsp->sessionRequest = NULL;
+                }
+
+                if (ocspRsp->serverSession != NULL) {
+                    (*hcv1->freeSessionFcn)(ocspRsp->serverSession);
+                    ocspRsp->serverSession = NULL;
+                }
+        }
+
+        if (ocspRsp->arena != NULL) {
+                PORT_FreeArena(ocspRsp->arena, PR_FALSE);
+                ocspRsp->arena = NULL;
+        }
+
+	PKIX_DECREF(ocspRsp->producedAtDate);
+	PKIX_DECREF(ocspRsp->pkixSignerCert);
+	PKIX_DECREF(ocspRsp->request);
+
+cleanup:
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspResponse_Hashcode(
+        PKIX_PL_Object *object,
+        PKIX_UInt32 *pHashcode,
+        void *plContext)
+{
+        PKIX_PL_OcspResponse *ocspRsp = NULL;
+
+        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Hashcode");
+        PKIX_NULLCHECK_TWO(object, pHashcode);
+
+        PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
+                    PKIX_OBJECTNOTANOCSPRESPONSE);
+
+        ocspRsp = (PKIX_PL_OcspResponse *)object;
+
+        if (ocspRsp->encodedResponse->data == NULL) {
+                *pHashcode = 0;
+        } else {
+                PKIX_CHECK(pkix_hash
+                        (ocspRsp->encodedResponse->data,
+                        ocspRsp->encodedResponse->len,
+                        pHashcode,
+                        plContext),
+                        PKIX_HASHFAILED);
+        }
+
+cleanup:
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspResponse_Equals(
+        PKIX_PL_Object *firstObj,
+        PKIX_PL_Object *secondObj,
+        PKIX_Boolean *pResult,
+        void *plContext)
+{
+        PKIX_UInt32 secondType = 0;
+        PKIX_UInt32 firstLen = 0;
+        PKIX_UInt32 i = 0;
+        PKIX_PL_OcspResponse *rsp1 = NULL;
+        PKIX_PL_OcspResponse *rsp2 = NULL;
+        const unsigned char *firstData = NULL;
+        const unsigned char *secondData = NULL;
+
+        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Equals");
+        PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
+
+        /* test that firstObj is a OcspResponse */
+        PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPRESPONSE_TYPE, plContext),
+                    PKIX_FIRSTOBJARGUMENTNOTANOCSPRESPONSE);
+
+        /*
+         * Since we know firstObj is a OcspResponse, if both references are
+         * identical, they must be equal
+         */
+        if (firstObj == secondObj){
+                *pResult = PKIX_TRUE;
+                goto cleanup;
+        }
+
+        /*
+         * If secondObj isn't a OcspResponse, we don't throw an error.
+         * We simply return a Boolean result of FALSE
+         */
+        *pResult = PKIX_FALSE;
+        PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext),
+                PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+        if (secondType != PKIX_OCSPRESPONSE_TYPE) {
+                goto cleanup;
+        }
+
+        rsp1 = (PKIX_PL_OcspResponse *)firstObj;
+        rsp2 = (PKIX_PL_OcspResponse *)secondObj;
+
+        /* If either lacks an encoded string, they cannot be compared */
+        firstData = (const unsigned char *)rsp1->encodedResponse->data;
+        secondData = (const unsigned char *)rsp2->encodedResponse->data;
+        if ((firstData == NULL) || (secondData == NULL)) {
+                goto cleanup;
+        }
+
+        firstLen = rsp1->encodedResponse->len;
+
+        if (firstLen != rsp2->encodedResponse->len) {
+                goto cleanup;
+        }
+
+        for (i = 0; i < firstLen; i++) {
+                if (*firstData++ != *secondData++) {
+                        goto cleanup;
+                }
+        }
+
+        *pResult = PKIX_TRUE;
+
+cleanup:
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_RegisterSelf
+ * DESCRIPTION:
+ *  Registers PKIX_OCSPRESPONSE_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_OcspResponse_RegisterSelf(void *plContext)
+{
+        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+        pkix_ClassTable_Entry *entry = &systemClasses[PKIX_OCSPRESPONSE_TYPE];
+
+        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_RegisterSelf");
+
+        entry->description = "OcspResponse";
+        entry->typeObjectSize = sizeof(PKIX_PL_OcspResponse);
+        entry->destructor = pkix_pl_OcspResponse_Destroy;
+        entry->equalsFunction = pkix_pl_OcspResponse_Equals;
+        entry->hashcodeFunction = pkix_pl_OcspResponse_Hashcode;
+        entry->duplicateFunction = pkix_duplicateImmutable;
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Create
+ * DESCRIPTION:
+ *
+ *  This function transmits the OcspRequest pointed to by "request" and obtains
+ *  an OcspResponse, which it stores at "pOcspResponse". If the HTTPClient
+ *  supports non-blocking I/O this function may store a non-NULL value at
+ *  "pNBIOContext" (the WOULDBLOCK condition). In that case the caller should
+ *  make a subsequent call with the same value in "pNBIOContext" and
+ *  "pOcspResponse" to resume the operation. Additional WOULDBLOCK returns may
+ *  occur; the caller should persist until a return occurs with NULL stored at
+ *  "pNBIOContext".
+ *
+ *  If a SEC_HttpClientFcn "responder" is supplied, it is used as the client
+ *  to which the OCSP query is sent. If none is supplied, the default responder
+ *  is used.
+ *
+ *  If an OcspResponse_VerifyCallback "verifyFcn" is supplied, it is used to
+ *  verify the Cert received from the responder as the signer. If none is
+ *  supplied, the default verification function is used.
+ *
+ *  The contents of "request" are ignored on calls subsequent to a WOULDBLOCK
+ *  return, and the caller is permitted to supply NULL.
+ *
+ * PARAMETERS
+ *  "request"
+ *      Address of the OcspRequest for which a response is desired.
+ *  "httpMethod"
+ *      GET or POST
+ *  "responder"
+ *      Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP
+ *      query.
+ *  "verifyFcn"
+ *      Address, if non-NULL, of the OcspResponse_VerifyCallback function to be
+ *      used to verify the Cert of the OCSP responder.
+ *  "pNBIOContext"
+ *      Address at which platform-dependent information is stored for handling
+ *      of non-blocking I/O. Must be non-NULL.
+ *  "pOcspResponse"
+ *      The address where the created OcspResponse 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 OcspResponse 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_OcspResponse_Create(
+        PKIX_PL_OcspRequest *request,
+        const char *httpMethod,
+        void *responder,
+        PKIX_PL_VerifyCallback verifyFcn,
+        void **pNBIOContext,
+        PKIX_PL_OcspResponse **pResponse,
+        void *plContext)
+{
+        void *nbioContext = NULL;
+        PKIX_PL_OcspResponse *ocspResponse = NULL;
+        const SEC_HttpClientFcn *httpClient = NULL;
+        const SEC_HttpClientFcnV1 *hcv1 = NULL;
+        SECStatus rv = SECFailure;
+        char *location = NULL;
+        char *hostname = NULL;
+        char *path = NULL;
+        char *responseContentType = NULL;
+        PRUint16 port = 0;
+        SEC_HTTP_SERVER_SESSION serverSession = NULL;
+        SEC_HTTP_REQUEST_SESSION sessionRequest = NULL;
+        SECItem *encodedRequest = NULL;
+        PRUint16 responseCode = 0;
+        char *responseData = NULL;
+ 
+        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create");
+        PKIX_NULLCHECK_TWO(pNBIOContext, pResponse);
+
+	if (!strcmp(httpMethod, "GET") && !strcmp(httpMethod, "POST")) {
+		PKIX_ERROR(PKIX_INVALIDOCSPHTTPMETHOD);
+	}
+
+        nbioContext = *pNBIOContext;
+        *pNBIOContext = NULL;
+
+        if (nbioContext != NULL) {
+
+                ocspResponse = *pResponse;
+                PKIX_NULLCHECK_ONE(ocspResponse);
+
+                httpClient = ocspResponse->httpClient;
+                serverSession = ocspResponse->serverSession;
+                sessionRequest = ocspResponse->sessionRequest;
+                PKIX_NULLCHECK_THREE(httpClient, serverSession, sessionRequest);
+
+        } else {
+                PKIX_UInt32 timeout =
+                    ((PKIX_PL_NssContext*)plContext)->timeoutSeconds;
+
+                PKIX_NULLCHECK_ONE(request);
+
+                PKIX_CHECK(pkix_pl_OcspRequest_GetEncoded
+                        (request, &encodedRequest, plContext),
+                        PKIX_OCSPREQUESTGETENCODEDFAILED);
+
+                /* prepare initial message to HTTPClient */
+
+                /* Is there a default responder and is it enabled? */
+                if (responder) {
+                    httpClient = (const SEC_HttpClientFcn *)responder;
+                } else {
+                    httpClient = SEC_GetRegisteredHttpClient();
+                }
+
+                if (httpClient && (httpClient->version == 1)) {
+			char *fullGetPath = NULL;
+			const char *sessionPath = NULL;
+			PRBool usePOST = !strcmp(httpMethod, "POST");
+
+                        hcv1 = &(httpClient->fcnTable.ftable1);
+
+                        PKIX_CHECK(pkix_pl_OcspRequest_GetLocation
+                                (request, &location, plContext),
+                                PKIX_OCSPREQUESTGETLOCATIONFAILED);
+
+                        /* parse location -> hostname, port, path */    
+                        rv = CERT_ParseURL(location, &hostname, &port, &path);
+                        if (rv == SECFailure || hostname == NULL || path == NULL) {
+                                PKIX_ERROR(PKIX_URLPARSINGFAILED);
+                        }
+
+                        rv = (*hcv1->createSessionFcn)(hostname, port,
+                                                       &serverSession);
+                        if (rv != SECSuccess) {
+                                PKIX_ERROR(PKIX_OCSPSERVERERROR);
+                        }       
+
+			if (usePOST) {
+				sessionPath = path;
+			} else {
+				/* calculate, are we allowed to use GET? */
+				enum { max_get_request_size = 255 }; /* defined by RFC2560 */
+				char b64ReqBuf[max_get_request_size+1];
+				size_t base64size;
+				size_t slashLengthIfNeeded = 0;
+				size_t pathLength;
+				PRInt32 urlEncodedBufLength;
+				size_t getURLLength;
+				char *walkOutput = NULL;
+
+				pathLength = strlen(path);
+				if (path[pathLength-1] != '/') {
+					slashLengthIfNeeded = 1;
+				}
+				base64size = (((encodedRequest->len +2)/3) * 4);
+				if (base64size > max_get_request_size) {
+					PKIX_ERROR(PKIX_OCSPGETREQUESTTOOBIG);
+				}
+				memset(b64ReqBuf, 0, sizeof(b64ReqBuf));
+				PL_Base64Encode((const char *)encodedRequest->data, encodedRequest->len, b64ReqBuf);
+				urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL);
+				getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded;
+				fullGetPath = (char*)PORT_Alloc(getURLLength);
+				if (!fullGetPath) {
+					PKIX_ERROR(PKIX_OUTOFMEMORY);
+				}
+				strcpy(fullGetPath, path);
+				walkOutput = fullGetPath + pathLength;
+				if (walkOutput > fullGetPath && slashLengthIfNeeded) {
+					strcpy(walkOutput, "/");
+					++walkOutput;
+				}
+				ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput);
+				sessionPath = fullGetPath;
+			}
+
+                        rv = (*hcv1->createFcn)(serverSession, "http",
+                                                sessionPath, httpMethod,
+                                                PR_SecondsToInterval(timeout),
+                                                &sessionRequest);
+			sessionPath = NULL;
+			if (fullGetPath) {
+				PORT_Free(fullGetPath);
+				fullGetPath = NULL;
+			}
+			
+                        if (rv != SECSuccess) {
+                                PKIX_ERROR(PKIX_OCSPSERVERERROR);
+                        }       
+
+			if (usePOST) {
+				rv = (*hcv1->setPostDataFcn)(sessionRequest,
+							  (char *)encodedRequest->data,
+							  encodedRequest->len,
+							  "application/ocsp-request");
+				if (rv != SECSuccess) {
+					PKIX_ERROR(PKIX_OCSPSERVERERROR);
+				}
+			}
+
+                        /* create a PKIX_PL_OcspResponse object */
+                        PKIX_CHECK(PKIX_PL_Object_Alloc
+                                    (PKIX_OCSPRESPONSE_TYPE,
+                                    sizeof (PKIX_PL_OcspResponse),
+                                    (PKIX_PL_Object **)&ocspResponse,
+                                    plContext),
+                                    PKIX_COULDNOTCREATEOBJECT);
+
+                        PKIX_INCREF(request);
+                        ocspResponse->request = request;
+                        ocspResponse->httpClient = httpClient;
+                        ocspResponse->serverSession = serverSession;
+                        serverSession = NULL;
+                        ocspResponse->sessionRequest = sessionRequest;
+                        sessionRequest = NULL;
+                        ocspResponse->verifyFcn = verifyFcn;
+                        ocspResponse->handle = CERT_GetDefaultCertDB();
+                        ocspResponse->encodedResponse = NULL;
+                        ocspResponse->arena = NULL;
+                        ocspResponse->producedAt = 0;
+                        ocspResponse->producedAtDate = NULL;
+                        ocspResponse->pkixSignerCert = NULL;
+                        ocspResponse->nssOCSPResponse = NULL;
+                        ocspResponse->signerCert = NULL;
+                }
+        }
+
+        /* begin or resume IO to HTTPClient */
+        if (httpClient && (httpClient->version == 1)) {
+                PRUint32 responseDataLen = 
+                   ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+
+                hcv1 = &(httpClient->fcnTable.ftable1);
+
+                rv = (*hcv1->trySendAndReceiveFcn)(ocspResponse->sessionRequest,
+                        (PRPollDesc **)&nbioContext,
+                        &responseCode,
+                        (const char **)&responseContentType,
+                        NULL,   /* responseHeaders */
+                        (const char **)&responseData,
+                        &responseDataLen);
+
+                if (rv != SECSuccess) {
+                        PKIX_ERROR(PKIX_OCSPSERVERERROR);
+                }
+                /* responseContentType is a pointer to the null-terminated
+                 * string returned by httpclient. Memory allocated for context
+                 * type will be freed with freeing of the HttpClient struct. */
+                if (PORT_Strcasecmp(responseContentType, 
+                                   "application/ocsp-response")) {
+                       PKIX_ERROR(PKIX_OCSPSERVERERROR);
+                }
+                if (nbioContext != NULL) {
+                        *pNBIOContext = nbioContext;
+                        goto cleanup;
+                }
+                if (responseCode != 200) {
+                        PKIX_ERROR(PKIX_OCSPBADHTTPRESPONSE);
+                }
+                ocspResponse->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+                if (ocspResponse->arena == NULL) {
+                        PKIX_ERROR(PKIX_OUTOFMEMORY);
+                }
+                ocspResponse->encodedResponse = SECITEM_AllocItem
+                        (ocspResponse->arena, NULL, responseDataLen);
+                if (ocspResponse->encodedResponse == NULL) {
+                        PKIX_ERROR(PKIX_OUTOFMEMORY);
+                }
+                PORT_Memcpy(ocspResponse->encodedResponse->data,
+                            responseData, responseDataLen);
+        }
+        *pResponse = ocspResponse;
+        ocspResponse = NULL;
+
+cleanup:
+
+        if (path != NULL) {
+            PORT_Free(path);
+        }
+        if (hostname != NULL) {
+            PORT_Free(hostname);
+        }
+        if (ocspResponse) {
+            PKIX_DECREF(ocspResponse);
+        }
+        if (serverSession) {
+            hcv1->freeSessionFcn(serverSession);
+        }
+        if (sessionRequest) {
+            hcv1->freeFcn(sessionRequest);
+        }
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Decode
+ * DESCRIPTION:
+ *
+ *  This function decodes the DER data contained in the OcspResponse pointed to
+ *  by "response", storing PKIX_TRUE at "pPassed" if the decoding was
+ *  successful, and PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ *  "response"
+ *      The address of the OcspResponse whose DER data is to be decoded. Must
+ *      be non-NULL.
+ *  "pPassed"
+ *      Address at which the Boolean result is stored. Must be non-NULL.
+ *  "pReturnCode"
+ *      Address at which the SECErrorCodes 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 OcspResponse 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_OcspResponse_Decode(
+        PKIX_PL_OcspResponse *response,
+        PKIX_Boolean *pPassed,
+        SECErrorCodes *pReturnCode,
+        void *plContext)
+{
+
+        PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_Decode");
+        PKIX_NULLCHECK_TWO(response, response->encodedResponse);
+
+        response->nssOCSPResponse =
+            CERT_DecodeOCSPResponse(response->encodedResponse);
+
+	if (response->nssOCSPResponse != NULL) {
+                *pPassed = PKIX_TRUE;
+                *pReturnCode = 0;
+        } else {
+                *pPassed = PKIX_FALSE;
+                *pReturnCode = PORT_GetError();
+        }
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_GetStatus
+ * DESCRIPTION:
+ *
+ *  This function checks the response status of the OcspResponse pointed to
+ *  by "response", storing PKIX_TRUE at "pPassed" if the responder understood
+ *  the request and considered it valid, and PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ *  "response"
+ *      The address of the OcspResponse whose status is to be retrieved. Must
+ *      be non-NULL.
+ *  "pPassed"
+ *      Address at which the Boolean 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 OcspResponse 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_OcspResponse_GetStatus(
+        PKIX_PL_OcspResponse *response,
+        PKIX_Boolean *pPassed,
+        SECErrorCodes *pReturnCode,
+        void *plContext)
+{
+        SECStatus rv = SECFailure;
+
+        PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_GetStatus");
+        PKIX_NULLCHECK_FOUR(response, response->nssOCSPResponse, pPassed, pReturnCode);
+
+        rv = CERT_GetOCSPResponseStatus(response->nssOCSPResponse);
+
+	if (rv == SECSuccess) {
+                *pPassed = PKIX_TRUE;
+                *pReturnCode = 0;
+        } else {
+                *pPassed = PKIX_FALSE;
+                *pReturnCode = PORT_GetError();
+        }
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+
+static PKIX_Error*
+pkix_pl_OcspResponse_VerifyResponse(
+        PKIX_PL_OcspResponse *response,
+        PKIX_ProcessingParams *procParams,
+        SECCertUsage certUsage,
+        void **state,
+        PKIX_BuildResult **buildResult,
+        void **pNBIOContext,
+        void *plContext)
+{
+    SECStatus rv = SECFailure;
+
+    PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifyResponse");
+
+    if (response->verifyFcn != NULL) {
+        void *lplContext = NULL;
+        
+        PKIX_CHECK(
+            PKIX_PL_NssContext_Create(((SECCertificateUsage)1) << certUsage,
+                                      PKIX_FALSE, NULL, &lplContext),
+            PKIX_NSSCONTEXTCREATEFAILED);
+
+        PKIX_CHECK(
+            (response->verifyFcn)((PKIX_PL_Object*)response->pkixSignerCert,
+                                  NULL, response->producedAtDate,
+                                  procParams, pNBIOContext,
+                                  state, buildResult,
+                                  NULL, lplContext),
+            PKIX_CERTVERIFYKEYUSAGEFAILED);
+        rv = SECSuccess;
+    } else {
+        rv = CERT_VerifyCert(response->handle, response->signerCert, PKIX_TRUE,
+                             certUsage, response->producedAt, NULL, NULL);
+        if (rv != SECSuccess) {
+            PKIX_ERROR(PKIX_CERTVERIFYKEYUSAGEFAILED);
+        }
+    }
+
+cleanup:
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+    }
+
+    PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_VerifySignature
+ * DESCRIPTION:
+ *
+ *  This function verifies the ocspResponse signature field in the OcspResponse
+ *  pointed to by "response", storing PKIX_TRUE at "pPassed" if verification
+ *  is successful and PKIX_FALSE otherwise. If verification is unsuccessful an
+ *  error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode.
+ *
+ * PARAMETERS
+ *  "response"
+ *      The address of the OcspResponse whose signature field is to be
+ *      retrieved. Must be non-NULL.
+ *  "cert"
+ *      The address of the Cert for which the OCSP query was made. Must be
+ *      non-NULL.
+ *  "procParams"
+ *      Address of ProcessingParams used to initialize the ExpirationChecker
+ *      and TargetCertChecker. Must be non-NULL.
+ *  "pPassed"
+ *      Address at which the Boolean result is stored. Must be non-NULL.
+ *  "pNBIOContext"
+ *      Address at which the NBIOContext is stored indicating whether the
+ *      checking is complete. 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 OcspResponse 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_OcspResponse_VerifySignature(
+        PKIX_PL_OcspResponse *response,
+        PKIX_PL_Cert *cert,
+        PKIX_ProcessingParams *procParams,
+        PKIX_Boolean *pPassed,
+        void **pNBIOContext,
+        void *plContext)
+{
+        SECStatus rv = SECFailure;
+        CERTOCSPResponse *nssOCSPResponse = NULL;
+        CERTCertificate *issuerCert = NULL;
+        PKIX_BuildResult *buildResult = NULL;
+        void *nbio = NULL;
+        void *state = NULL;
+
+        ocspSignature *signature = NULL;
+        ocspResponseData *tbsData = NULL;
+        SECItem *tbsResponseDataDER = NULL;
+
+
+        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature");
+        PKIX_NULLCHECK_FOUR(response, cert, pPassed,  pNBIOContext);
+
+        nbio = *pNBIOContext;
+        *pNBIOContext = NULL;
+
+        nssOCSPResponse = response->nssOCSPResponse;
+        if (nssOCSPResponse == NULL) {
+            PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+            goto cleanup;
+        }
+
+        tbsData =
+            ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER);
+        
+        signature = ocsp_GetResponseSignature(nssOCSPResponse);
+
+
+        /* Are we resuming after a WOULDBLOCK response? */
+        if (nbio == NULL) {
+            /* No, this is a new query */
+
+            issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(),
+                                             certUsageAnyCA);
+            
+            /*
+             * If this signature has already gone through verification,
+             * just return the cached result.
+             */
+            if (signature->wasChecked) {
+                if (signature->status == SECSuccess) {
+                    response->signerCert =
+                        CERT_DupCertificate(signature->cert);
+                } else {
+                    PORT_SetError(signature->failureReason);
+                    goto cleanup;
+                }
+            }
+            
+            response->signerCert = 
+                ocsp_GetSignerCertificate(response->handle, tbsData,
+                                          signature, issuerCert);
+            
+            if (response->signerCert == NULL) {
+                if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) {
+                    /* Make the error a little more specific. */
+                    PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+                }
+                goto cleanup;
+            }            
+            PKIX_CHECK( 
+                PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert,
+                                                       &(response->pkixSignerCert),
+                                                       plContext),
+                PKIX_CERTCREATEWITHNSSCERTFAILED);
+            
+            /*
+             * We could mark this true at the top of this function, or
+             * always below at "finish", but if the problem was just that
+             * we could not find the signer's cert, leave that as if the
+             * signature hasn't been checked. Maybe a subsequent call will
+             * have better luck.
+             */
+            signature->wasChecked = PR_TRUE;
+            
+            /*
+             * We are about to verify the signer certificate; we need to
+             * specify *when* that certificate must be valid -- for our
+             * purposes we expect it to be valid when the response was
+             * signed. The value of "producedAt" is the signing time.
+             */
+            rv = DER_GeneralizedTimeToTime(&response->producedAt,
+                                           &tbsData->producedAt);
+            if (rv != SECSuccess) {
+                PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+                goto cleanup;
+            }
+            
+            /*
+             * We need producedAtDate and pkixSignerCert if we are calling a
+             * user-supplied verification function. Let's put their
+             * creation before the code that gets repeated when
+             * non-blocking I/O is used.
+             */
+            
+            PKIX_CHECK(
+                pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt,
+                                              &(response->producedAtDate),
+                                              plContext),
+                PKIX_DATECREATEFROMPRTIMEFAILED);
+            
+	}
+        
+        /*
+         * Just because we have a cert does not mean it is any good; check
+         * it for validity, trust and usage. Use the caller-supplied
+         * verification function, if one was supplied.
+         */
+        if (ocsp_CertIsOCSPDefaultResponder(response->handle,
+                                            response->signerCert)) {
+            rv = SECSuccess;
+        } else {
+            SECCertUsage certUsage;
+            if (CERT_IsCACert(response->signerCert, NULL)) {
+                certUsage = certUsageAnyCA;
+            } else {
+                certUsage = certUsageStatusResponder;
+            }
+            PKIX_CHECK_ONLY_FATAL(
+                pkix_pl_OcspResponse_VerifyResponse(response, procParams,
+                                                    certUsage, &state,
+                                                    &buildResult, &nbio,
+                                                    plContext),
+                PKIX_CERTVERIFYKEYUSAGEFAILED);
+            if (pkixTempErrorReceived) {
+                rv = SECFailure;
+                goto cleanup;
+            }
+            if (nbio != NULL) {
+                *pNBIOContext = nbio;
+                goto cleanup;
+            }            
+        }
+
+        rv = ocsp_VerifyResponseSignature(response->signerCert, signature,
+                                          tbsResponseDataDER, NULL);
+        
+cleanup:
+        if (rv == SECSuccess) {
+            *pPassed = PKIX_TRUE;
+        } else {
+            *pPassed = PKIX_FALSE;
+        }
+        
+        if (signature) {
+            if (signature->wasChecked) {
+                signature->status = rv;
+            }
+            
+            if (rv != SECSuccess) {
+                signature->failureReason = PORT_GetError();
+                if (response->signerCert != NULL) {
+                    CERT_DestroyCertificate(response->signerCert);
+                    response->signerCert = NULL;
+                }
+            } else {
+                /* Save signer's certificate in signature. */
+                signature->cert = CERT_DupCertificate(response->signerCert);
+            }
+        }
+
+	if (issuerCert)
+	    CERT_DestroyCertificate(issuerCert);
+        
+        PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_GetStatusForCert
+ * DESCRIPTION:
+ *
+ *  This function checks the revocation status of the Cert for which the
+ *  OcspResponse was obtained, storing PKIX_TRUE at "pPassed" if the Cert has
+ *  not been revoked and PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ *  "response"
+ *      The address of the OcspResponse whose certificate status is to be
+ *      retrieved. Must be non-NULL.
+ *  "pPassed"
+ *      Address at which the Boolean result is stored. Must be non-NULL.
+ *  "pReturnCode"
+ *      Address at which the SECErrorCodes 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 OcspResponse 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_OcspResponse_GetStatusForCert(
+        PKIX_PL_OcspCertID *cid,
+        PKIX_PL_OcspResponse *response,
+        PKIX_Boolean allowCachingOfFailures,
+        PKIX_PL_Date *validity,
+        PKIX_Boolean *pPassed,
+        SECErrorCodes *pReturnCode,
+        void *plContext)
+{
+        PRTime time = 0;
+        SECStatus rv = SECFailure;
+        CERTOCSPSingleResponse *single = NULL;
+
+        PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert");
+        PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode);
+
+        /*
+         * It is an error to call this function except following a successful
+         * return from pkix_pl_OcspResponse_VerifySignature, which would have
+         * set response->signerCert.
+         */
+        PKIX_NULLCHECK_TWO(response->signerCert, response->request);
+        PKIX_NULLCHECK_TWO(cid, cid->certID);
+
+        if (validity != NULL) {
+            PKIX_Error *er = pkix_pl_Date_GetPRTime(validity, &time, plContext);
+            PKIX_DECREF(er);
+        }
+        if (!time) {
+            time = PR_Now();
+        }
+
+        rv = ocsp_GetVerifiedSingleResponseForCertID(response->handle,
+                                                     response->nssOCSPResponse,
+                                                     cid->certID, 
+                                                     response->signerCert,
+                                                     time, &single);
+        if (rv == SECSuccess) {
+                /*
+                 * Check whether the status says revoked, and if so 
+                 * how that compares to the time value passed into this routine.
+                 */
+                rv = ocsp_CertHasGoodStatus(single->certStatus, time);
+        }
+
+        if (rv == SECSuccess || allowCachingOfFailures) {
+                /* allowed to update the cache */
+                PRBool certIDWasConsumed = PR_FALSE;
+
+                if (single) {
+                        ocsp_CacheSingleResponse(cid->certID,single,
+                                                 &certIDWasConsumed);
+                } else {
+                        cert_RememberOCSPProcessingFailure(cid->certID,
+                                                           &certIDWasConsumed);
+                }
+
+                if (certIDWasConsumed) {
+                        cid->certID = NULL;
+                }
+        }
+
+	if (rv == SECSuccess) {
+                *pPassed = PKIX_TRUE;
+                *pReturnCode = 0;
+        } else {
+                *pPassed = PKIX_FALSE;
+                *pReturnCode = PORT_GetError();
+        }
+
+        PKIX_RETURN(OCSPRESPONSE);
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)