/* * 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); }
PKIX_Error * pkix_pl_AIAMgr_GetHTTPCerts( PKIX_PL_AIAMgr *aiaMgr, PKIX_PL_InfoAccess *ia, void **pNBIOContext, PKIX_List **pCerts, void *plContext) { PKIX_PL_GeneralName *location = NULL; PKIX_PL_String *locationString = NULL; PKIX_UInt32 len = 0; PRUint16 port = 0; const SEC_HttpClientFcn *httpClient = NULL; const SEC_HttpClientFcnV1 *hcv1 = NULL; SECStatus rv = SECFailure; SEC_HTTP_SERVER_SESSION serverSession = NULL; SEC_HTTP_REQUEST_SESSION requestSession = NULL; char *path = NULL; char *hostname = NULL; char *locationAscii = NULL; void *nbio = NULL; PRUint16 responseCode = 0; const char *responseContentType = NULL; const char *responseData = NULL; PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts"); PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts); nbio = *pNBIOContext; *pNBIOContext = NULL; *pCerts = NULL; if (nbio == NULL) { /* a new request */ PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation (ia, &location, plContext), PKIX_INFOACCESSGETLOCATIONFAILED); /* find or create httpClient = default client */ httpClient = SEC_GetRegisteredHttpClient(); aiaMgr->client.hdata.httpClient = httpClient; if (!httpClient) PKIX_ERROR(PKIX_OUTOFMEMORY); if (httpClient->version == 1) { PKIX_UInt32 timeout = ((PKIX_PL_NssContext*)plContext)->timeoutSeconds; hcv1 = &(httpClient->fcnTable.ftable1); /* create server session */ PKIX_TOSTRING(location, &locationString, plContext, PKIX_GENERALNAMETOSTRINGFAILED); PKIX_CHECK(PKIX_PL_String_GetEncoded (locationString, PKIX_ESCASCII, (void **)&locationAscii, &len, plContext), PKIX_STRINGGETENCODEDFAILED); rv = CERT_ParseURL(locationAscii, &hostname, &port, &path); if ((rv != SECSuccess) || (hostname == NULL) || (path == NULL)) { PKIX_ERROR(PKIX_URLPARSINGFAILED); } rv = (*hcv1->createSessionFcn)(hostname, port, &serverSession); if (rv != SECSuccess) { PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED); } aiaMgr->client.hdata.serverSession = serverSession; /* create request session */ rv = (*hcv1->createFcn)(serverSession, "http", path, "GET", PR_SecondsToInterval(timeout), &requestSession); if (rv != SECSuccess) { PKIX_ERROR(PKIX_HTTPSERVERERROR); } aiaMgr->client.hdata.requestSession = requestSession; } else { PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); } } httpClient = aiaMgr->client.hdata.httpClient; if (httpClient->version == 1) { PRUint32 responseDataLen = ((PKIX_PL_NssContext*)plContext)->maxResponseLength; hcv1 = &(httpClient->fcnTable.ftable1); requestSession = aiaMgr->client.hdata.requestSession; /* trySendAndReceive */ rv = (*hcv1->trySendAndReceiveFcn)(requestSession, (PRPollDesc **)&nbio, &responseCode, (const char **)&responseContentType, NULL, /* &responseHeaders */ (const char **)&responseData, &responseDataLen); if (rv != SECSuccess) { PKIX_ERROR(PKIX_HTTPSERVERERROR); } if (nbio != 0) { *pNBIOContext = nbio; goto cleanup; } PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse (responseCode, responseContentType, responseData, responseDataLen, pCerts, plContext), PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); /* Session and request cleanup in case of success */ if (aiaMgr->client.hdata.requestSession != NULL) { (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); aiaMgr->client.hdata.requestSession = NULL; } if (aiaMgr->client.hdata.serverSession != NULL) { (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); aiaMgr->client.hdata.serverSession = NULL; } aiaMgr->client.hdata.httpClient = 0; /* callback fn */ } else { PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); } cleanup: /* Session and request cleanup in case of error. Passing through without cleanup * if interrupted by blocked IO. */ if (PKIX_ERROR_RECEIVED && aiaMgr) { if (aiaMgr->client.hdata.requestSession != NULL) { (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); aiaMgr->client.hdata.requestSession = NULL; } if (aiaMgr->client.hdata.serverSession != NULL) { (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); aiaMgr->client.hdata.serverSession = NULL; } aiaMgr->client.hdata.httpClient = 0; /* callback fn */ } PKIX_DECREF(location); PKIX_DECREF(locationString); if (locationAscii) { PORT_Free(locationAscii); } if (hostname) { PORT_Free(hostname); } if (path) { PORT_Free(path); } PKIX_RETURN(AIAMGR); }
/* * FUNCTION: pkix_pl_HttpCertStore_CreateWithAsciiName * DESCRIPTION: * * This function uses the HttpClient pointed to by "client" and the string * (hostname:portnum/path, with portnum optional) pointed to by "locationAscii" * to create an HttpCertStore connected to the desired location, storing the * created CertStore at "pCertStore". * * PARAMETERS: * "client" * The address of the HttpClient. Must be non-NULL. * "locationAscii" * The address of the character string indicating the hostname, port, and * path to be queried for Certs or Crls. Must be non-NULL. * "pCertStore" * The address in which the object 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 a HttpCertStore 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_HttpCertStore_CreateWithAsciiName( PKIX_PL_HttpClient *client, char *locationAscii, PKIX_CertStore **pCertStore, void *plContext) { const SEC_HttpClientFcn *clientFcn = NULL; const SEC_HttpClientFcnV1 *hcv1 = NULL; PKIX_PL_HttpCertStoreContext *httpCertStore = NULL; PKIX_CertStore *certStore = NULL; char *hostname = NULL; char *path = NULL; PRUint16 port = 0; SECStatus rv = SECFailure; PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_CreateWithAsciiName"); PKIX_NULLCHECK_TWO(locationAscii, pCertStore); if (client == NULL) { clientFcn = SEC_GetRegisteredHttpClient(); if (clientFcn == NULL) { PKIX_ERROR(PKIX_NOREGISTEREDHTTPCLIENT); } } else { clientFcn = (const SEC_HttpClientFcn *)client; } if (clientFcn->version != 1) { PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); } /* create a PKIX_PL_HttpCertStore object */ PKIX_CHECK(PKIX_PL_Object_Alloc (PKIX_HTTPCERTSTORECONTEXT_TYPE, sizeof (PKIX_PL_HttpCertStoreContext), (PKIX_PL_Object **)&httpCertStore, plContext), PKIX_COULDNOTCREATEOBJECT); /* Initialize fields */ httpCertStore->client = clientFcn; /* not a PKIX object! */ /* parse location -> hostname, port, path */ rv = CERT_ParseURL(locationAscii, &hostname, &port, &path); if (rv == SECFailure || hostname == NULL || path == NULL) { PKIX_ERROR(PKIX_URLPARSINGFAILED); } httpCertStore->path = path; path = NULL; hcv1 = &(clientFcn->fcnTable.ftable1); rv = (*hcv1->createSessionFcn)(hostname, port, &(httpCertStore->serverSession)); if (rv != SECSuccess) { PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED); } httpCertStore->requestSession = NULL; PKIX_CHECK(PKIX_CertStore_Create (pkix_pl_HttpCertStore_GetCert, pkix_pl_HttpCertStore_GetCRL, pkix_pl_HttpCertStore_GetCertContinue, pkix_pl_HttpCertStore_GetCRLContinue, NULL, /* don't support trust */ NULL, /* can not store crls */ NULL, /* can not do revocation check */ (PKIX_PL_Object *)httpCertStore, PKIX_TRUE, /* cache flag */ PKIX_FALSE, /* not local */ &certStore, plContext), PKIX_CERTSTORECREATEFAILED); *pCertStore = certStore; certStore = NULL; cleanup: PKIX_DECREF(httpCertStore); if (hostname) { PORT_Free(hostname); } if (path) { PORT_Free(path); } PKIX_RETURN(CERTSTORE); }