/* * 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. * "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, 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); 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)) { 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); } rv = (*hcv1->createFcn)(serverSession, "http", path, "POST", PR_SecondsToInterval(timeout), &sessionRequest); if (rv != SECSuccess) { PKIX_ERROR(PKIX_OCSPSERVERERROR); } 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; ocspResponse->sessionRequest = sessionRequest; 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)(sessionRequest, (PRPollDesc **)&nbioContext, &responseCode, &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; cleanup: if (path != NULL) { PORT_Free(path); } if (hostname != NULL) { PORT_Free(hostname); } if (PKIX_ERROR_RECEIVED){ if (ocspResponse) { PKIX_DECREF(ocspResponse); } else { if (serverSession) hcv1->freeSessionFcn(serverSession); if (sessionRequest) hcv1->freeFcn(sessionRequest); } } PKIX_RETURN(OCSPRESPONSE); }
/* * 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. * "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, void *responder, PKIX_PL_OcspResponse_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; PRUint16 port = 0; SEC_HTTP_SERVER_SESSION serverSession = NULL; SEC_HTTP_REQUEST_SESSION requestSession = NULL; SECItem *encodedRequest = NULL; PRUint16 responseCode = 0; char *responseData = NULL; PRUint32 responseDataLen = 0; PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create"); PKIX_NULLCHECK_TWO(pNBIOContext, pResponse); nbioContext = *pNBIOContext; *pNBIOContext = NULL; if (nbioContext != NULL) { ocspResponse = *pResponse; PKIX_NULLCHECK_ONE(ocspResponse); httpClient = ocspResponse->httpClient; serverSession = ocspResponse->serverSession; requestSession = ocspResponse->requestSession; PKIX_NULLCHECK_THREE(httpClient, serverSession, requestSession); } else { 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) { PKIX_PL_NSSCALLRV (OCSPRESPONSE, responder, (void *)SEC_GetRegisteredHttpClient, ()); } httpClient = (const SEC_HttpClientFcn *)responder; if (httpClient && (httpClient->version == 1)) { hcv1 = &(httpClient->fcnTable.ftable1); PKIX_CHECK(pkix_pl_OcspRequest_GetLocation (request, &location, plContext), PKIX_OCSPREQUESTGETLOCATIONFAILED); /* parse location -> hostname, port, path */ PKIX_PL_NSSCALLRV(OCSPRESPONSE, rv, CERT_ParseURL, (location, &hostname, &port, &path)); if ((hostname == NULL) || (path == NULL)) { PKIX_ERROR(PKIX_URLPARSINGFAILED); } PKIX_PL_NSSCALLRV (OCSPRESPONSE, rv, hcv1->createSessionFcn, (hostname, port, &serverSession)); if (rv != SECSuccess) { PKIX_ERROR(PKIX_OCSPSERVERERROR); } PKIX_PL_NSSCALLRV (OCSPRESPONSE, rv, hcv1->createFcn, (serverSession, "http", path, "POST", PR_TicksPerSecond() * 60, &requestSession)); if (rv != SECSuccess) { PKIX_ERROR(PKIX_OCSPSERVERERROR); } PKIX_PL_NSSCALLRV (OCSPRESPONSE, rv, hcv1->setPostDataFcn, (requestSession, (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; ocspResponse->requestSession = requestSession; 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; } }