| /* 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_httpcertstore.c |
| * |
| * HTTPCertStore Function Definitions |
| * |
| */ |
| |
| /* We can't decode the length of a message without at least this many bytes */ |
| |
| #include "pkix_pl_httpcertstore.h" |
| extern PKIX_PL_HashTable *httpSocketCache; |
| SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate) |
| SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
| SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate) |
| SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate) |
| |
| SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate) |
| SEC_ASN1_CHOOSER_DECLARE(SECOID_AlgorithmIDTemplate) |
| /* SEC_ASN1_CHOOSER_DECLARE(SEC_SetOfAnyTemplate) |
| SEC_ASN1_CHOOSER_DECLARE(CERT_SetOfSignedCrlTemplate) |
| |
| const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = { |
| { SEC_ASN1_SEQUENCE, |
| 0, NULL, sizeof(CERTIssuerAndSN) }, |
| { SEC_ASN1_SAVE, |
| offsetof(CERTIssuerAndSN,derIssuer) }, |
| { SEC_ASN1_INLINE, |
| offsetof(CERTIssuerAndSN,issuer), |
| CERT_NameTemplate }, |
| { SEC_ASN1_INTEGER, |
| offsetof(CERTIssuerAndSN,serialNumber) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SECOID_AlgorithmIDTemplate[] = { |
| { SEC_ASN1_SEQUENCE, |
| 0, NULL, sizeof(SECAlgorithmID) }, |
| { SEC_ASN1_OBJECT_ID, |
| offsetof(SECAlgorithmID,algorithm) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, |
| offsetof(SECAlgorithmID,parameters) }, |
| { 0 } |
| }; */ |
| |
| /* --Private-HttpCertStoreContext-Object Functions----------------------- */ |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStoreContext_Destroy |
| * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_pl_HttpCertStoreContext_Destroy( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| const SEC_HttpClientFcnV1 *hcv1 = NULL; |
| PKIX_PL_HttpCertStoreContext *context = NULL; |
| |
| PKIX_ENTER |
| (HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStoreContext_Destroy"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| PKIX_CHECK(pkix_CheckType |
| (object, PKIX_HTTPCERTSTORECONTEXT_TYPE, plContext), |
| PKIX_OBJECTNOTANHTTPCERTSTORECONTEXT); |
| |
| context = (PKIX_PL_HttpCertStoreContext *)object; |
| hcv1 = (const SEC_HttpClientFcnV1 *)(context->client); |
| if (context->requestSession != NULL) { |
| (*hcv1->freeFcn)(context->requestSession); |
| context->requestSession = NULL; |
| } |
| if (context->serverSession != NULL) { |
| (*hcv1->freeSessionFcn)(context->serverSession); |
| context->serverSession = NULL; |
| } |
| if (context->path != NULL) { |
| PORT_Free(context->path); |
| context->path = NULL; |
| } |
| |
| cleanup: |
| |
| PKIX_RETURN(HTTPCERTSTORECONTEXT); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStoreContext_RegisterSelf |
| * |
| * DESCRIPTION: |
| * Registers PKIX_PL_HTTPCERTSTORECONTEXT_TYPE and its related |
| * functions with systemClasses[] |
| * |
| * 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_HttpCertStoreContext_RegisterSelf(void *plContext) |
| { |
| extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; |
| pkix_ClassTable_Entry *entry = &systemClasses[PKIX_HTTPCERTSTORECONTEXT_TYPE]; |
| |
| PKIX_ENTER(HTTPCERTSTORECONTEXT, |
| "pkix_pl_HttpCertStoreContext_RegisterSelf"); |
| |
| entry->description = "HttpCertStoreContext"; |
| entry->typeObjectSize = sizeof(PKIX_PL_HttpCertStoreContext); |
| entry->destructor = pkix_pl_HttpCertStoreContext_Destroy; |
| |
| PKIX_RETURN(HTTPCERTSTORECONTEXT); |
| } |
| |
| |
| /* --Private-Http-CertStore-Database-Functions----------------------- */ |
| |
| typedef struct callbackContextStruct { |
| PKIX_List *pkixCertList; |
| PKIX_Error *error; |
| void *plContext; |
| } callbackContext; |
| |
| |
| /* |
| * FUNCTION: certCallback |
| * DESCRIPTION: |
| * |
| * This function processes the null-terminated array of SECItems produced by |
| * extracting the contents of a signedData message received in response to an |
| * HTTP cert query. Its address is supplied as a callback function to |
| * CERT_DecodeCertPackage; it is not expected to be called directly. |
| * |
| * Note that it does not conform to the libpkix API standard of returning |
| * a PKIX_Error*. It returns a SECStatus. |
| * |
| * PARAMETERS: |
| * "arg" |
| * The address of the callbackContext provided as a void* argument to |
| * CERT_DecodeCertPackage. Must be non-NULL. |
| * "secitemCerts" |
| * The address of the null-terminated array of SECItems. Must be non-NULL. |
| * "numcerts" |
| * The number of SECItems found in the signedData. Must be non-NULL. |
| * "plContext" |
| * Platform-specific context pointer. |
| * THREAD SAFETY: |
| * Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| * RETURNS: |
| * Returns SECSuccess if the function succeeds. |
| * Returns SECFailure if the function fails. |
| */ |
| static SECStatus |
| certCallback(void *arg, SECItem **secitemCerts, int numcerts) |
| { |
| callbackContext *cbContext; |
| PKIX_List *pkixCertList = NULL; |
| PKIX_Error *error = NULL; |
| void *plContext = NULL; |
| int itemNum = 0; |
| |
| if ((arg == NULL) || (secitemCerts == NULL)) { |
| return (SECFailure); |
| } |
| |
| cbContext = (callbackContext *)arg; |
| plContext = cbContext->plContext; |
| pkixCertList = cbContext->pkixCertList; |
| |
| for (; itemNum < numcerts; itemNum++ ) { |
| error = pkix_pl_Cert_CreateToList(secitemCerts[itemNum], |
| pkixCertList, plContext); |
| if (error != NULL) { |
| if (error->errClass == PKIX_FATAL_ERROR) { |
| cbContext->error = error; |
| return SECFailure; |
| } |
| /* reuse "error" since we could not destruct the old * |
| * value */ |
| error = PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, |
| plContext); |
| if (error) { |
| /* Treat decref failure as a fatal error. |
| * In this case will leak error, but can not do |
| * anything about it. */ |
| error->errClass = PKIX_FATAL_ERROR; |
| cbContext->error = error; |
| return SECFailure; |
| } |
| } |
| } |
| |
| return SECSuccess; |
| } |
| |
| |
| typedef SECStatus (*pkix_DecodeCertsFunc)(char *certbuf, int certlen, |
| CERTImportCertificateFunc f, void *arg); |
| |
| |
| struct pkix_DecodeFuncStr { |
| pkix_DecodeCertsFunc func; /* function pointer to the |
| * CERT_DecodeCertPackage function */ |
| PRLibrary *smimeLib; /* Pointer to the smime shared lib*/ |
| PRCallOnceType once; |
| }; |
| |
| static struct pkix_DecodeFuncStr pkix_decodeFunc; |
| static const PRCallOnceType pkix_pristine; |
| |
| #define SMIME_LIB_NAME SHLIB_PREFIX"smime3."SHLIB_SUFFIX |
| |
| /* |
| * load the smime library and look up the SEC_ReadPKCS7Certs function. |
| * we do this so we don't have a circular depenency on the smime library, |
| * and also so we don't have to load the smime library in applications that |
| * don't use it. |
| */ |
| static PRStatus PR_CALLBACK pkix_getDecodeFunction(void) |
| { |
| pkix_decodeFunc.smimeLib = |
| PR_LoadLibrary(SHLIB_PREFIX"smime3."SHLIB_SUFFIX); |
| if (pkix_decodeFunc.smimeLib == NULL) { |
| return PR_FAILURE; |
| } |
| |
| pkix_decodeFunc.func = (pkix_DecodeCertsFunc) PR_FindFunctionSymbol( |
| pkix_decodeFunc.smimeLib, "CERT_DecodeCertPackage"); |
| if (!pkix_decodeFunc.func) { |
| return PR_FAILURE; |
| } |
| return PR_SUCCESS; |
| |
| } |
| |
| /* |
| * clears our global state on shutdown. |
| */ |
| void |
| pkix_pl_HttpCertStore_Shutdown(void *plContext) |
| { |
| if (pkix_decodeFunc.smimeLib) { |
| PR_UnloadLibrary(pkix_decodeFunc.smimeLib); |
| pkix_decodeFunc.smimeLib = NULL; |
| } |
| /* the function pointer just need to be cleared, not freed */ |
| pkix_decodeFunc.func = NULL; |
| pkix_decodeFunc.once = pkix_pristine; |
| } |
| |
| /* |
| * This function is based on CERT_DecodeCertPackage from lib/pkcs7/certread.c |
| * read an old style ascii or binary certificate chain |
| */ |
| PKIX_Error * |
| pkix_pl_HttpCertStore_DecodeCertPackage |
| (const char *certbuf, |
| int certlen, |
| CERTImportCertificateFunc f, |
| void *arg, |
| void *plContext) |
| { |
| |
| PRStatus status; |
| SECStatus rv; |
| |
| PKIX_ENTER |
| (HTTPCERTSTORECONTEXT, |
| "pkix_pl_HttpCertStore_DecodeCertPackage"); |
| PKIX_NULLCHECK_TWO(certbuf, f); |
| |
| status = PR_CallOnce(&pkix_decodeFunc.once, pkix_getDecodeFunction); |
| |
| if (status != PR_SUCCESS) { |
| PKIX_ERROR(PKIX_CANTLOADLIBSMIME); |
| } |
| |
| /* paranoia, shouldn't happen if status == PR_SUCCESS); */ |
| if (!pkix_decodeFunc.func) { |
| PKIX_ERROR(PKIX_CANTLOADLIBSMIME); |
| } |
| |
| rv = (*pkix_decodeFunc.func)((char*)certbuf, certlen, f, arg); |
| |
| if (rv != SECSuccess) { |
| PKIX_ERROR (PKIX_SECREADPKCS7CERTSFAILED); |
| } |
| |
| |
| cleanup: |
| |
| PKIX_RETURN(HTTPCERTSTORECONTEXT); |
| } |
| |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStore_ProcessCertResponse |
| * DESCRIPTION: |
| * |
| * This function verifies that the response code pointed to by "responseCode" |
| * and the content type pointed to by "responseContentType" are as expected, |
| * and then decodes the data pointed to by "responseData", of length |
| * "responseDataLen", into a List of Certs, possibly empty, which is returned |
| * at "pCertList". |
| * |
| * PARAMETERS: |
| * "responseCode" |
| * The value of the HTTP response code. |
| * "responseContentType" |
| * The address of the Content-type string. Must be non-NULL. |
| * "responseData" |
| * The address of the message data. Must be non-NULL. |
| * "responseDataLen" |
| * The length of the message data. |
| * "pCertList" |
| * The address of the List that is created. 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_ProcessCertResponse( |
| PRUint16 responseCode, |
| const char *responseContentType, |
| const char *responseData, |
| PRUint32 responseDataLen, |
| PKIX_List **pCertList, |
| void *plContext) |
| { |
| callbackContext cbContext; |
| |
| PKIX_ENTER(HTTPCERTSTORECONTEXT, |
| "pkix_pl_HttpCertStore_ProcessCertResponse"); |
| |
| cbContext.error = NULL; |
| cbContext.plContext = plContext; |
| cbContext.pkixCertList = NULL; |
| |
| PKIX_NULLCHECK_ONE(pCertList); |
| |
| if (responseCode != 200) { |
| PKIX_ERROR(PKIX_BADHTTPRESPONSE); |
| } |
| |
| /* check that response type is application/pkcs7-mime */ |
| if (responseContentType == NULL) { |
| PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE); |
| } |
| |
| if (responseData == NULL) { |
| PKIX_ERROR(PKIX_NORESPONSEDATAINHTTPRESPONSE); |
| } |
| |
| PKIX_CHECK( |
| PKIX_List_Create(&cbContext.pkixCertList, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| PKIX_CHECK_ONLY_FATAL( |
| pkix_pl_HttpCertStore_DecodeCertPackage(responseData, |
| responseDataLen, |
| certCallback, |
| &cbContext, |
| plContext), |
| PKIX_HTTPCERTSTOREDECODECERTPACKAGEFAILED); |
| if (cbContext.error) { |
| /* Aborting on a fatal error(See certCallback fn) */ |
| pkixErrorResult = cbContext.error; |
| goto cleanup; |
| } |
| |
| *pCertList = cbContext.pkixCertList; |
| cbContext.pkixCertList = NULL; |
| |
| cleanup: |
| |
| PKIX_DECREF(cbContext.pkixCertList); |
| |
| PKIX_RETURN(HTTPCERTSTORECONTEXT); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStore_ProcessCrlResponse |
| * DESCRIPTION: |
| * |
| * This function verifies that the response code pointed to by "responseCode" |
| * and the content type pointed to by "responseContentType" are as expected, |
| * and then decodes the data pointed to by "responseData", of length |
| * "responseDataLen", into a List of Crls, possibly empty, which is returned |
| * at "pCrlList". |
| * |
| * PARAMETERS: |
| * "responseCode" |
| * The value of the HTTP response code. |
| * "responseContentType" |
| * The address of the Content-type string. Must be non-NULL. |
| * "responseData" |
| * The address of the message data. Must be non-NULL. |
| * "responseDataLen" |
| * The length of the message data. |
| * "pCrlList" |
| * The address of the List that is created. 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_ProcessCrlResponse( |
| PRUint16 responseCode, |
| const char *responseContentType, |
| const char *responseData, |
| PRUint32 responseDataLen, |
| PKIX_List **pCrlList, |
| void *plContext) |
| { |
| SECItem encodedResponse; |
| PRInt16 compareVal = 0; |
| PKIX_List *crls = NULL; |
| SECItem *derCrlCopy = NULL; |
| CERTSignedCrl *nssCrl = NULL; |
| PKIX_PL_CRL *crl = NULL; |
| |
| PKIX_ENTER(HTTPCERTSTORECONTEXT, |
| "pkix_pl_HttpCertStore_ProcessCrlResponse"); |
| PKIX_NULLCHECK_ONE(pCrlList); |
| |
| if (responseCode != 200) { |
| PKIX_ERROR(PKIX_BADHTTPRESPONSE); |
| } |
| |
| /* check that response type is application/pkix-crl */ |
| if (responseContentType == NULL) { |
| PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE); |
| } |
| |
| compareVal = PORT_Strcasecmp(responseContentType, |
| "application/pkix-crl"); |
| if (compareVal != 0) { |
| PKIX_ERROR(PKIX_CONTENTTYPENOTPKIXCRL); |
| } |
| encodedResponse.type = siBuffer; |
| encodedResponse.data = (void*)responseData; |
| encodedResponse.len = responseDataLen; |
| |
| derCrlCopy = SECITEM_DupItem(&encodedResponse); |
| if (!derCrlCopy) { |
| PKIX_ERROR(PKIX_ALLOCERROR); |
| } |
| /* crl will be based on derCrlCopy, but will not own the der. */ |
| nssCrl = |
| CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE, |
| CRL_DECODE_DONT_COPY_DER | |
| CRL_DECODE_SKIP_ENTRIES); |
| if (!nssCrl) { |
| PKIX_ERROR(PKIX_FAILEDTODECODECRL); |
| } |
| /* pkix crls own the der. */ |
| PKIX_CHECK( |
| pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy, NULL, |
| &crl, plContext), |
| PKIX_CRLCREATEWITHSIGNEDCRLFAILED); |
| /* Left control over memory pointed by derCrlCopy and |
| * nssCrl to pkix crl. */ |
| derCrlCopy = NULL; |
| nssCrl = NULL; |
| PKIX_CHECK(PKIX_List_Create(&crls, plContext), |
| PKIX_LISTCREATEFAILED); |
| PKIX_CHECK(PKIX_List_AppendItem |
| (crls, (PKIX_PL_Object *) crl, plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| *pCrlList = crls; |
| crls = NULL; |
| cleanup: |
| if (derCrlCopy) { |
| SECITEM_FreeItem(derCrlCopy, PR_TRUE); |
| } |
| if (nssCrl) { |
| SEC_DestroyCrl(nssCrl); |
| } |
| PKIX_DECREF(crl); |
| PKIX_DECREF(crls); |
| |
| PKIX_RETURN(HTTPCERTSTORECONTEXT); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStore_CreateRequestSession |
| * DESCRIPTION: |
| * |
| * This function takes elements from the HttpCertStoreContext pointed to by |
| * "context" (path, client, and serverSession) and creates a RequestSession. |
| * See the HTTPClient API described in ocspt.h for further details. |
| * |
| * PARAMETERS: |
| * "context" |
| * The address of the HttpCertStoreContext. 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_CreateRequestSession( |
| PKIX_PL_HttpCertStoreContext *context, |
| void *plContext) |
| { |
| const SEC_HttpClientFcnV1 *hcv1 = NULL; |
| SECStatus rv = SECFailure; |
| |
| PKIX_ENTER |
| (HTTPCERTSTORECONTEXT, |
| "pkix_pl_HttpCertStore_CreateRequestSession"); |
| PKIX_NULLCHECK_TWO(context, context->serverSession); |
| |
| if (context->client->version != 1) { |
| PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); |
| } |
| |
| hcv1 = &(context->client->fcnTable.ftable1); |
| if (context->requestSession != NULL) { |
| (*hcv1->freeFcn)(context->requestSession); |
| context->requestSession = 0; |
| } |
| |
| rv = (*hcv1->createFcn)(context->serverSession, "http", |
| context->path, "GET", |
| PR_SecondsToInterval( |
| ((PKIX_PL_NssContext*)plContext)->timeoutSeconds), |
| &(context->requestSession)); |
| |
| if (rv != SECSuccess) { |
| PKIX_ERROR(PKIX_HTTPSERVERERROR); |
| } |
| cleanup: |
| |
| PKIX_RETURN(HTTPCERTSTORECONTEXT); |
| |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStore_GetCert |
| * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h) |
| */ |
| PKIX_Error * |
| pkix_pl_HttpCertStore_GetCert( |
| PKIX_CertStore *store, |
| PKIX_CertSelector *selector, |
| PKIX_VerifyNode *verifyNode, |
| void **pNBIOContext, |
| PKIX_List **pCertList, |
| void *plContext) |
| { |
| const SEC_HttpClientFcnV1 *hcv1 = NULL; |
| PKIX_PL_HttpCertStoreContext *context = NULL; |
| void *nbioContext = NULL; |
| SECStatus rv = SECFailure; |
| PRUint16 responseCode = 0; |
| const char *responseContentType = NULL; |
| const char *responseData = NULL; |
| PRUint32 responseDataLen = 0; |
| PKIX_List *certList = NULL; |
| |
| PKIX_ENTER(HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStore_GetCert"); |
| PKIX_NULLCHECK_THREE(store, selector, pCertList); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| PKIX_CHECK(PKIX_CertStore_GetCertStoreContext |
| (store, (PKIX_PL_Object **)&context, plContext), |
| PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); |
| |
| if (context->client->version != 1) { |
| PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); |
| } |
| |
| hcv1 = &(context->client->fcnTable.ftable1); |
| |
| PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession |
| (context, plContext), |
| PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED); |
| |
| responseDataLen = |
| ((PKIX_PL_NssContext*)plContext)->maxResponseLength; |
| |
| rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, |
| (PRPollDesc **)&nbioContext, |
| &responseCode, |
| (const char **)&responseContentType, |
| NULL, /* &responseHeaders */ |
| (const char **)&responseData, |
| &responseDataLen); |
| if (rv != SECSuccess) { |
| PKIX_ERROR(PKIX_HTTPSERVERERROR); |
| } |
| |
| if (nbioContext != 0) { |
| *pNBIOContext = nbioContext; |
| goto cleanup; |
| } |
| |
| PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse |
| (responseCode, |
| responseContentType, |
| responseData, |
| responseDataLen, |
| &certList, |
| plContext), |
| PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); |
| |
| *pCertList = certList; |
| |
| cleanup: |
| PKIX_DECREF(context); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStore_GetCertContinue |
| * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h) |
| */ |
| PKIX_Error * |
| pkix_pl_HttpCertStore_GetCertContinue( |
| PKIX_CertStore *store, |
| PKIX_CertSelector *selector, |
| PKIX_VerifyNode *verifyNode, |
| void **pNBIOContext, |
| PKIX_List **pCertList, |
| void *plContext) |
| { |
| const SEC_HttpClientFcnV1 *hcv1 = NULL; |
| PKIX_PL_HttpCertStoreContext *context = NULL; |
| void *nbioContext = NULL; |
| SECStatus rv = SECFailure; |
| PRUint16 responseCode = 0; |
| const char *responseContentType = NULL; |
| const char *responseData = NULL; |
| PRUint32 responseDataLen = 0; |
| PKIX_List *certList = NULL; |
| |
| PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCertContinue"); |
| PKIX_NULLCHECK_THREE(store, selector, pCertList); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| PKIX_CHECK(PKIX_CertStore_GetCertStoreContext |
| (store, (PKIX_PL_Object **)&context, plContext), |
| PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); |
| |
| if (context->client->version != 1) { |
| PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); |
| } |
| |
| hcv1 = &(context->client->fcnTable.ftable1); |
| PKIX_NULLCHECK_ONE(context->requestSession); |
| |
| responseDataLen = |
| ((PKIX_PL_NssContext*)plContext)->maxResponseLength; |
| |
| rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, |
| (PRPollDesc **)&nbioContext, |
| &responseCode, |
| (const char **)&responseContentType, |
| NULL, /* &responseHeaders */ |
| (const char **)&responseData, |
| &responseDataLen); |
| |
| if (rv != SECSuccess) { |
| PKIX_ERROR(PKIX_HTTPSERVERERROR); |
| } |
| |
| if (nbioContext != 0) { |
| *pNBIOContext = nbioContext; |
| goto cleanup; |
| } |
| |
| PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse |
| (responseCode, |
| responseContentType, |
| responseData, |
| responseDataLen, |
| &certList, |
| plContext), |
| PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); |
| |
| *pCertList = certList; |
| |
| cleanup: |
| PKIX_DECREF(context); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStore_GetCRL |
| * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) |
| */ |
| PKIX_Error * |
| pkix_pl_HttpCertStore_GetCRL( |
| PKIX_CertStore *store, |
| PKIX_CRLSelector *selector, |
| void **pNBIOContext, |
| PKIX_List **pCrlList, |
| void *plContext) |
| { |
| |
| const SEC_HttpClientFcnV1 *hcv1 = NULL; |
| PKIX_PL_HttpCertStoreContext *context = NULL; |
| void *nbioContext = NULL; |
| SECStatus rv = SECFailure; |
| PRUint16 responseCode = 0; |
| const char *responseContentType = NULL; |
| const char *responseData = NULL; |
| PRUint32 responseDataLen = 0; |
| PKIX_List *crlList = NULL; |
| |
| PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRL"); |
| PKIX_NULLCHECK_THREE(store, selector, pCrlList); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| PKIX_CHECK(PKIX_CertStore_GetCertStoreContext |
| (store, (PKIX_PL_Object **)&context, plContext), |
| PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); |
| |
| if (context->client->version != 1) { |
| PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); |
| } |
| |
| hcv1 = &(context->client->fcnTable.ftable1); |
| PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession |
| (context, plContext), |
| PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED); |
| |
| responseDataLen = |
| ((PKIX_PL_NssContext*)plContext)->maxResponseLength; |
| |
| rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, |
| (PRPollDesc **)&nbioContext, |
| &responseCode, |
| (const char **)&responseContentType, |
| NULL, /* &responseHeaders */ |
| (const char **)&responseData, |
| &responseDataLen); |
| |
| if (rv != SECSuccess) { |
| PKIX_ERROR(PKIX_HTTPSERVERERROR); |
| } |
| |
| if (nbioContext != 0) { |
| *pNBIOContext = nbioContext; |
| goto cleanup; |
| } |
| |
| PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse |
| (responseCode, |
| responseContentType, |
| responseData, |
| responseDataLen, |
| &crlList, |
| plContext), |
| PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED); |
| |
| *pCrlList = crlList; |
| |
| cleanup: |
| PKIX_DECREF(context); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_HttpCertStore_GetCRLContinue |
| * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) |
| */ |
| PKIX_Error * |
| pkix_pl_HttpCertStore_GetCRLContinue( |
| PKIX_CertStore *store, |
| PKIX_CRLSelector *selector, |
| void **pNBIOContext, |
| PKIX_List **pCrlList, |
| void *plContext) |
| { |
| const SEC_HttpClientFcnV1 *hcv1 = NULL; |
| PKIX_PL_HttpCertStoreContext *context = NULL; |
| void *nbioContext = NULL; |
| SECStatus rv = SECFailure; |
| PRUint16 responseCode = 0; |
| const char *responseContentType = NULL; |
| const char *responseData = NULL; |
| PRUint32 responseDataLen = 0; |
| PKIX_List *crlList = NULL; |
| |
| PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRLContinue"); |
| PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| PKIX_CHECK(PKIX_CertStore_GetCertStoreContext |
| (store, (PKIX_PL_Object **)&context, plContext), |
| PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); |
| |
| if (context->client->version != 1) { |
| PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); |
| } |
| hcv1 = &(context->client->fcnTable.ftable1); |
| |
| PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession |
| (context, plContext), |
| PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED); |
| |
| responseDataLen = |
| ((PKIX_PL_NssContext*)plContext)->maxResponseLength; |
| |
| rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, |
| (PRPollDesc **)&nbioContext, |
| &responseCode, |
| (const char **)&responseContentType, |
| NULL, /* &responseHeaders */ |
| (const char **)&responseData, |
| &responseDataLen); |
| |
| if (rv != SECSuccess) { |
| PKIX_ERROR(PKIX_HTTPSERVERERROR); |
| } |
| |
| if (nbioContext != 0) { |
| *pNBIOContext = nbioContext; |
| goto cleanup; |
| } |
| |
| PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse |
| (responseCode, |
| responseContentType, |
| responseData, |
| responseDataLen, |
| &crlList, |
| plContext), |
| PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED); |
| |
| *pCrlList = crlList; |
| |
| cleanup: |
| PKIX_DECREF(context); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |
| /* --Public-HttpCertStore-Functions----------------------------------- */ |
| |
| /* |
| * 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); |
| } |
| |
| /* |
| * FUNCTION: PKIX_PL_HttpCertStore_Create |
| * (see comments in pkix_samples_modules.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_HttpCertStore_Create( |
| PKIX_PL_HttpClient *client, |
| PKIX_PL_GeneralName *location, |
| PKIX_CertStore **pCertStore, |
| void *plContext) |
| { |
| PKIX_PL_String *locationString = NULL; |
| char *locationAscii = NULL; |
| PKIX_UInt32 len = 0; |
| |
| PKIX_ENTER(CERTSTORE, "PKIX_PL_HttpCertStore_Create"); |
| PKIX_NULLCHECK_TWO(location, pCertStore); |
| |
| PKIX_TOSTRING(location, &locationString, plContext, |
| PKIX_GENERALNAMETOSTRINGFAILED); |
| |
| PKIX_CHECK(PKIX_PL_String_GetEncoded |
| (locationString, |
| PKIX_ESCASCII, |
| (void **)&locationAscii, |
| &len, |
| plContext), |
| PKIX_STRINGGETENCODEDFAILED); |
| |
| PKIX_CHECK(pkix_pl_HttpCertStore_CreateWithAsciiName |
| (client, locationAscii, pCertStore, plContext), |
| PKIX_HTTPCERTSTORECREATEWITHASCIINAMEFAILED); |
| |
| cleanup: |
| |
| PKIX_DECREF(locationString); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |
| /* |
| * FUNCTION: pkix_HttpCertStore_FindSocketConnection |
| * DESCRIPTION: |
| * |
| PRIntervalTime timeout, |
| char *hostname, |
| PRUint16 portnum, |
| PRErrorCode *pStatus, |
| PKIX_PL_Socket **pSocket, |
| |
| * This function checks for an existing socket, creating a new one if unable |
| * to find an existing one, for the host pointed to by "hostname" and the port |
| * pointed to by "portnum". If a new socket is created the PRIntervalTime in |
| * "timeout" will be used for the timeout value and a creation status is |
| * returned at "pStatus". The address of the socket is stored at "pSocket". |
| * |
| * PARAMETERS: |
| * "timeout" |
| * The PRIntervalTime of the timeout value. |
| * "hostname" |
| * The address of the string containing the hostname. Must be non-NULL. |
| * "portnum" |
| * The port number for the desired socket. |
| * "pStatus" |
| * The address at which the status is stored. Must be non-NULL. |
| * "pSocket" |
| * The address at which the socket 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_HttpCertStore_FindSocketConnection( |
| PRIntervalTime timeout, |
| char *hostname, |
| PRUint16 portnum, |
| PRErrorCode *pStatus, |
| PKIX_PL_Socket **pSocket, |
| void *plContext) |
| { |
| PKIX_PL_String *formatString = NULL; |
| PKIX_PL_String *hostString = NULL; |
| PKIX_PL_String *domainString = NULL; |
| PKIX_PL_Socket *socket = NULL; |
| |
| PKIX_ENTER(CERTSTORE, "pkix_HttpCertStore_FindSocketConnection"); |
| PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket); |
| |
| *pStatus = 0; |
| |
| /* create PKIX_PL_String from hostname and port */ |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, "%s:%d", 0, &formatString, plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| #if 0 |
| hostname = "variation.red.iplanet.com"; |
| portnum = 2001; |
| #endif |
| |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, hostname, 0, &hostString, plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Sprintf |
| (&domainString, plContext, formatString, hostString, portnum), |
| PKIX_STRINGCREATEFAILED); |
| |
| #ifdef PKIX_SOCKETCACHE |
| /* Is this domainName already in cache? */ |
| PKIX_CHECK(PKIX_PL_HashTable_Lookup |
| (httpSocketCache, |
| (PKIX_PL_Object *)domainString, |
| (PKIX_PL_Object **)&socket, |
| plContext), |
| PKIX_HASHTABLELOOKUPFAILED); |
| #endif |
| if (socket == NULL) { |
| |
| /* No, create a connection (and cache it) */ |
| PKIX_CHECK(pkix_pl_Socket_CreateByHostAndPort |
| (PKIX_FALSE, /* create a client, not a server */ |
| timeout, |
| hostname, |
| portnum, |
| pStatus, |
| &socket, |
| plContext), |
| PKIX_SOCKETCREATEBYHOSTANDPORTFAILED); |
| |
| #ifdef PKIX_SOCKETCACHE |
| PKIX_CHECK(PKIX_PL_HashTable_Add |
| (httpSocketCache, |
| (PKIX_PL_Object *)domainString, |
| (PKIX_PL_Object *)socket, |
| plContext), |
| PKIX_HASHTABLEADDFAILED); |
| #endif |
| } |
| |
| *pSocket = socket; |
| socket = NULL; |
| |
| cleanup: |
| |
| PKIX_DECREF(formatString); |
| PKIX_DECREF(hostString); |
| PKIX_DECREF(domainString); |
| PKIX_DECREF(socket); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |