summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c')
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c1147
1 files changed, 1147 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c
new file mode 100755
index 000000000..471f92004
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c
@@ -0,0 +1,1147 @@
+/* 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);
+}
+