summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/libpkix/pkix_pl_nss/module
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss/module')
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/Makefile66
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp36
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn34
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp41
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c699
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h65
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c1292
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h34
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c1147
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h62
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c1654
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h139
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c1113
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h75
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c2494
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h82
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c757
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h86
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c786
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h96
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h314
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c417
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c389
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h61
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c1039
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h31
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c1695
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h209
28 files changed, 14913 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile
new file mode 100644
index 0000000000..e97ad8e4de
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile
@@ -0,0 +1,66 @@
+#! gmake
+#
+# 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/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+ifdef NSS_PKIX_NO_LDAP
+LDAP_HEADERS =
+LDAP_CSRCS =
+else
+LDAP_HEADERS = \
+ pkix_pl_ldapt.h \
+ pkix_pl_ldapcertstore.h \
+ pkix_pl_ldapresponse.h \
+ pkix_pl_ldaprequest.h \
+ pkix_pl_ldapdefaultclient.h \
+ $(NULL)
+
+LDAP_CSRCS = \
+ pkix_pl_ldaptemplates.c \
+ pkix_pl_ldapcertstore.c \
+ pkix_pl_ldapresponse.c \
+ pkix_pl_ldaprequest.c \
+ pkix_pl_ldapdefaultclient.c \
+ $(NULL)
+endif
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp
new file mode 100644
index 0000000000..064a17ce44
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp
@@ -0,0 +1,36 @@
+# 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/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_libpkix_pkix_pl_nss_module_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'pkix_pl_aiamgr.h',
+ 'pkix_pl_colcertstore.h',
+ 'pkix_pl_httpcertstore.h',
+ 'pkix_pl_httpdefaultclient.h',
+ 'pkix_pl_ldapcertstore.h',
+ 'pkix_pl_ldapdefaultclient.h',
+ 'pkix_pl_ldaprequest.h',
+ 'pkix_pl_ldapresponse.h',
+ 'pkix_pl_ldapt.h',
+ 'pkix_pl_nsscontext.h',
+ 'pkix_pl_pk11certstore.h',
+ 'pkix_pl_socket.h'
+ ],
+ 'destination': '<(nss_private_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn
new file mode 100644
index 0000000000..31231e4edf
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn
@@ -0,0 +1,34 @@
+#
+# 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/.
+CORE_DEPTH = ../../../..
+
+PRIVATE_EXPORTS = \
+ pkix_pl_aiamgr.h \
+ pkix_pl_colcertstore.h \
+ pkix_pl_httpcertstore.h \
+ pkix_pl_httpdefaultclient.h \
+ $(LDAP_HEADERS) \
+ pkix_pl_nsscontext.h \
+ pkix_pl_pk11certstore.h \
+ pkix_pl_socket.h \
+ $(NULL)
+
+MODULE = nss
+
+DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DSHLIB_VERSION=\"$(LIBRARY_VERSION)\"
+
+CSRCS = \
+ pkix_pl_aiamgr.c \
+ pkix_pl_colcertstore.c \
+ pkix_pl_httpcertstore.c \
+ pkix_pl_httpdefaultclient.c \
+ $(LDAP_CSRCS) \
+ pkix_pl_nsscontext.c \
+ pkix_pl_pk11certstore.c \
+ pkix_pl_socket.c \
+ $(NULL)
+
+LIBRARY_NAME = pkixmodule
+SHARED_LIBRARY = $(NULL)
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp b/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp
new file mode 100644
index 0000000000..8d7459ded6
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp
@@ -0,0 +1,41 @@
+# 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/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pkixmodule',
+ 'type': 'static_library',
+ 'sources': [
+ 'pkix_pl_aiamgr.c',
+ 'pkix_pl_colcertstore.c',
+ 'pkix_pl_httpcertstore.c',
+ 'pkix_pl_httpdefaultclient.c',
+ 'pkix_pl_ldapcertstore.c',
+ 'pkix_pl_ldapdefaultclient.c',
+ 'pkix_pl_ldaprequest.c',
+ 'pkix_pl_ldapresponse.c',
+ 'pkix_pl_ldaptemplates.c',
+ 'pkix_pl_nsscontext.c',
+ 'pkix_pl_pk11certstore.c',
+ 'pkix_pl_socket.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'target_defaults': {
+ 'defines': [
+ 'SHLIB_SUFFIX=\"<(dll_suffix)\"',
+ 'SHLIB_PREFIX=\"<(dll_prefix)\"',
+ 'SHLIB_VERSION=\"\"'
+ ]
+ },
+ 'variables': {
+ 'module': 'nss'
+ }
+} \ No newline at end of file
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c
new file mode 100644
index 0000000000..d9f5662303
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c
@@ -0,0 +1,699 @@
+/* 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_aiamgr.c
+ *
+ * AIAMgr Object Definitions
+ *
+ */
+
+#include "pkix_pl_aiamgr.h"
+extern PKIX_PL_HashTable *aiaConnectionCache;
+
+#ifndef NSS_PKIX_NO_LDAP
+/* --Virtual-LdapClient-Functions------------------------------------ */
+
+PKIX_Error *
+PKIX_PL_LdapClient_InitiateRequest(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_InitiateRequest");
+ PKIX_NULLCHECK_TWO(client, client->initiateFcn);
+
+ PKIX_CHECK(client->initiateFcn
+ (client, requestParams, pNBIO, pResponse, plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+cleanup:
+
+ PKIX_RETURN(LDAPCLIENT);
+
+}
+
+PKIX_Error *
+PKIX_PL_LdapClient_ResumeRequest(
+ PKIX_PL_LdapClient *client,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_ResumeRequest");
+ PKIX_NULLCHECK_TWO(client, client->resumeFcn);
+
+ PKIX_CHECK(client->resumeFcn
+ (client, pNBIO, pResponse, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+cleanup:
+
+ PKIX_RETURN(LDAPCLIENT);
+
+}
+#endif /* !NSS_PKIX_NO_LDAP */
+
+/* --Private-AIAMgr-Functions----------------------------------*/
+
+/*
+ * FUNCTION: pkix_pl_AIAMgr_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
+ */
+static PKIX_Error *
+pkix_pl_AIAMgr_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_AIAMgr *aiaMgr = NULL;
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_AIAMGR_TYPE, plContext),
+ PKIX_OBJECTNOTAIAMGR);
+
+ aiaMgr = (PKIX_PL_AIAMgr *)object;
+
+ /* pointer to cert cache */
+ /* pointer to crl cache */
+ aiaMgr->method = 0;
+ aiaMgr->aiaIndex = 0;
+ aiaMgr->numAias = 0;
+ PKIX_DECREF(aiaMgr->aia);
+ PKIX_DECREF(aiaMgr->location);
+ PKIX_DECREF(aiaMgr->results);
+#ifndef NSS_PKIX_NO_LDAP
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+#endif
+
+cleanup:
+
+ PKIX_RETURN(AIAMGR);
+}
+
+/*
+ * FUNCTION: pkix_pl_AIAMgr_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_AIAMGR_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_AIAMgr_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry = &systemClasses[PKIX_AIAMGR_TYPE];
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_RegisterSelf");
+
+ entry->description = "AIAMgr";
+ entry->typeObjectSize = sizeof(PKIX_PL_AIAMgr);
+ entry->destructor = pkix_pl_AIAMgr_Destroy;
+
+ PKIX_RETURN(AIAMGR);
+}
+
+#ifndef NSS_PKIX_NO_LDAP
+/*
+ * FUNCTION: pkix_pl_AiaMgr_FindLDAPClient
+ * DESCRIPTION:
+ *
+ * This function checks the collection of LDAPClient connections held by the
+ * AIAMgr pointed to by "aiaMgr" for one matching the domain name given by
+ * "domainName". The string may include a port number: e.g., "betty.nist.gov"
+ * or "nss.red.iplanet.com:1389". If a match is found, that LDAPClient is
+ * stored at "pClient". Otherwise, an LDAPClient is created and added to the
+ * collection, and then stored at "pClient".
+ *
+ * PARAMETERS:
+ * "aiaMgr"
+ * The AIAMgr whose LDAPClient connected are to be managed. Must be
+ * non-NULL.
+ * "domainName"
+ * Address of a string pointing to a server name. Must be non-NULL.
+ * An empty string (which means no <host> is given in the LDAP URL) is
+ * not supported.
+ * "pClient"
+ * Address at which the returned LDAPClient 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 AIAMgr Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_AiaMgr_FindLDAPClient(
+ PKIX_PL_AIAMgr *aiaMgr,
+ char *domainName,
+ PKIX_PL_LdapClient **pClient,
+ void *plContext)
+{
+ PKIX_PL_String *domainString = NULL;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AiaMgr_FindLDAPClient");
+ PKIX_NULLCHECK_THREE(aiaMgr, domainName, pClient);
+
+ /*
+ * An LDAP URL may not have a <host> part, for example,
+ * ldap:///o=University%20of%20Michigan,c=US
+ * PKIX_PL_LdapDefaultClient doesn't know how to discover the default
+ * LDAP server, so we don't support this kind of LDAP URL.
+ */
+ if (*domainName == '\0') {
+ /* Simulate a PKIX_PL_LdapDefaultClient_CreateByName failure. */
+ PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
+ }
+
+ /* create PKIX_PL_String from domain name */
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, domainName, 0, &domainString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ /* Is this domainName already in cache? */
+ PKIX_CHECK(PKIX_PL_HashTable_Lookup
+ (aiaConnectionCache,
+ (PKIX_PL_Object *)domainString,
+ (PKIX_PL_Object **)&client,
+ plContext),
+ PKIX_HASHTABLELOOKUPFAILED);
+
+ if (client == NULL) {
+
+ /* No, create a connection (and cache it) */
+ PKIX_CHECK(PKIX_PL_LdapDefaultClient_CreateByName
+ (domainName,
+ /* Do not use NBIO until we verify, that
+ * it is working. For now use 1 min timeout. */
+ PR_SecondsToInterval(
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
+ NULL,
+ &client,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
+
+ PKIX_CHECK(PKIX_PL_HashTable_Add
+ (aiaConnectionCache,
+ (PKIX_PL_Object *)domainString,
+ (PKIX_PL_Object *)client,
+ plContext),
+ PKIX_HASHTABLEADDFAILED);
+
+ }
+
+ *pClient = (PKIX_PL_LdapClient *)client;
+
+cleanup:
+
+ PKIX_DECREF(domainString);
+
+ PKIX_RETURN(AIAMGR);
+}
+#endif /* !NSS_PKIX_NO_LDAP */
+
+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) {
+ 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);
+}
+
+#ifndef NSS_PKIX_NO_LDAP
+PKIX_Error *
+pkix_pl_AIAMgr_GetLDAPCerts(
+ PKIX_PL_AIAMgr *aiaMgr,
+ PKIX_PL_InfoAccess *ia,
+ void **pNBIOContext,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_List *result = NULL;
+ PKIX_PL_GeneralName *location = NULL;
+ PKIX_PL_LdapClient *client = NULL;
+ LDAPRequestParams request;
+ PLArenaPool *arena = NULL;
+ char *domainName = NULL;
+ void *nbio = NULL;
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts");
+ PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);
+
+ nbio = *pNBIOContext;
+ *pNBIOContext = NULL;
+ *pCerts = NULL;
+
+ if (nbio == NULL) { /* a new request */
+
+ /* Initiate an LDAP request */
+
+ request.scope = WHOLE_SUBTREE;
+ request.derefAliases = NEVER_DEREF;
+ request.sizeLimit = 0;
+ request.timeLimit = 0;
+
+ PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
+ (ia, &location, plContext),
+ PKIX_INFOACCESSGETLOCATIONFAILED);
+
+ /*
+ * Get a short-lived arena. We'll be done with
+ * this space once the request is encoded.
+ */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation
+ (location, arena, &request, &domainName, plContext),
+ PKIX_INFOACCESSPARSELOCATIONFAILED);
+
+ PKIX_DECREF(location);
+
+ /* Find or create a connection to LDAP server */
+ PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient
+ (aiaMgr, domainName, &client, plContext),
+ PKIX_AIAMGRFINDLDAPCLIENTFAILED);
+
+ aiaMgr->client.ldapClient = client;
+
+ PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
+ (aiaMgr->client.ldapClient,
+ &request,
+ &nbio,
+ &result,
+ plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+
+ PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
+
+ } else {
+
+ PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
+ (aiaMgr->client.ldapClient, &nbio, &result, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+
+ }
+
+ if (nbio != NULL) { /* WOULDBLOCK */
+ *pNBIOContext = nbio;
+ *pCerts = NULL;
+ goto cleanup;
+ }
+
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+
+ if (result == NULL) {
+ *pCerts = NULL;
+ } else {
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (result, pCerts, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+ }
+
+ *pNBIOContext = nbio;
+
+cleanup:
+
+ if (arena && (PKIX_ERROR_RECEIVED)) {
+ PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
+ }
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+ }
+
+ PKIX_DECREF(location);
+
+ PKIX_RETURN(AIAMGR);
+}
+#endif /* !NSS_PKIX_NO_LDAP */
+
+/*
+ * FUNCTION: PKIX_PL_AIAMgr_Create
+ * DESCRIPTION:
+ *
+ * This function creates an AIAMgr, storing the result at "pAIAMgr".
+ *
+ * PARAMETERS:
+ * "pAIAMGR"
+ * Address at which the returned AIAMgr 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 AIAMgr 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_AIAMgr_Create(
+ PKIX_PL_AIAMgr **pAIAMgr,
+ void *plContext)
+{
+ PKIX_PL_AIAMgr *aiaMgr = NULL;
+
+ PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_Create");
+ PKIX_NULLCHECK_ONE(pAIAMgr);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_AIAMGR_TYPE,
+ sizeof(PKIX_PL_AIAMgr),
+ (PKIX_PL_Object **)&aiaMgr,
+ plContext),
+ PKIX_COULDNOTCREATEAIAMGROBJECT);
+ /* pointer to cert cache */
+ /* pointer to crl cache */
+ aiaMgr->method = 0;
+ aiaMgr->aiaIndex = 0;
+ aiaMgr->numAias = 0;
+ aiaMgr->aia = NULL;
+ aiaMgr->location = NULL;
+ aiaMgr->results = NULL;
+ aiaMgr->client.hdata.httpClient = NULL;
+ aiaMgr->client.hdata.serverSession = NULL;
+ aiaMgr->client.hdata.requestSession = NULL;
+
+ *pAIAMgr = aiaMgr;
+
+cleanup:
+
+ PKIX_RETURN(AIAMGR);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_AIAMgr_GetAIACerts(
+ PKIX_PL_AIAMgr *aiaMgr,
+ PKIX_PL_Cert *prevCert,
+ void **pNBIOContext,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_UInt32 numAias = 0;
+ PKIX_UInt32 aiaIndex = 0;
+ PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN;
+ PKIX_List *certs = NULL;
+ PKIX_PL_InfoAccess *ia = NULL;
+ void *nbio = NULL;
+
+ PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts");
+ PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts);
+
+ nbio = *pNBIOContext;
+ *pCerts = NULL;
+ *pNBIOContext = NULL;
+
+ if (nbio == NULL) { /* a new request */
+
+ /* Does this Cert have an AIA extension? */
+ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
+ (prevCert, &aiaMgr->aia, plContext),
+ PKIX_CERTGETAUTHORITYINFOACCESSFAILED);
+
+ if (aiaMgr->aia != NULL) {
+ PKIX_CHECK(PKIX_List_GetLength
+ (aiaMgr->aia, &numAias, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+ }
+
+ /* And if so, does it have any entries? */
+ if ((aiaMgr->aia == NULL) || (numAias == 0)) {
+ *pCerts = NULL;
+ goto cleanup;
+ }
+
+ aiaMgr->aiaIndex = 0;
+ aiaMgr->numAias = numAias;
+ aiaMgr->results = NULL;
+
+ }
+
+ for (aiaIndex = aiaMgr->aiaIndex;
+ aiaIndex < aiaMgr->numAias;
+ aiaIndex ++) {
+ PKIX_UInt32 method = 0;
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (aiaMgr->aia,
+ aiaIndex,
+ (PKIX_PL_Object **)&ia,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod
+ (ia, &method, plContext),
+ PKIX_INFOACCESSGETMETHODFAILED);
+
+ if (method != PKIX_INFOACCESS_CA_ISSUERS &&
+ method != PKIX_INFOACCESS_CA_REPOSITORY) {
+ PKIX_DECREF(ia);
+ continue;
+ }
+
+ PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType
+ (ia, &iaType, plContext),
+ PKIX_INFOACCESSGETLOCATIONTYPEFAILED);
+
+ if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) {
+ PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts
+ (aiaMgr, ia, &nbio, &certs, plContext),
+ PKIX_AIAMGRGETHTTPCERTSFAILED);
+#ifndef NSS_PKIX_NO_LDAP
+ } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) {
+ PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts
+ (aiaMgr, ia, &nbio, &certs, plContext),
+ PKIX_AIAMGRGETLDAPCERTSFAILED);
+#endif
+ } else {
+ /* We only support http and ldap requests. */
+ PKIX_DECREF(ia);
+ continue;
+ }
+
+ if (nbio != NULL) { /* WOULDBLOCK */
+ aiaMgr->aiaIndex = aiaIndex;
+ *pNBIOContext = nbio;
+ *pCerts = NULL;
+ goto cleanup;
+ }
+
+ /*
+ * We can't just use and modify the List we received.
+ * Because it's cached, it's set immutable.
+ */
+ if (aiaMgr->results == NULL) {
+ PKIX_CHECK(PKIX_List_Create
+ (&(aiaMgr->results), plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+ PKIX_CHECK(pkix_List_AppendList
+ (aiaMgr->results, certs, plContext),
+ PKIX_APPENDLISTFAILED);
+ PKIX_DECREF(certs);
+
+ PKIX_DECREF(ia);
+ }
+
+ PKIX_DECREF(aiaMgr->aia);
+
+ *pNBIOContext = NULL;
+ *pCerts = aiaMgr->results;
+ aiaMgr->results = NULL;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(aiaMgr->aia);
+ PKIX_DECREF(aiaMgr->results);
+#ifndef NSS_PKIX_NO_LDAP
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+#endif
+ }
+
+ PKIX_DECREF(certs);
+ PKIX_DECREF(ia);
+
+ PKIX_RETURN(AIAMGR);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h
new file mode 100644
index 0000000000..356c1ecdf2
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h
@@ -0,0 +1,65 @@
+/* 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_aiamgr.h
+ *
+ * AIAMgr Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_AIAMGR_H
+#define _PKIX_PL_AIAMGR_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_AIAMgrStruct {
+ /* pointer to cert cache */
+ /* pointer to crl cache */
+ PKIX_UInt32 method;
+ PKIX_UInt32 aiaIndex;
+ PKIX_UInt32 numAias;
+ PKIX_List *aia;
+ PKIX_PL_GeneralName *location;
+ PKIX_List *results;
+ union {
+#ifndef NSS_PKIX_NO_LDAP
+ PKIX_PL_LdapClient *ldapClient;
+#endif
+ struct {
+ const SEC_HttpClientFcn *httpClient;
+ SEC_HTTP_SERVER_SESSION serverSession;
+ SEC_HTTP_REQUEST_SESSION requestSession;
+ char *path;
+ } hdata;
+ } client;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_AIAMgr_RegisterSelf(void *plContext);
+
+#ifndef NSS_PKIX_NO_LDAP
+PKIX_Error *PKIX_PL_LdapClient_InitiateRequest(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+
+PKIX_Error *PKIX_PL_LdapClient_ResumeRequest(
+ PKIX_PL_LdapClient *client,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+#endif /* !NSS_PKIX_NO_LDAP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_AIAMGR_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c
new file mode 100644
index 0000000000..4cc5607cf6
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c
@@ -0,0 +1,1292 @@
+/* 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_colcertstore.c
+ *
+ * CollectionCertStore Function Definitions
+ *
+ */
+
+#include "pkix_pl_colcertstore.h"
+
+/*
+ * This Object is going to be taken out from libpkix SOON. The following
+ * function is copied from nss/cmd library, but not supported by NSS as
+ * public API. We use it since ColCertStore are read in Cert/Crl from
+ * files and need this support.
+ */
+
+static SECStatus
+SECU_FileToItem(SECItem *dst, PRFileDesc *src)
+{
+ PRFileInfo info;
+ PRInt32 numBytes;
+ PRStatus prStatus;
+
+ prStatus = PR_GetOpenFileInfo(src, &info);
+
+ if (prStatus != PR_SUCCESS) {
+ PORT_SetError(SEC_ERROR_IO);
+ return SECFailure;
+ }
+
+ /* XXX workaround for 3.1, not all utils zero dst before sending */
+ dst->data = 0;
+ if (!SECITEM_AllocItem(NULL, dst, info.size))
+ goto loser;
+
+ numBytes = PR_Read(src, dst->data, info.size);
+ if (numBytes != info.size) {
+ PORT_SetError(SEC_ERROR_IO);
+ goto loser;
+ }
+
+ return SECSuccess;
+loser:
+ SECITEM_FreeItem(dst, PR_FALSE);
+ return SECFailure;
+}
+
+static SECStatus
+SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
+{
+ SECStatus rv;
+ if (ascii) {
+ /* First convert ascii to binary */
+ SECItem filedata;
+
+ /* Read in ascii data */
+ rv = SECU_FileToItem(&filedata, inFile);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if (!filedata.data) {
+ fprintf(stderr, "unable to read data from input file\n");
+ return SECFailure;
+ }
+ /* need one additional byte for zero terminator */
+ rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len + 1);
+ if (rv != SECSuccess) {
+ PORT_Free(filedata.data);
+ return rv;
+ }
+ char *asc = (char *)filedata.data;
+ asc[filedata.len - 1] = '\0';
+
+ char *body;
+ /* check for headers and trailers and remove them */
+ if ((body = strstr(asc, "-----BEGIN")) != NULL) {
+ char *trailer = NULL;
+ asc = body;
+ body = PORT_Strchr(body, '\n');
+ if (!body)
+ body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
+ if (body)
+ trailer = strstr(++body, "-----END");
+ if (trailer != NULL) {
+ *trailer = '\0';
+ } else {
+ fprintf(stderr, "input has header but no trailer\n");
+ PORT_Free(filedata.data);
+ return SECFailure;
+ }
+ } else {
+ body = asc;
+ }
+
+ /* Convert to binary */
+ rv = ATOB_ConvertAsciiToItem(der, body);
+ if (rv) {
+ return SECFailure;
+ }
+
+ PORT_Free(filedata.data);
+ } else {
+ /* Read in binary der */
+ rv = SECU_FileToItem(der, inFile);
+ if (rv) {
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+}
+
+/*
+ * FUNCTION: PKIX_PL_CollectionCertStoreContext_Create
+ * DESCRIPTION:
+ *
+ * Creates a new CollectionCertStoreContext using the String pointed to
+ * by "storeDir" and stores it at "pColCertStoreContext".
+ *
+ * PARAMETERS:
+ * "storeDir"
+ * The absolute path where *.crl and *.crt files are located.
+ * "pColCertStoreContext"
+ * Address where object pointer will be 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 CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Create(
+ PKIX_PL_String *storeDir,
+ PKIX_PL_CollectionCertStoreContext **pColCertStoreContext,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Create");
+ PKIX_NULLCHECK_TWO(storeDir, pColCertStoreContext);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_COLLECTIONCERTSTORECONTEXT_TYPE,
+ sizeof (PKIX_PL_CollectionCertStoreContext),
+ (PKIX_PL_Object **)&colCertStoreContext,
+ plContext),
+ PKIX_COULDNOTCREATECOLLECTIONCERTSTORECONTEXTOBJECT);
+
+ PKIX_INCREF(storeDir);
+ colCertStoreContext->storeDir = storeDir;
+
+ colCertStoreContext->crlList = NULL;
+ colCertStoreContext->certList = NULL;
+
+ *pColCertStoreContext = colCertStoreContext;
+ colCertStoreContext = NULL;
+
+cleanup:
+
+ PKIX_DECREF(colCertStoreContext);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_COLLECTIONCERTSTORECONTEXT_TYPE, plContext),
+ PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT);
+
+ colCertStoreContext = (PKIX_PL_CollectionCertStoreContext *)object;
+
+ PKIX_DECREF(colCertStoreContext->storeDir);
+ PKIX_DECREF(colCertStoreContext->crlList);
+ PKIX_DECREF(colCertStoreContext->certList);
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *collectionCSContext = NULL;
+ PKIX_UInt32 tempHash = 0;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object,
+ PKIX_COLLECTIONCERTSTORECONTEXT_TYPE,
+ plContext),
+ PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT);
+
+ collectionCSContext = (PKIX_PL_CollectionCertStoreContext *)object;
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode
+ ((PKIX_PL_Object *) collectionCSContext->storeDir,
+ &tempHash,
+ plContext),
+ PKIX_STRINGHASHCODEFAILED);
+
+ *pHashcode = tempHash << 7;
+
+ /* should not hash on crlList and certList, values are dynamic */
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *firstCCSContext = NULL;
+ PKIX_PL_CollectionCertStoreContext *secondCCSContext = NULL;
+ PKIX_Boolean cmpResult = 0;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject,
+ secondObject,
+ PKIX_COLLECTIONCERTSTORECONTEXT_TYPE,
+ plContext),
+ PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT);
+
+ firstCCSContext = (PKIX_PL_CollectionCertStoreContext *)firstObject;
+ secondCCSContext = (PKIX_PL_CollectionCertStoreContext *)secondObject;
+
+ if (firstCCSContext->storeDir == secondCCSContext->storeDir) {
+
+ cmpResult = PKIX_TRUE;
+
+ } else {
+
+ PKIX_CHECK(PKIX_PL_Object_Equals
+ ((PKIX_PL_Object *) firstCCSContext->storeDir,
+ (PKIX_PL_Object *) secondCCSContext->storeDir,
+ &cmpResult,
+ plContext),
+ PKIX_STRINGEQUALSFAILED);
+ }
+
+ *pResult = cmpResult;
+
+ /* should not check equal on crlList and certList, data are dynamic */
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStore_CheckTrust
+ * DESCRIPTION:
+ * This function checks the trust status of this "cert" that was retrieved
+ * from the CertStore "store" and returns its trust status at "pTrusted".
+ *
+ * PARAMETERS:
+ * "store"
+ * Address of the CertStore. Must be non-NULL.
+ * "cert"
+ * Address of the Cert. Must be non-NULL.
+ * "pTrusted"
+ * Address of PKIX_Boolean where the "cert" trust status is returned.
+ * 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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStore_CheckTrust(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_CheckTrust");
+ PKIX_NULLCHECK_THREE(store, cert, pTrusted);
+
+ *pTrusted = PKIX_TRUE;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_CreateCert
+ * DESCRIPTION:
+ *
+ * Creates Cert using data file path name pointed to by "certFileName" and
+ * stores it at "pCert". If the Cert can not be decoded, NULL is stored
+ * at "pCert".
+ *
+ * PARAMETERS
+ * "certFileName" - Address of Cert data file path name. Must be non-NULL.
+ * "pCert" - Address where object pointer will be 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 CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_CreateCert(
+ const char *certFileName,
+ PKIX_PL_Cert **pCert,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *byteArray = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ PRFileDesc *inFile = NULL;
+ SECItem certDER;
+ void *buf = NULL;
+ PKIX_UInt32 len;
+ SECStatus rv;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_CreateCert");
+ PKIX_NULLCHECK_TWO(certFileName, pCert);
+
+ *pCert = NULL;
+ certDER.data = NULL;
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_Open.\n");
+ inFile = PR_Open(certFileName, PR_RDONLY, 0);
+
+ if (!inFile){
+ PKIX_ERROR(PKIX_UNABLETOOPENCERTFILE);
+ } else {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECU_ReadDerFromFile.\n");
+ rv = SECU_ReadDERFromFile(&certDER, inFile, PR_FALSE);
+ if (!rv){
+ buf = (void *)certDER.data;
+ len = certDER.len;
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (buf, len, &byteArray, plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_Create
+ (byteArray, &cert, plContext),
+ PKIX_CERTCREATEFAILED);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem.\n");
+ SECITEM_FreeItem(&certDER, PR_FALSE);
+
+ } else {
+ PKIX_ERROR(PKIX_UNABLETOREADDERFROMCERTFILE);
+ }
+ }
+
+ *pCert = cert;
+
+cleanup:
+ if (inFile){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_Close(inFile);
+ }
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&certDER, PR_FALSE);
+
+ PKIX_DECREF(cert);
+ }
+ PKIX_DECREF(byteArray);
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_CreateCRL
+ * DESCRIPTION:
+ *
+ * Creates CRL using data file path name pointed to by "crlFileName" and
+ * stores it at "pCrl". If the CRL can not be decoded, NULL is stored
+ * at "pCrl".
+ *
+ * PARAMETERS
+ * "crlFileName" - Address of CRL data file path name. Must be non-NULL.
+ * "pCrl" - Address where object pointer will be 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 CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_CreateCRL(
+ const char *crlFileName,
+ PKIX_PL_CRL **pCrl,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *byteArray = NULL;
+ PKIX_PL_CRL *crl = NULL;
+ PRFileDesc *inFile = NULL;
+ SECItem crlDER;
+ void *buf = NULL;
+ PKIX_UInt32 len;
+ SECStatus rv;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_CreateCRL");
+ PKIX_NULLCHECK_TWO(crlFileName, pCrl);
+
+ *pCrl = NULL;
+ crlDER.data = NULL;
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_Open.\n");
+ inFile = PR_Open(crlFileName, PR_RDONLY, 0);
+
+ if (!inFile){
+ PKIX_ERROR(PKIX_UNABLETOOPENCRLFILE);
+ } else {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECU_ReadDerFromFile.\n");
+ rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE);
+ if (!rv){
+ buf = (void *)crlDER.data;
+ len = crlDER.len;
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (buf, len, &byteArray, plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_CRL_Create
+ (byteArray, &crl, plContext),
+ PKIX_CRLCREATEFAILED);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem.\n");
+ SECITEM_FreeItem(&crlDER, PR_FALSE);
+
+ } else {
+ PKIX_ERROR(PKIX_UNABLETOREADDERFROMCRLFILE);
+ }
+ }
+
+ *pCrl = crl;
+
+cleanup:
+ if (inFile){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_Close(inFile);
+ }
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&crlDER, PR_FALSE);
+
+ PKIX_DECREF(crl);
+ if (crlDER.data != NULL) {
+ SECITEM_FreeItem(&crlDER, PR_FALSE);
+ }
+ }
+
+ PKIX_DECREF(byteArray);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_PopulateCert
+ * DESCRIPTION:
+ *
+ * Create list of Certs from *.crt files at directory specified in dirName,
+ * Not recursive to sub-directory. Also assume the directory contents are
+ * not changed dynamically.
+ *
+ * PARAMETERS
+ * "colCertStoreContext" - Address of CollectionCertStoreContext
+ * where the dirName is specified and where the return
+ * Certs are stored as a list. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_PopulateCert(
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext,
+ void *plContext)
+{
+ PKIX_List *certList = NULL;
+ PKIX_PL_Cert *certItem = NULL;
+ char *dirName = NULL;
+ char *pathName = NULL;
+ PKIX_UInt32 dirNameLen = 0;
+ PRErrorCode prError = 0;
+ PRDir *dir = NULL;
+ PRDirEntry *dirEntry = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_PopulateCert");
+ PKIX_NULLCHECK_ONE(colCertStoreContext);
+
+ /* convert directory to ascii */
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (colCertStoreContext->storeDir,
+ PKIX_ESCASCII,
+ (void **)&dirName,
+ &dirNameLen,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ /* create cert list, if no cert file, should return an empty list */
+
+ PKIX_CHECK(PKIX_List_Create(&certList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* open directory and read in .crt files */
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_OpenDir.\n");
+ dir = PR_OpenDir(dirName);
+
+ if (!dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG_ARG
+ ("\t\t Directory Name:%s\n", dirName);
+ PKIX_ERROR(PKIX_CANNOTOPENCOLLECTIONCERTSTORECONTEXTDIRECTORY);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Empty directory.\n");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ while (dirEntry != NULL && prError == 0) {
+ if (PL_strrstr(dirEntry->name, ".crt") ==
+ dirEntry->name + PL_strlen(dirEntry->name) - 4) {
+
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_PL_Malloc
+ (dirNameLen + PL_strlen(dirEntry->name) + 2,
+ (void **)&pathName,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ if ((!PKIX_ERROR_RECEIVED) && (pathName != NULL)){
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcpy for dirName.\n");
+ PL_strcpy(pathName, dirName);
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for dirName.\n");
+ PL_strcat(pathName, "/");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for /.\n");
+ PL_strcat(pathName, dirEntry->name);
+
+ PKIX_CHECK_ONLY_FATAL
+ (pkix_pl_CollectionCertStoreContext_CreateCert
+ (pathName, &certItem, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTCREATECERTFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (certList,
+ (PKIX_PL_Object *)certItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(certItem);
+ PKIX_FREE(pathName);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+ }
+
+ if ((prError != 0) && (prError != PR_NO_MORE_FILES_ERROR)) {
+ PKIX_ERROR(PKIX_COLLECTIONCERTSTOREPOPULATECERTFAILED);
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable(certList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ PKIX_INCREF(certList);
+ colCertStoreContext->certList = certList;
+
+cleanup:
+ if (dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_CloseDir(dir);
+ }
+
+ PKIX_FREE(pathName);
+ PKIX_FREE(dirName);
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(certList);
+ }
+
+ PKIX_DECREF(certItem);
+ PKIX_DECREF(certList);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_PopulateCRL
+ * DESCRIPTION:
+ *
+ * Create list of CRLs from *.crl files at directory specified in dirName,
+ * Not recursive to sub-dirctory. Also assume the directory contents are
+ * not changed dynamically.
+ *
+ * PARAMETERS
+ * "colCertStoreContext" - Address of CollectionCertStoreContext
+ * where the dirName is specified and where the return
+ * CRLs are stored as a list. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_PopulateCRL(
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext,
+ void *plContext)
+{
+ PKIX_List *crlList = NULL;
+ PKIX_PL_CRL *crlItem = NULL;
+ char *dirName = NULL;
+ char *pathName = NULL;
+ PKIX_UInt32 dirNameLen = 0;
+ PRErrorCode prError = 0;
+ PRDir *dir = NULL;
+ PRDirEntry *dirEntry = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_PopulateCRL");
+ PKIX_NULLCHECK_ONE(colCertStoreContext);
+
+ /* convert directory to ascii */
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (colCertStoreContext->storeDir,
+ PKIX_ESCASCII,
+ (void **)&dirName,
+ &dirNameLen,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ /* create CRL list, if no CRL file, should return an empty list */
+
+ PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* open directory and read in .crl files */
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_OpenDir.\n");
+ dir = PR_OpenDir(dirName);
+
+ if (!dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG_ARG
+ ("\t\t Directory Name:%s\n", dirName);
+ PKIX_ERROR(PKIX_CANNOTOPENCOLLECTIONCERTSTORECONTEXTDIRECTORY);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Empty directory.\n");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ while (dirEntry != NULL && prError == 0) {
+ if (PL_strrstr(dirEntry->name, ".crl") ==
+ dirEntry->name + PL_strlen(dirEntry->name) - 4) {
+
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_PL_Malloc
+ (dirNameLen + PL_strlen(dirEntry->name) + 2,
+ (void **)&pathName,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ if ((!PKIX_ERROR_RECEIVED) && (pathName != NULL)){
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcpy for dirName.\n");
+ PL_strcpy(pathName, dirName);
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for dirName.\n");
+ PL_strcat(pathName, "/");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for /.\n");
+ PL_strcat(pathName, dirEntry->name);
+
+ PKIX_CHECK_ONLY_FATAL
+ (pkix_pl_CollectionCertStoreContext_CreateCRL
+ (pathName, &crlItem, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTCREATECRLFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (crlList,
+ (PKIX_PL_Object *)crlItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(crlItem);
+ PKIX_FREE(pathName);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+ }
+
+ if ((prError != 0) && (prError != PR_NO_MORE_FILES_ERROR)) {
+ PKIX_ERROR(PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCRLFAILED);
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable(crlList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ PKIX_INCREF(crlList);
+ colCertStoreContext->crlList = crlList;
+
+cleanup:
+ if (dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_CloseDir(dir);
+ }
+
+ PKIX_FREE(pathName);
+ PKIX_FREE(dirName);
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(crlList);
+ }
+
+ PKIX_DECREF(crlItem);
+ PKIX_DECREF(crlList);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCert
+ * DESCRIPTION:
+ *
+ * Finds the Certs that match the criterion of the CertSelector pointed
+ * to by "selector" using the List of Certs pointed to by "certList" and
+ * stores the matching Certs at "pSelectedCertList".
+ *
+ * Not recursive to sub-directory.
+ *
+ * PARAMETERS
+ * "certList" - Address of List of Certs to be searched. Must be non-NULL.
+ * "colCertStoreContext" - Address of CollectionCertStoreContext
+ * where the cached Certs are stored.
+ * "selector" - CertSelector for chosing Cert based on Params set
+ * "pSelectedCertList" - Certs that qualified by selector.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_GetSelectedCert(
+ PKIX_List *certList,
+ PKIX_CertSelector *selector,
+ PKIX_List **pSelectedCertList,
+ void *plContext)
+{
+ PKIX_List *selectCertList = NULL;
+ PKIX_PL_Cert *certItem = NULL;
+ PKIX_CertSelector_MatchCallback certSelectorMatch = NULL;
+ PKIX_UInt32 numCerts = 0;
+ PKIX_UInt32 i = 0;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_GetSelectedCert");
+ PKIX_NULLCHECK_THREE(certList, selector, pSelectedCertList);
+
+ PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
+ (selector, &certSelectorMatch, plContext),
+ PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(certList, &numCerts, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ if (certSelectorMatch) {
+
+ PKIX_CHECK(PKIX_List_Create(&selectCertList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; i < numCerts; i++) {
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_GetItem
+ (certList,
+ i,
+ (PKIX_PL_Object **) &certItem,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (certSelectorMatch
+ (selector, certItem, plContext),
+ PKIX_CERTSELECTORMATCHFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (selectCertList,
+ (PKIX_PL_Object *)certItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(certItem);
+ }
+
+ } else {
+
+ PKIX_INCREF(certList);
+
+ selectCertList = certList;
+ }
+
+ *pSelectedCertList = selectCertList;
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCRL
+ * DESCRIPTION:
+ *
+ * Finds the CRLs that match the criterion of the CRLSelector pointed
+ * to by "selector" using the List of CRLs pointed to by "crlList" and
+ * stores the matching CRLs at "pSelectedCrlList".
+ *
+ * Not recursive to sub-directory.
+ *
+ * PARAMETERS
+ * "crlList" - Address of List of CRLs to be searched. Must be non-NULL
+ * "selector" - CRLSelector for chosing CRL based on Params set
+ * "pSelectedCrlList" - CRLs that qualified by selector.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_GetSelectedCRL(
+ PKIX_List *crlList,
+ PKIX_CRLSelector *selector,
+ PKIX_List **pSelectedCrlList,
+ void *plContext)
+{
+ PKIX_List *selectCrlList = NULL;
+ PKIX_PL_CRL *crlItem = NULL;
+ PKIX_CRLSelector_MatchCallback crlSelectorMatch = NULL;
+ PKIX_UInt32 numCrls = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_Boolean match = PKIX_FALSE;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_GetSelectedCRL");
+ PKIX_NULLCHECK_THREE(crlList, selector, pSelectedCrlList);
+
+ PKIX_CHECK(PKIX_CRLSelector_GetMatchCallback
+ (selector, &crlSelectorMatch, plContext),
+ PKIX_CRLSELECTORGETMATCHCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(crlList, &numCrls, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ if (crlSelectorMatch) {
+
+ PKIX_CHECK(PKIX_List_Create(&selectCrlList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; i < numCrls; i++) {
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
+ (crlList,
+ i,
+ (PKIX_PL_Object **) &crlItem,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (crlSelectorMatch
+ (selector, crlItem, &match, plContext),
+ PKIX_CRLSELECTORMATCHFAILED);
+
+ if (!(PKIX_ERROR_RECEIVED) && match) {
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (selectCrlList,
+ (PKIX_PL_Object *)crlItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(crlItem);
+ }
+ } else {
+
+ PKIX_INCREF(crlList);
+
+ selectCrlList = crlList;
+ }
+
+ /* Don't throw away the list if one CRL was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pSelectedCrlList = selectCrlList;
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStore_GetCert
+ * DESCRIPTION:
+ *
+ * Retrieve Certs in a list of PKIX_PL_Cert object.
+ *
+ * PARAMETERS:
+ * "colCertStoreContext"
+ * The object CertStore is the object passed in by checker call.
+ * "crlSelector"
+ * CRLSelector specifies criteria for chosing CRL's
+ * "pNBIOContext"
+ * Address where platform-dependent information is returned for CertStores
+ * that use non-blocking I/O. Must be non-NULL.
+ * "pCertList"
+ * Address where object pointer will be returned. 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 CertStore 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_CollectionCertStore_GetCert(
+ PKIX_CertStore *certStore,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+ PKIX_List *selectedCerts = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_GetCert");
+ PKIX_NULLCHECK_FOUR(certStore, selector, pNBIOContext, pCerts);
+
+ *pNBIOContext = NULL; /* We don't use non-blocking I/O */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (certStore,
+ (PKIX_PL_Object **) &colCertStoreContext,
+ plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (colCertStoreContext->certList == NULL) {
+
+ PKIX_OBJECT_LOCK(colCertStoreContext);
+
+ /*
+ * Certs in the directory are cached based on the
+ * assumption that the directory contents won't be
+ * changed dynamically.
+ */
+ if (colCertStoreContext->certList == NULL){
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_PopulateCert
+ (colCertStoreContext, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTPOPULATECERTFAILED);
+ }
+
+ PKIX_OBJECT_UNLOCK(colCertStoreContext);
+ }
+
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_GetSelectedCert
+ (colCertStoreContext->certList,
+ selector,
+ &selectedCerts,
+ plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCERTFAILED);
+
+ *pCerts = selectedCerts;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_DECREF(colCertStoreContext);
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStore_GetCRL
+ * DESCRIPTION:
+ *
+ * Retrieve CRL's in a list of PKIX_PL_CRL object.
+ *
+ * PARAMETERS:
+ * "colCertStoreContext"
+ * The object CertStore is passed in by checker call.
+ * "crlSelector"
+ * CRLSelector specifies criteria for chosing CRL's
+ * "pNBIOContext"
+ * Address where platform-dependent information is returned for CertStores
+ * that use non-blocking I/O. Must be non-NULL.
+ * "pCrlList"
+ * Address where object pointer will be returned. 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 CertStore 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_CollectionCertStore_GetCRL(
+ PKIX_CertStore *certStore,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+ PKIX_List *selectCrl = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_GetCRL");
+ PKIX_NULLCHECK_FOUR(certStore, selector, pNBIOContext, pCrlList);
+
+ *pNBIOContext = NULL; /* We don't use non-blocking I/O */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (certStore,
+ (PKIX_PL_Object **) &colCertStoreContext,
+ plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (colCertStoreContext->crlList == NULL) {
+
+ PKIX_OBJECT_LOCK(colCertStoreContext);
+
+ /*
+ * CRLs in the directory are cached based on the
+ * assumption that the directory contents won't be
+ * changed dynamically.
+ */
+ if (colCertStoreContext->crlList == NULL){
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_PopulateCRL
+ (colCertStoreContext, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTPOPULATECRLFAILED);
+ }
+
+ PKIX_OBJECT_UNLOCK(colCertStoreContext);
+
+ }
+
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_GetSelectedCRL
+ (colCertStoreContext->crlList,
+ selector,
+ &selectCrl,
+ plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCRLFAILED);
+
+ *pCrlList = selectCrl;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_DECREF(colCertStoreContext);
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_RegisterSelf
+ * DESCRIPTION:
+ *
+ * Registers PKIX_PL_COLLECTIONCERTSTORECONTEXT_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_CollectionCertStoreContext_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_RegisterSelf");
+
+ entry.description = "CollectionCertStoreContext";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CollectionCertStoreContext);
+ entry.destructor = pkix_pl_CollectionCertStoreContext_Destroy;
+ entry.equalsFunction = pkix_pl_CollectionCertStoreContext_Equals;
+ entry.hashcodeFunction = pkix_pl_CollectionCertStoreContext_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_COLLECTIONCERTSTORECONTEXT_TYPE] = entry;
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/* --Public-CollectionCertStoreContext-Functions--------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_CollectionCertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_CollectionCertStore_Create(
+ PKIX_PL_String *storeDir,
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+ PKIX_CertStore *certStore = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_CollectionCertStore_Create");
+ PKIX_NULLCHECK_TWO(storeDir, pCertStore);
+
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_Create
+ (storeDir, &colCertStoreContext, plContext),
+ PKIX_COULDNOTCREATECOLLECTIONCERTSTORECONTEXTOBJECT);
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_CollectionCertStore_GetCert,
+ pkix_pl_CollectionCertStore_GetCRL,
+ NULL, /* GetCertContinue */
+ NULL, /* GetCRLContinue */
+ pkix_pl_CollectionCertStore_CheckTrust,
+ NULL, /* can not store crls */
+ NULL, /* can not do revocation check */
+ (PKIX_PL_Object *)colCertStoreContext,
+ PKIX_TRUE, /* cache flag */
+ PKIX_TRUE, /* local - no network I/O */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ PKIX_DECREF(colCertStoreContext);
+
+ *pCertStore = certStore;
+
+cleanup:
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h
new file mode 100644
index 0000000000..f41e6fa5e8
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h
@@ -0,0 +1,34 @@
+/* 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_colcertstore.h
+ *
+ * CollectionCertstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_COLCERTSTORE_H
+#define _PKIX_PL_COLCERTSTORE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_CollectionCertStoreContext {
+ PKIX_PL_String *storeDir;
+ PKIX_List *crlList;
+ PKIX_List *certList;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_CollectionCertStoreContext_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_COLCERTSTORE_H */
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 100644
index 0000000000..471f92004a
--- /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);
+}
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h
new file mode 100644
index 0000000000..a03ea94d86
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h
@@ -0,0 +1,62 @@
+/* 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.h
+ *
+ * HTTPCertstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_HTTPCERTSTORE_H
+#define _PKIX_PL_HTTPCERTSTORE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_HttpCertStoreContextStruct {
+ const SEC_HttpClientFcn *client;
+ SEC_HTTP_SERVER_SESSION serverSession;
+ SEC_HTTP_REQUEST_SESSION requestSession;
+ char *path;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_HttpCertStoreContext_RegisterSelf(void *plContext);
+
+void pkix_pl_HttpCertStore_Shutdown(void *plContext);
+
+PKIX_Error *
+pkix_pl_HttpCertStore_CreateWithAsciiName(
+ PKIX_PL_HttpClient *client,
+ char *locationAscii,
+ PKIX_CertStore **pCertStore,
+ void *plContext);
+
+PKIX_Error *
+pkix_HttpCertStore_FindSocketConnection(
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_HttpCertStore_ProcessCertResponse(
+ PRUint16 responseCode,
+ const char *responseContentType,
+ const char *responseData,
+ PRUint32 responseDataLen,
+ PKIX_List **pCertList,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_HTTPCERTSTORE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
new file mode 100644
index 0000000000..f73b95f686
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
@@ -0,0 +1,1654 @@
+/* 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_httpdefaultclient.c
+ *
+ * HTTPDefaultClient Function Definitions
+ *
+ */
+
+#include "pkix_pl_httpdefaultclient.h"
+
+static void *plContext = NULL;
+
+/*
+ * The interface specification for an http client requires that it register
+ * a function table of type SEC_HttpClientFcn, which is defined as a union
+ * of tables, of which only version 1 is defined at present.
+ *
+ * Note: these functions violate the PKIX calling conventions, in that they
+ * return SECStatus rather than PKIX_Error*, and that they do not provide a
+ * plContext argument. They are implemented here as calls to PKIX functions,
+ * but the plContext value is circularly defined - a true kludge. Its value
+ * is saved at the time of the call to pkix_pl_HttpDefaultClient_Create for
+ * subsequent use, but since that initial call comes from the
+ * pkix_pl_HttpDefaultClient_CreateSessionFcn, it's not really getting saved.
+ */
+static SEC_HttpClientFcnV1 vtable = {
+ pkix_pl_HttpDefaultClient_CreateSessionFcn,
+ pkix_pl_HttpDefaultClient_KeepAliveSessionFcn,
+ pkix_pl_HttpDefaultClient_FreeSessionFcn,
+ pkix_pl_HttpDefaultClient_RequestCreateFcn,
+ pkix_pl_HttpDefaultClient_SetPostDataFcn,
+ pkix_pl_HttpDefaultClient_AddHeaderFcn,
+ pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn,
+ pkix_pl_HttpDefaultClient_CancelFcn,
+ pkix_pl_HttpDefaultClient_FreeFcn
+};
+
+static SEC_HttpClientFcn httpClient;
+
+static const char *eohMarker = "\r\n\r\n";
+static const PKIX_UInt32 eohMarkLen = 4; /* strlen(eohMarker) */
+static const char *crlf = "\r\n";
+static const PKIX_UInt32 crlfLen = 2; /* strlen(crlf) */
+static const char *httpprotocol = "HTTP/";
+static const PKIX_UInt32 httpprotocolLen = 5; /* strlen(httpprotocol) */
+
+
+#define HTTP_UNKNOWN_CONTENT_LENGTH -1
+
+/* --Private-HttpDefaultClient-Functions------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_HdrCheckComplete
+ * DESCRIPTION:
+ *
+ * This function determines whether the headers in the current receive buffer
+ * in the HttpDefaultClient pointed to by "client" are complete. If so, the
+ * input data is checked for status code, content-type and content-length are
+ * extracted, and the client is set up to read the body of the response.
+ * Otherwise, the client is set up to continue reading header data.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "bytesRead"
+ * The UInt32 number of bytes received in the latest read.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_HdrCheckComplete(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_UInt32 bytesRead,
+ PKIX_Boolean *pKeepGoing,
+ void *plCtx)
+{
+ PKIX_UInt32 alreadyScanned = 0;
+ PKIX_UInt32 comp = 0;
+ PKIX_UInt32 headerLength = 0;
+ PKIX_Int32 contentLength = HTTP_UNKNOWN_CONTENT_LENGTH;
+ char *eoh = NULL;
+ char *statusLineEnd = NULL;
+ char *space = NULL;
+ char *nextHeader = NULL;
+ const char *httpcode = NULL;
+ char *thisHeaderEnd = NULL;
+ char *value = NULL;
+ char *colon = NULL;
+ char *copy = NULL;
+ char *body = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_HdrCheckComplete");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ /* Does buffer contain end-of-header marker? */
+
+ /* Copy number of scanned bytes into a variable. */
+ alreadyScanned = client->filledupBytes;
+ /*
+ * If this is the initial buffer, we have to scan from the beginning.
+ * If we scanned, failed to find eohMarker, and read some more, we
+ * only have to scan from where we left off.
+ */
+ if (alreadyScanned > eohMarkLen) {
+ /* Back up and restart scanning over a few bytes that were
+ * scanned before */
+ PKIX_UInt32 searchStartPos = alreadyScanned - eohMarkLen;
+ eoh = PL_strnstr(&(client->rcvBuf[searchStartPos]), eohMarker,
+ bytesRead + searchStartPos);
+ } else {
+ /* A search from the beginning of the buffer. */
+ eoh = PL_strnstr(client->rcvBuf, eohMarker, bytesRead);
+ }
+
+ client->filledupBytes += bytesRead;
+
+ if (eoh == NULL) { /* did we see end-of-header? */
+ /* No. Continue to read header data */
+ client->connectStatus = HTTP_RECV_HDR;
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /* Yes. Calculate how many bytes in header (not counting eohMarker) */
+ headerLength = (eoh - client->rcvBuf);
+
+ /* allocate space to copy header (and for the NULL terminator) */
+ PKIX_CHECK(PKIX_PL_Malloc(headerLength + 1, (void **)&copy, plCtx),
+ PKIX_MALLOCFAILED);
+
+ /* copy header data before we corrupt it (by storing NULLs) */
+ PORT_Memcpy(copy, client->rcvBuf, headerLength);
+ /* Store the NULL terminator */
+ copy[headerLength] = '\0';
+ client->rcvHeaders = copy;
+
+ /* Did caller want a pointer to header? */
+ if (client->rcv_http_headers != NULL) {
+ /* store pointer for caller */
+ *(client->rcv_http_headers) = copy;
+ }
+
+ /* Check that message status is okay. */
+ statusLineEnd = PL_strnstr(client->rcvBuf, crlf, client->capacity);
+ if (statusLineEnd == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+ goto cleanup;
+ }
+
+ *statusLineEnd = '\0';
+
+ space = strchr((const char *)client->rcvBuf, ' ');
+ if (space == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ comp = PORT_Strncasecmp((const char *)client->rcvBuf, httpprotocol,
+ httpprotocolLen);
+ if (comp != 0) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ httpcode = space + 1;
+ space = strchr(httpcode, ' ');
+ if (space == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ *space = '\0';
+
+ client->responseCode = atoi(httpcode);
+ if (client->responseCode != 200) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ /* Find the content-type and content-length */
+ nextHeader = statusLineEnd + crlfLen;
+ *eoh = '\0';
+ do {
+ thisHeaderEnd = NULL;
+ value = NULL;
+
+ colon = strchr(nextHeader, ':');
+ if (colon == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ *colon = '\0';
+ value = colon + 1;
+ if (*value != ' ') {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ value++;
+ thisHeaderEnd = strstr(value, crlf);
+ if (thisHeaderEnd != NULL) {
+ *thisHeaderEnd = '\0';
+ }
+ comp = PORT_Strcasecmp(nextHeader, "content-type");
+ if (comp == 0) {
+ client->rcvContentType = PORT_Strdup(value);
+ } else {
+ comp = PORT_Strcasecmp(nextHeader, "content-length");
+ if (comp == 0) {
+ contentLength = atoi(value);
+ }
+ }
+ if (thisHeaderEnd != NULL) {
+ nextHeader = thisHeaderEnd + crlfLen;
+ } else {
+ nextHeader = NULL;
+ }
+ } while ((nextHeader != NULL) && (nextHeader < (eoh + crlfLen)));
+
+ /* Did caller provide a pointer to return content-type? */
+ if (client->rcv_http_content_type != NULL) {
+ *(client->rcv_http_content_type) = client->rcvContentType;
+ }
+
+ if (client->rcvContentType == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ /* How many bytes remain in current buffer, beyond the header? */
+ headerLength += eohMarkLen;
+ client->filledupBytes -= headerLength;
+
+ /*
+ * The headers have passed validation. Now figure out whether the
+ * message is within the caller's size limit (if one was specified).
+ */
+ switch (contentLength) {
+ case 0:
+ client->rcv_http_data_len = 0;
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+ break;
+
+ case HTTP_UNKNOWN_CONTENT_LENGTH:
+ /* Unknown contentLength indicator.Will be set by
+ * pkix_pl_HttpDefaultClient_RecvBody whey connection get closed */
+ client->rcv_http_data_len = HTTP_UNKNOWN_CONTENT_LENGTH;
+ contentLength = /* Try to reserve 4K+ buffer */
+ client->filledupBytes + HTTP_DATA_BUFSIZE;
+ if (client->maxResponseLen > 0 &&
+ contentLength > (PKIX_Int32)client->maxResponseLen) {
+ if (client->filledupBytes < client->maxResponseLen) {
+ contentLength = client->maxResponseLen;
+ } else {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ }
+ /* set available number of bytes in the buffer */
+ client->capacity = contentLength;
+ client->connectStatus = HTTP_RECV_BODY;
+ *pKeepGoing = PKIX_TRUE;
+ break;
+
+ default:
+ client->rcv_http_data_len = contentLength;
+ if (client->maxResponseLen > 0 &&
+ (PKIX_Int32)client->maxResponseLen < contentLength) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * Do we have all of the message body, or do we need to read some more?
+ */
+ if ((PKIX_Int32)client->filledupBytes < contentLength) {
+ client->connectStatus = HTTP_RECV_BODY;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+ }
+ }
+
+ if (contentLength > 0) {
+ /* allocate a buffer of size contentLength for the content */
+ PKIX_CHECK(PKIX_PL_Malloc(contentLength, (void **)&body, plCtx),
+ PKIX_MALLOCFAILED);
+
+ /* copy any remaining bytes in current buffer into new buffer */
+ if (client->filledupBytes > 0) {
+ PORT_Memcpy(body, &(client->rcvBuf[headerLength]),
+ client->filledupBytes);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Free(client->rcvBuf, plCtx),
+ PKIX_FREEFAILED);
+ client->rcvBuf = body;
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_HttpDefaultClient_Create
+ * DESCRIPTION:
+ *
+ * This function creates a new HttpDefaultClient, and stores the result at
+ * "pClient".
+ *
+ * The HttpClient API does not include a plContext argument in its
+ * function calls. Its value at the time of this Create call must be the
+ * same as when the client is invoked.
+ *
+ * PARAMETERS:
+ * "host"
+ * The name of the server with which we hope to exchange messages. Must
+ * be non-NULL.
+ * "portnum"
+ * The port number to be used for our connection to the server.
+ * "pClient"
+ * The address at which the created HttpDefaultClient is to be stored.
+ * Must be non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Create(
+ const char *host,
+ PRUint16 portnum,
+ PKIX_PL_HttpDefaultClient **pClient,
+ void *plCtx)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "PKIX_PL_HttpDefaultClient_Create");
+ PKIX_NULLCHECK_TWO(pClient, host);
+
+ /* allocate an HttpDefaultClient */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_HTTPDEFAULTCLIENT_TYPE,
+ sizeof (PKIX_PL_HttpDefaultClient),
+ (PKIX_PL_Object **)&client,
+ plCtx),
+ PKIX_COULDNOTCREATEHTTPDEFAULTCLIENTOBJECT);
+
+ /* Client timeout is overwritten in HttpDefaultClient_RequestCreate
+ * function. Default value will be ignored. */
+ client->timeout = 0;
+ client->connectStatus = HTTP_NOT_CONNECTED;
+ client->portnum = portnum;
+ client->bytesToWrite = 0;
+ client->send_http_data_len = 0;
+ client->rcv_http_data_len = 0;
+ client->capacity = 0;
+ client->filledupBytes = 0;
+ client->responseCode = 0;
+ client->maxResponseLen = 0;
+ client->GETLen = 0;
+ client->POSTLen = 0;
+ client->pRcv_http_data_len = NULL;
+ client->callbackList = NULL;
+ client->GETBuf = NULL;
+ client->POSTBuf = NULL;
+ client->rcvBuf = NULL;
+ /* "host" is a parsing result by CERT_GetURL function that adds
+ * "end of line" to the value. OK to dup the string. */
+ client->host = PORT_Strdup(host);
+ if (!client->host) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ client->path = NULL;
+ client->rcvContentType = NULL;
+ client->rcvHeaders = NULL;
+ client->send_http_method = HTTP_POST_METHOD;
+ client->send_http_content_type = NULL;
+ client->send_http_data = NULL;
+ client->rcv_http_response_code = NULL;
+ client->rcv_http_content_type = NULL;
+ client->rcv_http_headers = NULL;
+ client->rcv_http_data = NULL;
+ client->socket = NULL;
+
+ /*
+ * The HttpClient API does not include a plCtx argument in its
+ * function calls. Save it here.
+ */
+ client->plContext = plCtx;
+
+ *pClient = client;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(client);
+ }
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Destroy(
+ PKIX_PL_Object *object,
+ void *plCtx)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_HTTPDEFAULTCLIENT_TYPE, plCtx),
+ PKIX_OBJECTNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)object;
+
+ if (client->rcvHeaders) {
+ PKIX_PL_Free(client->rcvHeaders, plCtx);
+ client->rcvHeaders = NULL;
+ }
+ if (client->rcvContentType) {
+ PORT_Free(client->rcvContentType);
+ client->rcvContentType = NULL;
+ }
+ if (client->GETBuf != NULL) {
+ PR_smprintf_free(client->GETBuf);
+ client->GETBuf = NULL;
+ }
+ if (client->POSTBuf != NULL) {
+ PKIX_PL_Free(client->POSTBuf, plCtx);
+ client->POSTBuf = NULL;
+ }
+ if (client->rcvBuf != NULL) {
+ PKIX_PL_Free(client->rcvBuf, plCtx);
+ client->rcvBuf = NULL;
+ }
+ if (client->host) {
+ PORT_Free(client->host);
+ client->host = NULL;
+ }
+ if (client->path) {
+ PORT_Free(client->path);
+ client->path = NULL;
+ }
+ PKIX_DECREF(client->socket);
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_HTTPDEFAULTCLIENT_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_HttpDefaultClient_RegisterSelf(void *plCtx)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry =
+ &systemClasses[PKIX_HTTPDEFAULTCLIENT_TYPE];
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_RegisterSelf");
+
+ entry->description = "HttpDefaultClient";
+ entry->typeObjectSize = sizeof(PKIX_PL_HttpDefaultClient);
+ entry->destructor = pkix_pl_HttpDefaultClient_Destroy;
+
+ httpClient.version = 1;
+ httpClient.fcnTable.ftable1 = vtable;
+ (void)SEC_RegisterDefaultHttpClient(&httpClient);
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/* --Private-HttpDefaultClient-I/O-Functions---------------------------- */
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_ConnectContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether a socket Connect initiated earlier for the
+ * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_ConnectContinue(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plCtx)
+{
+ PRErrorCode status;
+ PKIX_Boolean keepGoing = PKIX_FALSE;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_ConnectContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->connectcontinueCallback
+ (client->socket, &status, plCtx),
+ PKIX_SOCKETCONNECTCONTINUEFAILED);
+
+ if (status == 0) {
+ client->connectStatus = HTTP_CONNECTED;
+ keepGoing = PKIX_TRUE;
+ } else if (status != PR_IN_PROGRESS_ERROR) {
+ PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION);
+ }
+
+ *pKeepGoing = keepGoing;
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_Send
+ * DESCRIPTION:
+ *
+ * This function creates and sends HTTP-protocol headers and, if applicable,
+ * data, for the HttpDefaultClient "client", and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input, and at
+ * "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent is stored. Must be
+ * non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Send(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plCtx)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_Int32 lenToWrite = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ char *dataToWrite = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Send");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ /* Do we have anything waiting to go? */
+ if ((client->GETBuf) || (client->POSTBuf)) {
+
+ if (client->GETBuf) {
+ dataToWrite = client->GETBuf;
+ lenToWrite = client->GETLen;
+ } else {
+ dataToWrite = client->POSTBuf;
+ lenToWrite = client->POSTLen;
+ }
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->sendCallback
+ (client->socket,
+ dataToWrite,
+ lenToWrite,
+ &bytesWritten,
+ plCtx),
+ PKIX_SOCKETSENDFAILED);
+
+ client->rcvBuf = NULL;
+ client->capacity = 0;
+ client->filledupBytes = 0;
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * to poll for completion later.
+ */
+ if (bytesWritten >= 0) {
+ client->connectStatus = HTTP_RECV_HDR;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = HTTP_SEND_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+ }
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_SendContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the sending of the HTTP message for the
+ * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a
+ * flag indicating whether processing can continue without further input, and
+ * at "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent is stored. Must be
+ * non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_SendContinue(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plCtx)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_SendContinue");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->socket, &bytesWritten, NULL, plCtx),
+ PKIX_SOCKETPOLLFAILED);
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * continue to poll.
+ */
+ if (bytesWritten >= 0) {
+ client->connectStatus = HTTP_RECV_HDR;
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdr
+ * DESCRIPTION:
+ *
+ * This function receives HTTP headers for the HttpDefaultClient "client", and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_RecvHdr(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plCtx)
+{
+ PKIX_UInt32 bytesToRead = 0;
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvHdr");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ /*
+ * rcvbuf, capacity, and filledupBytes were
+ * initialized when we wrote the headers. We begin by reading
+ * HTTP_HEADER_BUFSIZE bytes, repeatedly increasing the buffersize and
+ * reading again if necessary, until we have read the end-of-header
+ * marker, "\r\n\r\n", or have reached our maximum.
+ */
+ client->capacity += HTTP_HEADER_BUFSIZE;
+ PKIX_CHECK(PKIX_PL_Realloc
+ (client->rcvBuf,
+ client->capacity,
+ (void **)&(client->rcvBuf),
+ plCtx),
+ PKIX_REALLOCFAILED);
+
+ bytesToRead = client->capacity - client->filledupBytes;
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->recvCallback
+ (client->socket,
+ (void *)&(client->rcvBuf[client->filledupBytes]),
+ bytesToRead,
+ &bytesRead,
+ plCtx),
+ PKIX_SOCKETRECVFAILED);
+
+ if (bytesRead > 0) {
+ /* client->filledupBytes will be adjusted by
+ * pkix_pl_HttpDefaultClient_HdrCheckComplete */
+ PKIX_CHECK(
+ pkix_pl_HttpDefaultClient_HdrCheckComplete(client, bytesRead,
+ pKeepGoing,
+ plCtx),
+ PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
+ } else {
+ client->connectStatus = HTTP_RECV_HDR_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdrContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the receiving of the HTTP headers for the
+ * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_RecvHdrContinue(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plCtx)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_RecvHdrContinue");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->socket, NULL, &bytesRead, plCtx),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesRead > 0) {
+ client->filledupBytes += bytesRead;
+
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete
+ (client, bytesRead, pKeepGoing, plCtx),
+ PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
+
+ } else {
+
+ *pKeepGoing = PKIX_FALSE;
+
+ }
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RecvBody
+ * DESCRIPTION:
+ *
+ * This function processes the contents of the first buffer of a received
+ * HTTP-protocol message for the HttpDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_RecvBody(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plCtx)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_Int32 bytesToRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvBody");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ if (client->rcv_http_data_len != HTTP_UNKNOWN_CONTENT_LENGTH) {
+ bytesToRead = client->rcv_http_data_len -
+ client->filledupBytes;
+ } else {
+ /* Reading till the EOF. Context length is not known.*/
+ /* Check the buffer capacity: increase and
+ * reallocate if it is low. */
+ int freeBuffSize = client->capacity - client->filledupBytes;
+ if (freeBuffSize < HTTP_MIN_AVAILABLE_BUFFER_SIZE) {
+ /* New length will be consist of available(downloaded) bytes,
+ * plus remaining capacity, plus new expansion. */
+ int currBuffSize = client->capacity;
+ /* Try to increase the buffer by 4K */
+ unsigned int newLength = currBuffSize + HTTP_DATA_BUFSIZE;
+ if (client->maxResponseLen > 0 &&
+ newLength > client->maxResponseLen) {
+ newLength = client->maxResponseLen;
+ }
+ /* Check if we can grow the buffer and report an error if
+ * new size is not larger than the current size of the buffer.*/
+ if (newLength <= client->filledupBytes) {
+ client->rcv_http_data_len = client->filledupBytes;
+ client->connectStatus = HTTP_ERROR;
+ *pKeepGoing = PKIX_FALSE;
+ goto cleanup;
+ }
+ if (client->capacity < newLength) {
+ client->capacity = newLength;
+ PKIX_CHECK(
+ PKIX_PL_Realloc(client->rcvBuf, newLength,
+ (void**)&client->rcvBuf, plCtx),
+ PKIX_REALLOCFAILED);
+ freeBuffSize = client->capacity -
+ client->filledupBytes;
+ }
+ }
+ bytesToRead = freeBuffSize;
+ }
+
+ /* Use poll callback if waiting on non-blocking IO */
+ if (client->connectStatus == HTTP_RECV_BODY_PENDING) {
+ PKIX_CHECK(callbackList->pollCallback
+ (client->socket, NULL, &bytesRead, plCtx),
+ PKIX_SOCKETPOLLFAILED);
+ } else {
+ PKIX_CHECK(callbackList->recvCallback
+ (client->socket,
+ (void *)&(client->rcvBuf[client->filledupBytes]),
+ bytesToRead,
+ &bytesRead,
+ plCtx),
+ PKIX_SOCKETRECVFAILED);
+ }
+
+ /* If bytesRead < 0, an error will be thrown by recvCallback, so
+ * need to handle >= 0 cases. */
+
+ /* bytesRead == 0 - IO was blocked. */
+ if (bytesRead == 0) {
+ client->connectStatus = HTTP_RECV_BODY_PENDING;
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /* We got something. Did we get it all? */
+ client->filledupBytes += bytesRead;
+
+ /* continue if not enough bytes read or if complete size of
+ * transfer is unknown */
+ if (bytesToRead > bytesRead ||
+ client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+
+cleanup:
+ if (pkixErrorResult && pkixErrorResult->errCode ==
+ PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED) {
+ if (client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
+ client->rcv_http_data_len = client->filledupBytes;
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+ PKIX_DECREF(pkixErrorResult);
+ } else {
+ client->connectStatus = HTTP_ERROR;
+ }
+ }
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_Dispatch
+ * DESCRIPTION:
+ *
+ * This function is the state machine dispatcher for the HttpDefaultClient
+ * pointed to by "client". Results are returned by changes to various fields
+ * in the context.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "plCtx"
+ * 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 HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Dispatch(
+ PKIX_PL_HttpDefaultClient *client,
+ void *plCtx)
+{
+ PKIX_UInt32 bytesTransferred = 0;
+ PKIX_Boolean keepGoing = PKIX_TRUE;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Dispatch");
+ PKIX_NULLCHECK_ONE(client);
+
+ while (keepGoing) {
+ switch (client->connectStatus) {
+ case HTTP_CONNECT_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_ConnectContinue
+ (client, &keepGoing, plCtx),
+ PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED);
+ break;
+ case HTTP_CONNECTED:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_Send
+ (client, &keepGoing, &bytesTransferred, plCtx),
+ PKIX_HTTPDEFAULTCLIENTSENDFAILED);
+ break;
+ case HTTP_SEND_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue
+ (client, &keepGoing, &bytesTransferred, plCtx),
+ PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED);
+ break;
+ case HTTP_RECV_HDR:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr
+ (client, &keepGoing, plCtx),
+ PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED);
+ break;
+ case HTTP_RECV_HDR_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue
+ (client, &keepGoing, plCtx),
+ PKIX_HTTPDEFAULTCLIENTRECVHDRCONTINUEFAILED);
+ break;
+ case HTTP_RECV_BODY:
+ case HTTP_RECV_BODY_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvBody
+ (client, &keepGoing, plCtx),
+ PKIX_HTTPDEFAULTCLIENTRECVBODYFAILED);
+ break;
+ case HTTP_ERROR:
+ case HTTP_COMPLETE:
+ keepGoing = PKIX_FALSE;
+ break;
+ case HTTP_NOT_CONNECTED:
+ default:
+ PKIX_ERROR(PKIX_HTTPDEFAULTCLIENTINILLEGALSTATE);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * --HttpClient vtable functions
+ * See comments in ocspt.h for the function (wrappers) that return SECStatus.
+ * The functions that return PKIX_Error* are the libpkix implementations.
+ */
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_CreateSession(
+ const char *host,
+ PRUint16 portnum,
+ SEC_HTTP_SERVER_SESSION *pSession,
+ void *plCtx)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_CreateSession");
+ PKIX_NULLCHECK_TWO(host, pSession);
+
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_Create
+ (host, portnum, &client, plCtx),
+ PKIX_HTTPDEFAULTCLIENTCREATEFAILED);
+
+ *pSession = (SEC_HTTP_SERVER_SESSION)client;
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_KeepAliveSession(
+ SEC_HTTP_SERVER_SESSION session,
+ PRPollDesc **pPollDesc,
+ void *plCtx)
+{
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_KeepAliveSession");
+ PKIX_NULLCHECK_TWO(session, pPollDesc);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)session,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plCtx),
+ PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
+
+ /* XXX Not implemented */
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_RequestCreate(
+ SEC_HTTP_SERVER_SESSION session,
+ const char *http_protocol_variant, /* usually "http" */
+ const char *path_and_query_string,
+ const char *http_request_method,
+ const PRIntervalTime timeout,
+ SEC_HTTP_REQUEST_SESSION *pRequest,
+ void *plCtx)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+ PKIX_PL_Socket *socket = NULL;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ PRFileDesc *fileDesc = NULL;
+ PRErrorCode status = 0;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RequestCreate");
+ PKIX_NULLCHECK_TWO(session, pRequest);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)session,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plCtx),
+ PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)session;
+
+ /* We only know how to do http */
+ if (PORT_Strncasecmp(http_protocol_variant, "http", 4) != 0) {
+ PKIX_ERROR(PKIX_UNRECOGNIZEDPROTOCOLREQUESTED);
+ }
+
+ if (PORT_Strncasecmp(http_request_method, "POST", 4) == 0) {
+ client->send_http_method = HTTP_POST_METHOD;
+ } else if (PORT_Strncasecmp(http_request_method, "GET", 3) == 0) {
+ client->send_http_method = HTTP_GET_METHOD;
+ } else {
+ /* We only know how to do POST and GET */
+ PKIX_ERROR(PKIX_UNRECOGNIZEDREQUESTMETHOD);
+ }
+
+ if (path_and_query_string) {
+ /* "path_and_query_string" is a parsing result by CERT_GetURL
+ * function that adds "end of line" to the value. OK to dup
+ * the string. */
+ client->path = PORT_Strdup(path_and_query_string);
+ if (!client->path) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ }
+
+ client->timeout = timeout;
+
+#if 0
+ PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
+ (timeout,
+ "variation.red.iplanet.com", /* (char *)client->host, */
+ 2001, /* client->portnum, */
+ &status,
+ &socket,
+ plCtx),
+ PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
+#else
+ PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
+ (timeout,
+ (char *)client->host,
+ client->portnum,
+ &status,
+ &socket,
+ plCtx),
+ PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
+#endif
+
+ client->socket = socket;
+
+ PKIX_CHECK(pkix_pl_Socket_GetCallbackList
+ (socket, &callbackList, plCtx),
+ PKIX_SOCKETGETCALLBACKLISTFAILED);
+
+ client->callbackList = (void *)callbackList;
+
+ PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
+ (socket, &fileDesc, plCtx),
+ PKIX_SOCKETGETPRFILEDESCFAILED);
+
+ client->pollDesc.fd = fileDesc;
+ client->pollDesc.in_flags = 0;
+ client->pollDesc.out_flags = 0;
+
+ client->send_http_data = NULL;
+ client->send_http_data_len = 0;
+ client->send_http_content_type = NULL;
+
+ client->connectStatus =
+ ((status == 0) ? HTTP_CONNECTED : HTTP_CONNECT_PENDING);
+
+ /* Request object is the same object as Session object */
+ PKIX_INCREF(client);
+ *pRequest = client;
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_SetPostData(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_data,
+ const PRUint32 http_data_len,
+ const char *http_content_type,
+ void *plCtx)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_SetPostData");
+ PKIX_NULLCHECK_ONE(request);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)request,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plCtx),
+ PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)request;
+
+ client->send_http_data = http_data;
+ client->send_http_data_len = http_data_len;
+ client->send_http_content_type = http_content_type;
+
+ /* Caller is allowed to give NULL or empty string for content_type */
+ if ((client->send_http_content_type == NULL) ||
+ (*(client->send_http_content_type) == '\0')) {
+ client->send_http_content_type = "application/ocsp-request";
+ }
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_TrySendAndReceive(
+ SEC_HTTP_REQUEST_SESSION request,
+ PRUint16 *http_response_code,
+ const char **http_response_content_type,
+ const char **http_response_headers,
+ const char **http_response_data,
+ PRUint32 *http_response_data_len,
+ PRPollDesc **pPollDesc,
+ SECStatus *pSECReturn,
+ void *plCtx)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+ PKIX_UInt32 postLen = 0;
+ PRPollDesc *pollDesc = NULL;
+ char *sendbuf = NULL;
+ char portstr[16];
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_TrySendAndReceive");
+
+ PKIX_NULLCHECK_ONE(request);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)request,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plCtx),
+ PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)request;
+
+ if (!pPollDesc && client->timeout == 0) {
+ PKIX_ERROR_FATAL(PKIX_NULLARGUMENT);
+ }
+
+ if (pPollDesc) {
+ pollDesc = *pPollDesc;
+ }
+
+ /* if not continuing from an earlier WOULDBLOCK return... */
+ if (pollDesc == NULL) {
+
+ if (!((client->connectStatus == HTTP_CONNECTED) ||
+ (client->connectStatus == HTTP_CONNECT_PENDING))) {
+ PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
+ }
+
+ /* Did caller provide a value for response length? */
+ if (http_response_data_len != NULL) {
+ client->pRcv_http_data_len = http_response_data_len;
+ client->maxResponseLen = *http_response_data_len;
+ }
+
+ client->rcv_http_response_code = http_response_code;
+ client->rcv_http_content_type = http_response_content_type;
+ client->rcv_http_headers = http_response_headers;
+ client->rcv_http_data = http_response_data;
+
+ /* prepare the message */
+ portstr[0] = '\0';
+ if (client->portnum != 80) {
+ PR_snprintf(portstr, sizeof(portstr), ":%d",
+ client->portnum);
+ }
+
+ if (client->send_http_method == HTTP_POST_METHOD) {
+ sendbuf = PR_smprintf
+ ("POST %s HTTP/1.0\r\nHost: %s%s\r\n"
+ "Content-Type: %s\r\nContent-Length: %u\r\n\r\n",
+ client->path,
+ client->host,
+ portstr,
+ client->send_http_content_type,
+ client->send_http_data_len);
+ postLen = PORT_Strlen(sendbuf);
+
+ client->POSTLen = postLen + client->send_http_data_len;
+
+ /* allocate postBuffer big enough for header + data */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (client->POSTLen,
+ (void **)&(client->POSTBuf),
+ plCtx),
+ PKIX_MALLOCFAILED);
+
+ /* copy header into postBuffer */
+ PORT_Memcpy(client->POSTBuf, sendbuf, postLen);
+
+ /* append data after header */
+ PORT_Memcpy(&client->POSTBuf[postLen],
+ client->send_http_data,
+ client->send_http_data_len);
+
+ /* PR_smprintf_free original header buffer */
+ PR_smprintf_free(sendbuf);
+ sendbuf = NULL;
+
+ } else if (client->send_http_method == HTTP_GET_METHOD) {
+ client->GETBuf = PR_smprintf
+ ("GET %s HTTP/1.0\r\nHost: %s%s\r\n\r\n",
+ client->path,
+ client->host,
+ portstr);
+ client->GETLen = PORT_Strlen(client->GETBuf);
+ }
+
+ }
+
+ /* continue according to state */
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plCtx),
+ PKIX_HTTPDEFAULTCLIENTDISPATCHFAILED);
+
+ switch (client->connectStatus) {
+ case HTTP_CONNECT_PENDING:
+ case HTTP_SEND_PENDING:
+ case HTTP_RECV_HDR_PENDING:
+ case HTTP_RECV_BODY_PENDING:
+ pollDesc = &(client->pollDesc);
+ *pSECReturn = SECWouldBlock;
+ break;
+ case HTTP_ERROR:
+ /* Did caller provide a pointer for length? */
+ if (client->pRcv_http_data_len != NULL) {
+ /* Was error "response too big?" */
+ if (client->rcv_http_data_len !=
+ HTTP_UNKNOWN_CONTENT_LENGTH &&
+ client->maxResponseLen >=
+ client->rcv_http_data_len) {
+ /* Yes, report needed space */
+ *(client->pRcv_http_data_len) =
+ client->rcv_http_data_len;
+ } else {
+ /* No, report problem other than size */
+ *(client->pRcv_http_data_len) = 0;
+ }
+ }
+
+ pollDesc = NULL;
+ *pSECReturn = SECFailure;
+ break;
+ case HTTP_COMPLETE:
+ *(client->rcv_http_response_code) =
+ client->responseCode;
+ if (client->pRcv_http_data_len != NULL) {
+ *http_response_data_len =
+ client->rcv_http_data_len;
+ }
+ if (client->rcv_http_data != NULL) {
+ *(client->rcv_http_data) = client->rcvBuf;
+ }
+ pollDesc = NULL;
+ *pSECReturn = SECSuccess;
+ break;
+ case HTTP_NOT_CONNECTED:
+ case HTTP_CONNECTED:
+ case HTTP_RECV_HDR:
+ case HTTP_RECV_BODY:
+ default:
+ pollDesc = NULL;
+ *pSECReturn = SECFailure;
+ PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
+ break;
+ }
+
+ if (pPollDesc) {
+ *pPollDesc = pollDesc;
+ }
+
+cleanup:
+ if (sendbuf) {
+ PR_smprintf_free(sendbuf);
+ }
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_Cancel(
+ SEC_HTTP_REQUEST_SESSION request,
+ void *plCtx)
+{
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel");
+ PKIX_NULLCHECK_ONE(request);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)request,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plCtx),
+ PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
+
+ /* XXX Not implemented */
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_CreateSessionFcn(
+ const char *host,
+ PRUint16 portnum,
+ SEC_HTTP_SERVER_SESSION *pSession)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_CreateSession
+ (host, portnum, pSession, plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_KeepAliveSessionFcn(
+ SEC_HTTP_SERVER_SESSION session,
+ PRPollDesc **pPollDesc)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_KeepAliveSession
+ (session, pPollDesc, plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeSessionFcn(
+ SEC_HTTP_SERVER_SESSION session)
+{
+ PKIX_Error *err =
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)(session), plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_RequestCreateFcn(
+ SEC_HTTP_SERVER_SESSION session,
+ const char *http_protocol_variant, /* usually "http" */
+ const char *path_and_query_string,
+ const char *http_request_method,
+ const PRIntervalTime timeout,
+ SEC_HTTP_REQUEST_SESSION *pRequest)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_RequestCreate
+ (session,
+ http_protocol_variant,
+ path_and_query_string,
+ http_request_method,
+ timeout,
+ pRequest,
+ plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_SetPostDataFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_data,
+ const PRUint32 http_data_len,
+ const char *http_content_type)
+{
+ PKIX_Error *err =
+ pkix_pl_HttpDefaultClient_SetPostData(request, http_data,
+ http_data_len,
+ http_content_type,
+ plContext);
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_AddHeaderFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_header_name,
+ const char *http_header_value)
+{
+ /* Not supported */
+ return SECFailure;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ PRPollDesc **pPollDesc,
+ PRUint16 *http_response_code,
+ const char **http_response_content_type,
+ const char **http_response_headers,
+ const char **http_response_data,
+ PRUint32 *http_response_data_len)
+{
+ SECStatus rv = SECFailure;
+
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_TrySendAndReceive
+ (request,
+ http_response_code,
+ http_response_content_type,
+ http_response_headers,
+ http_response_data,
+ http_response_data_len,
+ pPollDesc,
+ &rv,
+ plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return rv;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_CancelFcn(
+ SEC_HTTP_REQUEST_SESSION request)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_Cancel(request, plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeFcn(
+ SEC_HTTP_REQUEST_SESSION request)
+{
+ PKIX_Error *err =
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)(request), plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h
new file mode 100644
index 0000000000..91916a0ab4
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h
@@ -0,0 +1,139 @@
+/* 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_httpdefaultclient.h
+ *
+ * HTTPDefaultClient Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_HTTPDEFAULTCLIENT_H
+#define _PKIX_PL_HTTPDEFAULTCLIENT_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HTTP_DATA_BUFSIZE 4096
+#define HTTP_HEADER_BUFSIZE 1024
+#define HTTP_MIN_AVAILABLE_BUFFER_SIZE 512
+
+typedef enum {
+ HTTP_NOT_CONNECTED,
+ HTTP_CONNECT_PENDING,
+ HTTP_CONNECTED,
+ HTTP_SEND_PENDING,
+ HTTP_RECV_HDR,
+ HTTP_RECV_HDR_PENDING,
+ HTTP_RECV_BODY,
+ HTTP_RECV_BODY_PENDING,
+ HTTP_COMPLETE,
+ HTTP_ERROR
+} HttpConnectStatus;
+
+typedef enum {
+ HTTP_POST_METHOD,
+ HTTP_GET_METHOD
+} HttpMethod;
+
+struct PKIX_PL_HttpDefaultClientStruct {
+ HttpConnectStatus connectStatus;
+ PRUint16 portnum;
+ PRIntervalTime timeout;
+ PKIX_UInt32 bytesToWrite;
+ PKIX_UInt32 send_http_data_len;
+ PKIX_UInt32 rcv_http_data_len;
+ PKIX_UInt32 capacity;
+ PKIX_UInt32 filledupBytes;
+ PKIX_UInt32 responseCode;
+ PKIX_UInt32 maxResponseLen;
+ PKIX_UInt32 GETLen;
+ PKIX_UInt32 POSTLen;
+ PRUint32 *pRcv_http_data_len;
+ PRPollDesc pollDesc;
+ void *callbackList; /* cast this to (PKIX_PL_Socket_Callback *) */
+ char *GETBuf;
+ char *POSTBuf;
+ char *rcvBuf;
+ char *host;
+ char *path;
+ char *rcvContentType;
+ void *rcvHeaders;
+ HttpMethod send_http_method;
+ const char *send_http_content_type;
+ const char *send_http_data;
+ PRUint16 *rcv_http_response_code;
+ const char **rcv_http_content_type;
+ const char **rcv_http_headers;
+ const char **rcv_http_data;
+ PKIX_PL_Socket *socket;
+ void *plContext;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_HttpDefaultClient_RegisterSelf(void *plContext);
+
+SECStatus
+pkix_pl_HttpDefaultClient_CreateSessionFcn(
+ const char *host,
+ PRUint16 portnum,
+ SEC_HTTP_SERVER_SESSION *pSession);
+
+SECStatus
+pkix_pl_HttpDefaultClient_KeepAliveSessionFcn(
+ SEC_HTTP_SERVER_SESSION session,
+ PRPollDesc **pPollDesc);
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeSessionFcn(
+ SEC_HTTP_SERVER_SESSION session);
+
+SECStatus
+pkix_pl_HttpDefaultClient_RequestCreateFcn(
+ SEC_HTTP_SERVER_SESSION session,
+ const char *http_protocol_variant, /* usually "http" */
+ const char *path_and_query_string,
+ const char *http_request_method,
+ const PRIntervalTime timeout,
+ SEC_HTTP_REQUEST_SESSION *pRequest);
+
+SECStatus
+pkix_pl_HttpDefaultClient_SetPostDataFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_data,
+ const PRUint32 http_data_len,
+ const char *http_content_type);
+
+SECStatus
+pkix_pl_HttpDefaultClient_AddHeaderFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_header_name,
+ const char *http_header_value);
+
+SECStatus
+pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ PRPollDesc **pPollDesc,
+ PRUint16 *http_response_code,
+ const char **http_response_content_type,
+ const char **http_response_headers,
+ const char **http_response_data,
+ PRUint32 *http_response_data_len);
+
+SECStatus
+pkix_pl_HttpDefaultClient_CancelFcn(
+ SEC_HTTP_REQUEST_SESSION request);
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeFcn(
+ SEC_HTTP_REQUEST_SESSION request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_HTTPDEFAULTCLIENT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c
new file mode 100644
index 0000000000..dd32334ab3
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c
@@ -0,0 +1,1113 @@
+/* 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_ldapcertstore.c
+ *
+ * LDAPCertStore Function Definitions
+ *
+ */
+
+/* We can't decode the length of a message without at least this many bytes */
+#define MINIMUM_MSG_LENGTH 5
+
+#include "pkix_pl_ldapcertstore.h"
+
+/* --Private-Ldap-CertStore-Database-Functions----------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_DecodeCrossCertPair
+ * DESCRIPTION:
+ *
+ * This function decodes a DER-encoded CrossCertPair pointed to by
+ * "responseList" and extracts and decodes the Certificates in that pair,
+ * adding the resulting Certs, if the decoding was successful, to the List
+ * (possibly empty) pointed to by "certList". If none of the objects
+ * can be decoded into a Cert, the List is returned unchanged.
+ *
+ * PARAMETERS:
+ * "derCCPItem"
+ * The address of the SECItem containing the DER representation of the
+ * CrossCertPair. Must be non-NULL.
+ * "certList"
+ * The address of the List to which the decoded Certs are added. May be
+ * empty, but 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 CertStore 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_LdapCertStore_DecodeCrossCertPair(
+ SECItem *derCCPItem,
+ PKIX_List *certList,
+ void *plContext)
+{
+ LDAPCertPair certPair = {{ siBuffer, NULL, 0 }, { siBuffer, NULL, 0 }};
+ SECStatus rv = SECFailure;
+
+ PLArenaPool *tempArena = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_DecodeCrossCertPair");
+ PKIX_NULLCHECK_TWO(derCCPItem, certList);
+
+ tempArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!tempArena) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ rv = SEC_ASN1DecodeItem(tempArena, &certPair, PKIX_PL_LDAPCrossCertPairTemplate,
+ derCCPItem);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ if (certPair.forward.data != NULL) {
+
+ PKIX_CHECK(
+ pkix_pl_Cert_CreateToList(&certPair.forward, certList,
+ plContext),
+ PKIX_CERTCREATETOLISTFAILED);
+ }
+
+ if (certPair.reverse.data != NULL) {
+
+ PKIX_CHECK(
+ pkix_pl_Cert_CreateToList(&certPair.reverse, certList,
+ plContext),
+ PKIX_CERTCREATETOLISTFAILED);
+ }
+
+cleanup:
+ if (tempArena) {
+ PORT_FreeArena(tempArena, PR_FALSE);
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_BuildCertList
+ * DESCRIPTION:
+ *
+ * This function takes a List of LdapResponse objects pointed to by
+ * "responseList" and extracts and decodes the Certificates in those responses,
+ * storing the List of those Certificates at "pCerts". If none of the objects
+ * can be decoded into a Cert, the returned List is empty.
+ *
+ * PARAMETERS:
+ * "responseList"
+ * The address of the List of LdapResponses. Must be non-NULL.
+ * "pCerts"
+ * The address at which the 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 a CertStore 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_LdapCertStore_BuildCertList(
+ PKIX_List *responseList,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_UInt32 numResponses = 0;
+ PKIX_UInt32 respIx = 0;
+ LdapAttrMask attrBits = 0;
+ PKIX_PL_LdapResponse *response = NULL;
+ PKIX_List *certList = NULL;
+ LDAPMessage *message = NULL;
+ LDAPSearchResponseEntry *sre = NULL;
+ LDAPSearchResponseAttr **sreAttrArray = NULL;
+ LDAPSearchResponseAttr *sreAttr = NULL;
+ SECItem *attrType = NULL;
+ SECItem **attrVal = NULL;
+ SECItem *derCertItem = NULL;
+
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCertList");
+ PKIX_NULLCHECK_TWO(responseList, pCerts);
+
+ PKIX_CHECK(PKIX_List_Create(&certList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* extract certs from response */
+ PKIX_CHECK(PKIX_List_GetLength
+ (responseList, &numResponses, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (respIx = 0; respIx < numResponses; respIx++) {
+ PKIX_CHECK(PKIX_List_GetItem
+ (responseList,
+ respIx,
+ (PKIX_PL_Object **)&response,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_GetMessage
+ (response, &message, plContext),
+ PKIX_LDAPRESPONSEGETMESSAGEFAILED);
+
+ sre = &(message->protocolOp.op.searchResponseEntryMsg);
+ sreAttrArray = sre->attributes;
+
+ /* Get next element of null-terminated array */
+ sreAttr = *sreAttrArray++;
+ while (sreAttr != NULL) {
+ attrType = &(sreAttr->attrType);
+ PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit
+ (attrType, &attrBits, plContext),
+ PKIX_LDAPREQUESTATTRTYPETOBITFAILED);
+ /* Is this attrVal a Certificate? */
+ if (((LDAPATTR_CACERT | LDAPATTR_USERCERT) &
+ attrBits) == attrBits) {
+ attrVal = sreAttr->val;
+ derCertItem = *attrVal++;
+ while (derCertItem != 0) {
+ /* create a PKIX_PL_Cert from derCert */
+ PKIX_CHECK(pkix_pl_Cert_CreateToList
+ (derCertItem, certList, plContext),
+ PKIX_CERTCREATETOLISTFAILED);
+ derCertItem = *attrVal++;
+ }
+ } else if ((LDAPATTR_CROSSPAIRCERT & attrBits) == attrBits){
+ /* Is this attrVal a CrossPairCertificate? */
+ attrVal = sreAttr->val;
+ derCertItem = *attrVal++;
+ while (derCertItem != 0) {
+ /* create PKIX_PL_Certs from derCert */
+ PKIX_CHECK(pkix_pl_LdapCertStore_DecodeCrossCertPair
+ (derCertItem, certList, plContext),
+ PKIX_LDAPCERTSTOREDECODECROSSCERTPAIRFAILED);
+ derCertItem = *attrVal++;
+ }
+ }
+ sreAttr = *sreAttrArray++;
+ }
+ PKIX_DECREF(response);
+ }
+
+ *pCerts = certList;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(certList);
+ }
+
+ PKIX_DECREF(response);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_BuildCrlList
+ * DESCRIPTION:
+ *
+ * This function takes a List of LdapResponse objects pointed to by
+ * "responseList" and extracts and decodes the CRLs in those responses, storing
+ * the List of those CRLs at "pCrls". If none of the objects can be decoded
+ * into a CRL, the returned List is empty.
+ *
+ * PARAMETERS:
+ * "responseList"
+ * The address of the List of LdapResponses. Must be non-NULL.
+ * "pCrls"
+ * The address at which the 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 a CertStore 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_LdapCertStore_BuildCrlList(
+ PKIX_List *responseList,
+ PKIX_List **pCrls,
+ void *plContext)
+{
+ PKIX_UInt32 numResponses = 0;
+ PKIX_UInt32 respIx = 0;
+ LdapAttrMask attrBits = 0;
+ CERTSignedCrl *nssCrl = NULL;
+ PKIX_PL_LdapResponse *response = NULL;
+ PKIX_List *crlList = NULL;
+ PKIX_PL_CRL *crl = NULL;
+ LDAPMessage *message = NULL;
+ LDAPSearchResponseEntry *sre = NULL;
+ LDAPSearchResponseAttr **sreAttrArray = NULL;
+ LDAPSearchResponseAttr *sreAttr = NULL;
+ SECItem *attrType = NULL;
+ SECItem **attrVal = NULL;
+ SECItem *derCrlCopy = NULL;
+ SECItem *derCrlItem = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCrlList");
+ PKIX_NULLCHECK_TWO(responseList, pCrls);
+
+ PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* extract crls from response */
+ PKIX_CHECK(PKIX_List_GetLength
+ (responseList, &numResponses, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (respIx = 0; respIx < numResponses; respIx++) {
+ PKIX_CHECK(PKIX_List_GetItem
+ (responseList,
+ respIx,
+ (PKIX_PL_Object **)&response,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_GetMessage
+ (response, &message, plContext),
+ PKIX_LDAPRESPONSEGETMESSAGEFAILED);
+
+ sre = &(message->protocolOp.op.searchResponseEntryMsg);
+ sreAttrArray = sre->attributes;
+
+ /* Get next element of null-terminated array */
+ sreAttr = *sreAttrArray++;
+ while (sreAttr != NULL) {
+ attrType = &(sreAttr->attrType);
+ PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit
+ (attrType, &attrBits, plContext),
+ PKIX_LDAPREQUESTATTRTYPETOBITFAILED);
+ /* Is this attrVal a Revocation List? */
+ if (((LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST) &
+ attrBits) == attrBits) {
+ attrVal = sreAttr->val;
+ derCrlItem = *attrVal++;
+ while (derCrlItem != 0) {
+ /* create a PKIX_PL_Crl from derCrl */
+ derCrlCopy = SECITEM_DupItem(derCrlItem);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ /* crl will be based on derCrlCopy, but wont
+ * own the der. */
+ nssCrl =
+ CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy,
+ SEC_CRL_TYPE,
+ CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_SKIP_ENTRIES);
+ if (!nssCrl) {
+ SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
+ continue;
+ }
+ /* pkix crl 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_AppendItem
+ (crlList, (PKIX_PL_Object *) crl, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(crl);
+ derCrlItem = *attrVal++;
+ }
+ /* Clean up after PKIX_CHECK_ONLY_FATAL */
+ pkixTempErrorReceived = PKIX_FALSE;
+ }
+ sreAttr = *sreAttrArray++;
+ }
+ PKIX_DECREF(response);
+ }
+
+ *pCrls = crlList;
+ crlList = NULL;
+cleanup:
+ if (derCrlCopy) {
+ SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
+ }
+ if (nssCrl) {
+ SEC_DestroyCrl(nssCrl);
+ }
+ PKIX_DECREF(crl);
+ PKIX_DECREF(crlList);
+ PKIX_DECREF(response);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_DestroyAVAList
+ * DESCRIPTION:
+ *
+ * This function frees the space allocated for the components of the
+ * equalFilters that make up the andFilter pointed to by "filter".
+ *
+ * PARAMETERS:
+ * "requestParams"
+ * The address of the andFilter whose components are to be freed. 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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapCertStore_DestroyAVAList(
+ LDAPNameComponent **nameComponents,
+ void *plContext)
+{
+ LDAPNameComponent **currentNC = NULL;
+ unsigned char *component = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_DestroyAVAList");
+ PKIX_NULLCHECK_ONE(nameComponents);
+
+ /* Set currentNC to point to first AVA pointer */
+ currentNC = nameComponents;
+
+ while ((*currentNC) != NULL) {
+ component = (*currentNC)->attrValue;
+ if (component != NULL) {
+ PORT_Free(component);
+ }
+ currentNC++;
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_MakeNameAVAList
+ * DESCRIPTION:
+ *
+ * This function allocates space from the arena pointed to by "arena" to
+ * construct a filter that will match components of the X500Name pointed to
+ * by "name", and stores the resulting filter at "pFilter".
+ *
+ * "name" is checked for commonName and organizationName components (cn=,
+ * and o=). The component strings are extracted using the family of
+ * CERT_Get* functions, and each must be freed with PORT_Free.
+ *
+ * It is not clear which components should be in a request, so, for now,
+ * we stop adding components after we have found one.
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in creating the filter. Must be
+ * non-NULL.
+ * "name"
+ * The address of the X500Name whose components define the desired
+ * matches. Must be non-NULL.
+ * "pList"
+ * The address at which the result is stored.
+ * "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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapCertStore_MakeNameAVAList(
+ PLArenaPool *arena,
+ PKIX_PL_X500Name *subjectName,
+ LDAPNameComponent ***pList,
+ void *plContext)
+{
+ LDAPNameComponent **setOfNameComponents;
+ LDAPNameComponent *currentNameComponent = NULL;
+ PKIX_UInt32 componentsPresent = 0;
+ void *v = NULL;
+ unsigned char *component = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_MakeNameAVAList");
+ PKIX_NULLCHECK_THREE(arena, subjectName, pList);
+
+ /* Increase this if additional components may be extracted */
+#define MAX_NUM_COMPONENTS 3
+
+ /* Space for (MAX_NUM_COMPONENTS + 1) pointers to LDAPNameComponents */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc,
+ (arena, (MAX_NUM_COMPONENTS + 1)*sizeof(LDAPNameComponent *)));
+ setOfNameComponents = (LDAPNameComponent **)v;
+
+ /* Space for MAX_NUM_COMPONENTS LDAPNameComponents */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray,
+ (arena, LDAPNameComponent, MAX_NUM_COMPONENTS));
+
+ currentNameComponent = (LDAPNameComponent *)v;
+
+ /* Try for commonName */
+ PKIX_CHECK(pkix_pl_X500Name_GetCommonName
+ (subjectName, &component, plContext),
+ PKIX_X500NAMEGETCOMMONNAMEFAILED);
+ if (component) {
+ setOfNameComponents[componentsPresent] = currentNameComponent;
+ currentNameComponent->attrType = (unsigned char *)"cn";
+ currentNameComponent->attrValue = component;
+ componentsPresent++;
+ currentNameComponent++;
+ }
+
+ /*
+ * The LDAP specification says we can send multiple name components
+ * in an "AND" filter, but the LDAP Servers don't seem to be able to
+ * handle such requests. So we'll quit after the cn component.
+ */
+#if 0
+ /* Try for orgName */
+ PKIX_CHECK(pkix_pl_X500Name_GetOrgName
+ (subjectName, &component, plContext),
+ PKIX_X500NAMEGETORGNAMEFAILED);
+ if (component) {
+ setOfNameComponents[componentsPresent] = currentNameComponent;
+ currentNameComponent->attrType = (unsigned char *)"o";
+ currentNameComponent->attrValue = component;
+ componentsPresent++;
+ currentNameComponent++;
+ }
+
+ /* Try for countryName */
+ PKIX_CHECK(pkix_pl_X500Name_GetCountryName
+ (subjectName, &component, plContext),
+ PKIX_X500NAMEGETCOUNTRYNAMEFAILED);
+ if (component) {
+ setOfNameComponents[componentsPresent] = currentNameComponent;
+ currentNameComponent->attrType = (unsigned char *)"c";
+ currentNameComponent->attrValue = component;
+ componentsPresent++;
+ currentNameComponent++;
+ }
+#endif
+
+ setOfNameComponents[componentsPresent] = NULL;
+
+ *pList = setOfNameComponents;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+
+}
+
+#if 0
+/*
+ * FUNCTION: pkix_pl_LdapCertstore_ConvertCertResponses
+ * DESCRIPTION:
+ *
+ * This function processes the List of LDAPResponses pointed to by "responses"
+ * into a List of resulting Certs, storing the result at "pCerts". If there
+ * are no responses converted successfully, a NULL may be stored.
+ *
+ * PARAMETERS:
+ * "responses"
+ * The LDAPResponses whose contents are to be converted. Must be non-NULL.
+ * "pCerts"
+ * Address at which the returned List 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 CertStore 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_LdapCertStore_ConvertCertResponses(
+ PKIX_List *responses,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_List *unfiltered = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_ConvertCertResponses");
+ PKIX_NULLCHECK_TWO(responses, pCerts);
+
+ /*
+ * We have a List of LdapResponse objects that have to be
+ * turned into Certs.
+ */
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (responses, &unfiltered, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+
+ *pCerts = unfiltered;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+}
+#endif
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCert
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCert(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ PLArenaPool *requestArena = NULL;
+ LDAPRequestParams requestParams;
+ void *pollDesc = NULL;
+ PKIX_Int32 minPathLen = 0;
+ PKIX_Boolean cacheFlag = PKIX_FALSE;
+ PKIX_ComCertSelParams *params = NULL;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_List *unfilteredCerts = NULL;
+ PKIX_List *filteredCerts = NULL;
+ PKIX_PL_X500Name *subjectName = 0;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCert");
+ PKIX_NULLCHECK_THREE(store, selector, pCertList);
+
+ requestParams.baseObject = "c=US";
+ requestParams.scope = WHOLE_SUBTREE;
+ requestParams.derefAliases = NEVER_DEREF;
+ requestParams.sizeLimit = 0;
+ requestParams.timeLimit = 0;
+
+ /* Prepare elements for request filter */
+
+ /*
+ * Get a short-lived arena. We'll be done with this space once
+ * the request is encoded.
+ */
+ requestArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!requestArena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (selector, &params, plContext),
+ PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED);
+
+ /*
+ * If we have the subject name for the desired subject,
+ * ask the server for Certs with that subject.
+ */
+ PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
+ (params, &subjectName, plContext),
+ PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetBasicConstraints
+ (params, &minPathLen, plContext),
+ PKIX_COMCERTSELPARAMSGETBASICCONSTRAINTSFAILED);
+
+ if (subjectName) {
+ PKIX_CHECK(pkix_pl_LdapCertStore_MakeNameAVAList
+ (requestArena,
+ subjectName,
+ &(requestParams.nc),
+ plContext),
+ PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED);
+
+ if (*requestParams.nc == NULL) {
+ /*
+ * The subjectName may not include any components
+ * that we know how to encode. We do not return
+ * an error, because the caller did not necessarily
+ * do anything wrong, but we return an empty List.
+ */
+ PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+
+ PKIX_CHECK(PKIX_List_Create(&filteredCerts, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (filteredCerts, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pNBIOContext = NULL;
+ *pCertList = filteredCerts;
+ filteredCerts = NULL;
+ goto cleanup;
+ }
+ } else {
+ PKIX_ERROR(PKIX_INSUFFICIENTCRITERIAFORCERTQUERY);
+ }
+
+ /* Prepare attribute field of request */
+
+ requestParams.attributes = 0;
+
+ if (minPathLen < 0) {
+ requestParams.attributes |= LDAPATTR_USERCERT;
+ }
+
+ if (minPathLen > -2) {
+ requestParams.attributes |=
+ LDAPATTR_CACERT | LDAPATTR_CROSSPAIRCERT;
+ }
+
+ /* All request fields are done */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
+ ((PKIX_PL_LdapClient *)lcs,
+ &requestParams,
+ &pollDesc,
+ &responses,
+ plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_DestroyAVAList
+ (requestParams.nc, plContext),
+ PKIX_LDAPCERTSTOREDESTROYAVALISTFAILED);
+
+ if (requestArena) {
+ PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+ requestArena = NULL;
+ }
+
+ if (pollDesc != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)pollDesc;
+ *pCertList = NULL;
+ goto cleanup;
+ }
+ /* LdapClient has given us a response! */
+
+ if (responses) {
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (store, &cacheFlag, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (responses, &unfilteredCerts, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+
+ PKIX_CHECK(pkix_CertSelector_Select
+ (selector, unfilteredCerts, &filteredCerts, plContext),
+ PKIX_CERTSELECTORSELECTFAILED);
+ }
+
+ *pNBIOContext = NULL;
+ *pCertList = filteredCerts;
+ filteredCerts = NULL;
+
+cleanup:
+
+ PKIX_DECREF(params);
+ PKIX_DECREF(subjectName);
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCerts);
+ PKIX_DECREF(filteredCerts);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCertContinue
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCertContinue(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ PKIX_Boolean cacheFlag = PKIX_FALSE;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ void *pollDesc = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_List *unfilteredCerts = NULL;
+ PKIX_List *filteredCerts = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCertContinue");
+ PKIX_NULLCHECK_THREE(store, selector, pCertList);
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
+ ((PKIX_PL_LdapClient *)lcs, &pollDesc, &responses, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+
+ if (pollDesc != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)pollDesc;
+ *pCertList = NULL;
+ goto cleanup;
+ }
+ /* LdapClient has given us a response! */
+
+ if (responses) {
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (store, &cacheFlag, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (responses, &unfilteredCerts, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+
+ PKIX_CHECK(pkix_CertSelector_Select
+ (selector, unfilteredCerts, &filteredCerts, plContext),
+ PKIX_CERTSELECTORSELECTFAILED);
+ }
+
+ *pNBIOContext = NULL;
+ *pCertList = filteredCerts;
+
+cleanup:
+
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCerts);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCRL
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCRL(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ LDAPRequestParams requestParams;
+ void *pollDesc = NULL;
+ PLArenaPool *requestArena = NULL;
+ PKIX_UInt32 numNames = 0;
+ PKIX_UInt32 thisName = 0;
+ PKIX_PL_CRL *candidate = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_List *issuerNames = NULL;
+ PKIX_List *filteredCRLs = NULL;
+ PKIX_List *unfilteredCRLs = NULL;
+ PKIX_PL_X500Name *issuer = NULL;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ PKIX_ComCRLSelParams *params = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRL");
+ PKIX_NULLCHECK_THREE(store, selector, pCrlList);
+
+ requestParams.baseObject = "c=US";
+ requestParams.scope = WHOLE_SUBTREE;
+ requestParams.derefAliases = NEVER_DEREF;
+ requestParams.sizeLimit = 0;
+ requestParams.timeLimit = 0;
+ requestParams.attributes = LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST;
+ /* Prepare elements for request filter */
+
+ /* XXX Place CRLDP code here. Handle the case when */
+ /* RFC 5280. Paragraph: 4.2.1.13: */
+ /* If the distributionPoint field contains a directoryName, the entry */
+ /* for that directoryName contains the current CRL for the associated */
+ /* reasons and the CRL is issued by the associated cRLIssuer. The CRL */
+ /* may be stored in either the certificateRevocationList or */
+ /* authorityRevocationList attribute. The CRL is to be obtained by the */
+ /* application from whatever directory server is locally configured. */
+ /* The protocol the application uses to access the directory (e.g., DAP */
+ /* or LDAP) is a local matter. */
+
+
+
+ /*
+ * Get a short-lived arena. We'll be done with this space once
+ * the request is encoded.
+ */
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE, requestArena, PORT_NewArena, (DER_DEFAULT_CHUNKSIZE));
+
+ if (!requestArena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CHECK(PKIX_CRLSelector_GetCommonCRLSelectorParams
+ (selector, &params, plContext),
+ PKIX_CRLSELECTORGETCOMCERTSELPARAMSFAILED);
+
+ PKIX_CHECK(PKIX_ComCRLSelParams_GetIssuerNames
+ (params, &issuerNames, plContext),
+ PKIX_COMCRLSELPARAMSGETISSUERNAMESFAILED);
+
+ /*
+ * The specification for PKIX_ComCRLSelParams_GetIssuerNames in
+ * pkix_crlsel.h says that if the criterion is not set we get a null
+ * pointer. If we get an empty List the criterion is impossible to
+ * meet ("must match at least one of the names in the List").
+ */
+ if (issuerNames) {
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (issuerNames, &numNames, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ if (numNames > 0) {
+ /*
+ * LDAP Servers don't seem to be able to handle
+ * requests with more than more than one name.
+ * So only use first name.
+ */
+ PKIX_CHECK(PKIX_List_GetItem
+ (issuerNames,
+ thisName,
+ (PKIX_PL_Object **)&issuer,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK
+ (pkix_pl_LdapCertStore_MakeNameAVAList
+ (requestArena,
+ issuer,
+ &(requestParams.nc),
+ plContext),
+ PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED);
+
+ PKIX_DECREF(issuer);
+
+ if (*requestParams.nc == NULL) {
+ /*
+ * The issuer may not include any
+ * components that we know how to
+ * encode. We do not return an error,
+ * because the caller did not
+ * necessarily do anything wrong, but
+ * we return an empty List.
+ */
+ PKIX_PL_NSSCALL
+ (CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+
+ PKIX_CHECK(PKIX_List_Create
+ (&filteredCRLs, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (filteredCRLs, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pNBIOContext = NULL;
+ *pCrlList = filteredCRLs;
+ goto cleanup;
+ }
+ } else {
+ PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY);
+ }
+ } else {
+ PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY);
+ }
+
+ /* All request fields are done */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
+ ((PKIX_PL_LdapClient *)lcs,
+ &requestParams,
+ &pollDesc,
+ &responses,
+ plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_DestroyAVAList
+ (requestParams.nc, plContext),
+ PKIX_LDAPCERTSTOREDESTROYAVALISTFAILED);
+
+ if (requestArena) {
+ PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+ }
+
+ if (pollDesc != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)pollDesc;
+ *pCrlList = NULL;
+ goto cleanup;
+ }
+ /* client has finished! */
+
+ if (responses) {
+
+ /*
+ * We have a List of LdapResponse objects that still have to be
+ * turned into Crls.
+ */
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList
+ (responses, &unfilteredCRLs, plContext),
+ PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED);
+
+ PKIX_CHECK(pkix_CRLSelector_Select
+ (selector, unfilteredCRLs, &filteredCRLs, plContext),
+ PKIX_CRLSELECTORSELECTFAILED);
+
+ }
+
+ /* Don't throw away the list if one CRL was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pNBIOContext = NULL;
+ *pCrlList = filteredCRLs;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(filteredCRLs);
+ }
+
+ PKIX_DECREF(params);
+ PKIX_DECREF(issuerNames);
+ PKIX_DECREF(issuer);
+ PKIX_DECREF(candidate);
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCRLs);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCRLContinue
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCRLContinue(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ void *nbio = NULL;
+ PKIX_PL_CRL *candidate = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ PKIX_List *filteredCRLs = NULL;
+ PKIX_List *unfilteredCRLs = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRLContinue");
+ PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList);
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
+ ((PKIX_PL_LdapClient *)lcs, &nbio, &responses, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+
+ if (nbio != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)nbio;
+ *pCrlList = NULL;
+ goto cleanup;
+ }
+ /* client has finished! */
+
+ if (responses) {
+
+ /*
+ * We have a List of LdapResponse objects that still have to be
+ * turned into Crls.
+ */
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList
+ (responses, &unfilteredCRLs, plContext),
+ PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED);
+
+ PKIX_CHECK(pkix_CRLSelector_Select
+ (selector, unfilteredCRLs, &filteredCRLs, plContext),
+ PKIX_CRLSELECTORSELECTFAILED);
+
+ PKIX_CHECK(PKIX_List_SetImmutable(filteredCRLs, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ }
+
+ /* Don't throw away the list if one CRL was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pCrlList = filteredCRLs;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(filteredCRLs);
+ }
+
+ PKIX_DECREF(candidate);
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCRLs);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/* --Public-LdapCertStore-Functions----------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_LdapCertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_LdapCertStore_Create(
+ PKIX_PL_LdapClient *client,
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_CertStore *certStore = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapCertStore_Create");
+ PKIX_NULLCHECK_TWO(client, pCertStore);
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_LdapCertStore_GetCert,
+ pkix_pl_LdapCertStore_GetCRL,
+ pkix_pl_LdapCertStore_GetCertContinue,
+ pkix_pl_LdapCertStore_GetCRLContinue,
+ NULL, /* don't support trust */
+ NULL, /* can not store crls */
+ NULL, /* can not do revocation check */
+ (PKIX_PL_Object *)client,
+ PKIX_TRUE, /* cache flag */
+ PKIX_FALSE, /* not local */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ *pCertStore = certStore;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h
new file mode 100644
index 0000000000..5bbe5385ca
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h
@@ -0,0 +1,75 @@
+/* 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_ldapcertstore.h
+ *
+ * LDAPCertstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPCERTSTORE_H
+#define _PKIX_PL_LDAPCERTSTORE_H
+
+#include "pkix_pl_ldapt.h"
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * At the time of this version, there are unresolved questions about the LDAP
+ * protocol. Although RFC1777 describes a BIND and UNBIND message, it is not
+ * clear whether they are appropriate to this application. We have tested only
+ * using servers that do not expect authentication, and that reject BIND
+ * messages. It is not clear what values might be appropriate for the bindname
+ * and authentication fields, which are currently implemented as char strings
+ * supplied by the caller. (If this changes, the API and possibly the templates
+ * will have to change.) Therefore the CertStore_Create API contains a BindAPI
+ * structure, a union, which will have to be revised and extended when this
+ * area of the protocol is better understood.
+ *
+ * It is further assumed that a given LdapCertStore will connect only to a
+ * single server, and that the creation of the socket will initiate the
+ * CONNECT. Therefore the LdapCertStore handles only the case of continuing
+ * the connection, if nonblocking I/O is being used.
+ */
+
+typedef enum {
+ LDAP_CONNECT_PENDING,
+ LDAP_CONNECTED,
+ LDAP_BIND_PENDING,
+ LDAP_BIND_RESPONSE,
+ LDAP_BIND_RESPONSE_PENDING,
+ LDAP_BOUND,
+ LDAP_SEND_PENDING,
+ LDAP_RECV,
+ LDAP_RECV_PENDING,
+ LDAP_RECV_INITIAL,
+ LDAP_RECV_NONINITIAL,
+ LDAP_ABANDON_PENDING
+} LDAPConnectStatus;
+
+#define LDAP_CACHEBUCKETS 128
+#define RCVBUFSIZE 512
+
+struct PKIX_PL_LdapCertStoreContext {
+ PKIX_PL_LdapClient *client;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_LdapCertStoreContext_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapCertStore_BuildCertList(
+ PKIX_List *responseList,
+ PKIX_List **pCerts,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPCERTSTORE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c
new file mode 100644
index 0000000000..9b6f8d688d
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c
@@ -0,0 +1,2494 @@
+/* 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_ldapdefaultclient.c
+ *
+ * LDAPDefaultClient Function Definitions
+ *
+ */
+
+/* We can't decode the length of a message without at least this many bytes */
+#define MINIMUM_MSG_LENGTH 5
+
+#include "pkix_pl_ldapdefaultclient.h"
+
+/* --Private-LdapDefaultClient-Message-Building-Functions---------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeBind
+ * DESCRIPTION:
+ *
+ * This function creates and encodes a Bind message, using the arena pointed
+ * to by "arena", the version number contained in "versionData", the
+ * LDAPBindAPI pointed to by "bindAPI", and the messageID contained in
+ * "msgNum", and stores a pointer to the encoded string at "pBindMsg".
+ *
+ * See pkix_pl_ldaptemplates.c for the ASN.1 description of a Bind message.
+ *
+ * This code is not used if the DefaultClient was created with a NULL pointer
+ * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be
+ * expected for anonymous Search requests.)
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in encoding the message. Must be
+ * non-NULL.
+ * "versionData"
+ * The Int32 containing the version number to be encoded in the Bind
+ * message.
+ * "bindAPI"
+ * The address of the LDAPBindAPI to be encoded in the Bind message. Must
+ * be non-NULL.
+ * "msgNum"
+ * The Int32 containing the MessageID to be encoded in the Bind message.
+ * "pBindMsg"
+ * The address at which the encoded Bind message will be 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeBind(
+ PLArenaPool *arena,
+ PKIX_Int32 versionData,
+ LDAPBindAPI *bindAPI,
+ PKIX_UInt32 msgNum,
+ SECItem **pBindMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ char version = '\0';
+ SECItem *encoded = NULL;
+ PKIX_UInt32 len = 0;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeBind");
+ PKIX_NULLCHECK_TWO(arena, pBindMsg);
+
+ PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset,
+ (&msg, 0, sizeof (LDAPMessage)));
+
+ version = (char)versionData;
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgNum;
+ msg.messageID.len = sizeof (msgNum);
+
+ msg.protocolOp.selector = LDAP_BIND_TYPE;
+
+ msg.protocolOp.op.bindMsg.version.type = siUnsignedInteger;
+ msg.protocolOp.op.bindMsg.version.data = (void *)&version;
+ msg.protocolOp.op.bindMsg.version.len = sizeof (char);
+
+ /*
+ * XXX At present we only know how to handle anonymous requests (no
+ * authentication), and we are guessing how to do simple authentication.
+ * This section will need to be revised and extended when other
+ * authentication is needed.
+ */
+ if (bindAPI->selector == SIMPLE_AUTH) {
+ msg.protocolOp.op.bindMsg.bindName.type = siAsciiString;
+ msg.protocolOp.op.bindMsg.bindName.data =
+ (void *)bindAPI->chooser.simple.bindName;
+ len = PL_strlen(bindAPI->chooser.simple.bindName);
+ msg.protocolOp.op.bindMsg.bindName.len = len;
+
+ msg.protocolOp.op.bindMsg.authentication.type = siAsciiString;
+ msg.protocolOp.op.bindMsg.authentication.data =
+ (void *)bindAPI->chooser.simple.authentication;
+ len = PL_strlen(bindAPI->chooser.simple.authentication);
+ msg.protocolOp.op.bindMsg.authentication.len = len;
+ }
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+ if (!encoded) {
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ *pBindMsg = encoded;
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeUnbind
+ * DESCRIPTION:
+ *
+ * This function creates and encodes a Unbind message, using the arena pointed
+ * to by "arena" and the messageID contained in "msgNum", and stores a pointer
+ * to the encoded string at "pUnbindMsg".
+ *
+ * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Unbind message.
+ *
+ * This code is not used if the DefaultClient was created with a NULL pointer
+ * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be
+ * expected for anonymous Search requests.)
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in encoding the message. Must be
+ * non-NULL.
+ * "msgNum"
+ * The Int32 containing the MessageID to be encoded in the Unbind message.
+ * "pUnbindMsg"
+ * The address at which the encoded Unbind message will be 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeUnbind(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgNum,
+ SECItem **pUnbindMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeUnbind");
+ PKIX_NULLCHECK_TWO(arena, pUnbindMsg);
+
+ PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset,
+ (&msg, 0, sizeof (LDAPMessage)));
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgNum;
+ msg.messageID.len = sizeof (msgNum);
+
+ msg.protocolOp.selector = LDAP_UNBIND_TYPE;
+
+ msg.protocolOp.op.unbindMsg.dummy.type = siBuffer;
+ msg.protocolOp.op.unbindMsg.dummy.data = NULL;
+ msg.protocolOp.op.unbindMsg.dummy.len = 0;
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+ if (!encoded) {
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ *pUnbindMsg = encoded;
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeAbandon
+ * DESCRIPTION:
+ *
+ * This function creates and encodes a Abandon message, using the arena pointed
+ * to by "arena" and the messageID contained in "msgNum", and stores a pointer
+ * to the encoded string at "pAbandonMsg".
+ *
+ * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Abandon message.
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in encoding the message. Must be
+ * non-NULL.
+ * "msgNum"
+ * The Int32 containing the MessageID to be encoded in the Abandon message.
+ * "pAbandonMsg"
+ * The address at which the encoded Abandon message will be 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeAbandon(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgNum,
+ SECItem **pAbandonMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeAbandon");
+ PKIX_NULLCHECK_TWO(arena, pAbandonMsg);
+
+ PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset,
+ (&msg, 0, sizeof (LDAPMessage)));
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgNum;
+ msg.messageID.len = sizeof (msgNum);
+
+ msg.protocolOp.selector = LDAP_ABANDONREQUEST_TYPE;
+
+ msg.protocolOp.op.abandonRequestMsg.messageID.type = siBuffer;
+ msg.protocolOp.op.abandonRequestMsg.messageID.data = (void*)&msgNum;
+ msg.protocolOp.op.abandonRequestMsg.messageID.len = sizeof (msgNum);
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+ if (!encoded) {
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ *pAbandonMsg = encoded;
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_DecodeBindResponse
+ * DESCRIPTION:
+ *
+ * This function decodes the encoded data pointed to by "src", using the arena
+ * pointed to by "arena", storing the decoded LDAPMessage at "pBindResponse"
+ * and the decoding status at "pStatus".
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool to be used in decoding the message. Must
+ * be non-NULL.
+ * "src"
+ * The address of the SECItem containing the DER- (or BER-)encoded string.
+ * Must be non-NULL.
+ * "pBindResponse"
+ * The address at which the LDAPMessage is stored, if the decoding is
+ * successful (the returned status is SECSuccess). Must be non-NULL.
+ * "pStatus"
+ * The address at which the decoding status 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_DecodeBindResponse(
+ PLArenaPool *arena,
+ SECItem *src,
+ LDAPMessage *pBindResponse,
+ SECStatus *pStatus,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+ LDAPMessage response;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_DecodeBindResponse");
+ PKIX_NULLCHECK_FOUR(arena, src, pBindResponse, pStatus);
+
+ PKIX_PL_NSSCALL
+ (LDAPDEFAULTCLIENT,
+ PORT_Memset,
+ (&response, 0, sizeof (LDAPMessage)));
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, rv, SEC_ASN1DecodeItem,
+ (arena, &response, PKIX_PL_LDAPMessageTemplate, src));
+
+ if (rv == SECSuccess) {
+ *pBindResponse = response;
+ }
+
+ *pStatus = rv;
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_VerifyBindResponse
+ * DESCRIPTION:
+ *
+ * This function verifies that the contents of the message in the rcvbuf of
+ * the LdapDefaultClient object pointed to by "client", and whose length is
+ * provided by "buflen", is a response to a successful Bind.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "buflen"
+ * The value of the number of bytes in the receive buffer.
+ * "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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_VerifyBindResponse(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_UInt32 bufLen,
+ void *plContext)
+{
+ SECItem decode = {siBuffer, NULL, 0};
+ SECStatus rv = SECFailure;
+ LDAPMessage msg;
+ LDAPBindResponse *ldapBindResponse = &msg.protocolOp.op.bindResponseMsg;
+
+ ldapBindResponse->resultCode.data = NULL;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_VerifyBindResponse");
+ PKIX_NULLCHECK_TWO(client, client->rcvBuf);
+
+ decode.data = (unsigned char *)(client->rcvBuf);
+ decode.len = bufLen;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_DecodeBindResponse
+ (client->arena, &decode, &msg, &rv, plContext),
+ PKIX_LDAPDEFAULTCLIENTDECODEBINDRESPONSEFAILED);
+
+ if (rv == SECSuccess) {
+ if (*(ldapBindResponse->resultCode.data) == SUCCESS) {
+ client->connectStatus = BOUND;
+ } else {
+ PKIX_ERROR(PKIX_BINDREJECTEDBYSERVER);
+ }
+ } else {
+ PKIX_ERROR(PKIX_CANTDECODEBINDRESPONSEFROMSERVER);
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvCheckComplete
+ * DESCRIPTION:
+ *
+ * This function determines whether the current response in the
+ * LdapDefaultClient pointed to by "client" is complete, in the sense that all
+ * bytes required to satisfy the message length field in the encoding have been
+ * received. If so, the pointer to input data is updated to reflect the number
+ * of bytes consumed, provided by "bytesProcessed". The state machine flag
+ * pointed to by "pKeepGoing" is updated to indicate whether processing can
+ * continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "bytesProcessed"
+ * The UInt32 value of the number of bytes consumed from the current
+ * buffer.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvCheckComplete(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_UInt32 bytesProcessed,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Boolean complete = PKIX_FALSE;
+ SECStatus rv = SECFailure;
+ LDAPMessageType messageType = 0;
+ LDAPResultCode resultCode = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_RecvCheckComplete");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_IsComplete
+ (client->currentResponse, &complete, plContext),
+ PKIX_LDAPRESPONSEISCOMPLETEFAILED);
+
+ if (complete) {
+ PKIX_CHECK(pkix_pl_LdapResponse_Decode
+ (client->arena, client->currentResponse, &rv, plContext),
+ PKIX_LDAPRESPONSEDECODEFAILED);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_CANTDECODESEARCHRESPONSEFROMSERVER);
+ }
+
+ PKIX_CHECK(pkix_pl_LdapResponse_GetMessageType
+ (client->currentResponse, &messageType, plContext),
+ PKIX_LDAPRESPONSEGETMESSAGETYPEFAILED);
+
+ if (messageType == LDAP_SEARCHRESPONSEENTRY_TYPE) {
+
+ if (client->entriesFound == NULL) {
+ PKIX_CHECK(PKIX_List_Create
+ (&(client->entriesFound), plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (client->entriesFound,
+ (PKIX_PL_Object *)client->currentResponse,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(client->currentResponse);
+
+ /* current receive buffer empty? */
+ if (client->currentBytesAvailable == 0) {
+ client->connectStatus = RECV;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = RECV_INITIAL;
+ client->currentInPtr = &((char *)
+ (client->currentInPtr))[bytesProcessed];
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ } else if (messageType == LDAP_SEARCHRESPONSERESULT_TYPE) {
+ PKIX_CHECK(pkix_pl_LdapResponse_GetResultCode
+ (client->currentResponse,
+ &resultCode,
+ plContext),
+ PKIX_LDAPRESPONSEGETRESULTCODEFAILED);
+
+ if ((client->entriesFound == NULL) &&
+ ((resultCode == SUCCESS) ||
+ (resultCode == NOSUCHOBJECT))) {
+ PKIX_CHECK(PKIX_List_Create
+ (&(client->entriesFound), plContext),
+ PKIX_LISTCREATEFAILED);
+ } else if (resultCode == SUCCESS) {
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (client->entriesFound, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+ PKIX_CHECK(PKIX_PL_HashTable_Add
+ (client->cachePtr,
+ (PKIX_PL_Object *)client->currentRequest,
+ (PKIX_PL_Object *)client->entriesFound,
+ plContext),
+ PKIX_HASHTABLEADDFAILED);
+ } else {
+ PKIX_ERROR(PKIX_UNEXPECTEDRESULTCODEINRESPONSE);
+ }
+
+ client->connectStatus = BOUND;
+ *pKeepGoing = PKIX_FALSE;
+ PKIX_DECREF(client->currentResponse);
+
+ } else {
+ PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE);
+ }
+ } else {
+ client->connectStatus = RECV;
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/* --Private-LdapDefaultClient-Object-Functions------------------------- */
+
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_InitiateRequest(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_ResumeRequest(
+ PKIX_PL_LdapClient *client,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_CreateHelper
+ * DESCRIPTION:
+ *
+ * This function creates a new LdapDefaultClient using the Socket pointed to
+ * by "socket", the PRIntervalTime pointed to by "timeout", and the
+ * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient".
+ *
+ * A value of zero for "timeout" means the LDAPClient will use non-blocking
+ * I/O.
+ *
+ * PARAMETERS:
+ * "socket"
+ * Address of the Socket to be used for the client. Must be non-NULL.
+ * "bindAPI"
+ * The address of the LDAPBindAPI containing the Bind information to be
+ * encoded in the Bind message.
+ * "pClient"
+ * The address at which the created LdapDefaultClient is to be 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 LdapDefaultClient 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_LdapDefaultClient_CreateHelper(
+ PKIX_PL_Socket *socket,
+ LDAPBindAPI *bindAPI,
+ PKIX_PL_LdapDefaultClient **pClient,
+ void *plContext)
+{
+ PKIX_PL_HashTable *ht;
+ PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL;
+ PKIX_PL_Socket_Callback *callbackList;
+ PRFileDesc *fileDesc = NULL;
+ PLArenaPool *arena = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_CreateHelper");
+ PKIX_NULLCHECK_TWO(socket, pClient);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_LDAPDEFAULTCLIENT_TYPE,
+ sizeof (PKIX_PL_LdapDefaultClient),
+ (PKIX_PL_Object **)&ldapDefaultClient,
+ plContext),
+ PKIX_COULDNOTCREATELDAPDEFAULTCLIENTOBJECT);
+
+ ldapDefaultClient->vtable.initiateFcn =
+ pkix_pl_LdapDefaultClient_InitiateRequest;
+ ldapDefaultClient->vtable.resumeFcn =
+ pkix_pl_LdapDefaultClient_ResumeRequest;
+
+ PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
+ (socket, &fileDesc, plContext),
+ PKIX_SOCKETGETPRFILEDESCFAILED);
+
+ ldapDefaultClient->pollDesc.fd = fileDesc;
+ ldapDefaultClient->pollDesc.in_flags = 0;
+ ldapDefaultClient->pollDesc.out_flags = 0;
+
+ ldapDefaultClient->bindAPI = bindAPI;
+
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (LDAP_CACHEBUCKETS, 0, &ht, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+ ldapDefaultClient->cachePtr = ht;
+
+ PKIX_CHECK(pkix_pl_Socket_GetCallbackList
+ (socket, &callbackList, plContext),
+ PKIX_SOCKETGETCALLBACKLISTFAILED);
+
+ ldapDefaultClient->callbackList = callbackList;
+
+ PKIX_INCREF(socket);
+ ldapDefaultClient->clientSocket = socket;
+
+ ldapDefaultClient->messageID = 0;
+
+ ldapDefaultClient->bindAPI = bindAPI;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+ ldapDefaultClient->arena = arena;
+
+ ldapDefaultClient->sendBuf = NULL;
+ ldapDefaultClient->bytesToWrite = 0;
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (RCVBUFSIZE, &ldapDefaultClient->rcvBuf, plContext),
+ PKIX_MALLOCFAILED);
+ ldapDefaultClient->capacity = RCVBUFSIZE;
+
+ ldapDefaultClient->bindMsg = NULL;
+ ldapDefaultClient->bindMsgLen = 0;
+
+ ldapDefaultClient->entriesFound = NULL;
+ ldapDefaultClient->currentRequest = NULL;
+ ldapDefaultClient->currentResponse = NULL;
+
+ *pClient = ldapDefaultClient;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(ldapDefaultClient);
+ }
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_LdapDefaultClient_Create
+ * DESCRIPTION:
+ *
+ * This function creates a new LdapDefaultClient using the PRNetAddr pointed to
+ * by "sockaddr", the PRIntervalTime pointed to by "timeout", and the
+ * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient".
+ *
+ * A value of zero for "timeout" means the LDAPClient will use non-blocking
+ * I/O.
+ *
+ * PARAMETERS:
+ * "sockaddr"
+ * Address of the PRNetAddr to be used for the socket connection. Must be
+ * non-NULL.
+ * "timeout"
+ * The PRIntervalTime to be used in I/O requests for this client.
+ * "bindAPI"
+ * The address of the LDAPBindAPI containing the Bind information to be
+ * encoded in the Bind message.
+ * "pClient"
+ * The address at which the created LdapDefaultClient is to be 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 LdapDefaultClient 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_LdapDefaultClient_Create(
+ PRNetAddr *sockaddr,
+ PRIntervalTime timeout,
+ LDAPBindAPI *bindAPI,
+ PKIX_PL_LdapDefaultClient **pClient,
+ void *plContext)
+{
+ PRErrorCode status = 0;
+ PKIX_PL_Socket *socket = NULL;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_Create");
+ PKIX_NULLCHECK_TWO(sockaddr, pClient);
+
+ PKIX_CHECK(pkix_pl_Socket_Create
+ (PKIX_FALSE, timeout, sockaddr, &status, &socket, plContext),
+ PKIX_SOCKETCREATEFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper
+ (socket, bindAPI, &client, plContext),
+ PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED);
+
+ /* Did Socket_Create say the connection was made? */
+ if (status == 0) {
+ if (client->bindAPI != NULL) {
+ client->connectStatus = CONNECTED;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ } else {
+ client->connectStatus = CONNECT_PENDING;
+ }
+
+ *pClient = client;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(client);
+ }
+
+ PKIX_DECREF(socket);
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_LdapDefaultClient_CreateByName
+ * DESCRIPTION:
+ *
+ * This function creates a new LdapDefaultClient using the hostname pointed to
+ * by "hostname", the PRIntervalTime pointed to by "timeout", and the
+ * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient".
+ *
+ * A value of zero for "timeout" means the LDAPClient will use non-blocking
+ * I/O.
+ *
+ * PARAMETERS:
+ * "hostname"
+ * Address of the hostname to be used for the socket connection. Must be
+ * non-NULL.
+ * "timeout"
+ * The PRIntervalTime to be used in I/O requests for this client.
+ * "bindAPI"
+ * The address of the LDAPBindAPI containing the Bind information to be
+ * encoded in the Bind message.
+ * "pClient"
+ * The address at which the created LdapDefaultClient is to be 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 LdapDefaultClient 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_LdapDefaultClient_CreateByName(
+ char *hostname,
+ PRIntervalTime timeout,
+ LDAPBindAPI *bindAPI,
+ PKIX_PL_LdapDefaultClient **pClient,
+ void *plContext)
+{
+ PRErrorCode status = 0;
+ PKIX_PL_Socket *socket = NULL;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_CreateByName");
+ PKIX_NULLCHECK_TWO(hostname, pClient);
+
+ PKIX_CHECK(pkix_pl_Socket_CreateByName
+ (PKIX_FALSE, timeout, hostname, &status, &socket, plContext),
+ PKIX_SOCKETCREATEBYNAMEFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper
+ (socket, bindAPI, &client, plContext),
+ PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED);
+
+ /* Did Socket_Create say the connection was made? */
+ if (status == 0) {
+ if (client->bindAPI != NULL) {
+ client->connectStatus = CONNECTED;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ } else {
+ client->connectStatus = CONNECT_PENDING;
+ }
+
+ *pClient = client;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(client);
+ }
+
+ PKIX_DECREF(socket);
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext),
+ PKIX_OBJECTNOTANLDAPDEFAULTCLIENT);
+
+ client = (PKIX_PL_LdapDefaultClient *)object;
+
+ switch (client->connectStatus) {
+ case CONNECT_PENDING:
+ break;
+ case CONNECTED:
+ case BIND_PENDING:
+ case BIND_RESPONSE:
+ case BIND_RESPONSE_PENDING:
+ case BOUND:
+ case SEND_PENDING:
+ case RECV:
+ case RECV_PENDING:
+ case RECV_INITIAL:
+ case RECV_NONINITIAL:
+ case ABANDON_PENDING:
+ if (client->bindAPI != NULL) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeUnbind
+ (client->arena,
+ ++(client->messageID),
+ &encoded,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEUNBINDFAILED);
+
+ callbackList =
+ (PKIX_PL_Socket_Callback *)(client->callbackList);
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ encoded->data,
+ encoded->len,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+ }
+ break;
+ default:
+ PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTINILLEGALSTATE);
+ }
+
+ PKIX_DECREF(client->cachePtr);
+ PKIX_DECREF(client->clientSocket);
+ PKIX_DECREF(client->entriesFound);
+ PKIX_DECREF(client->currentRequest);
+ PKIX_DECREF(client->currentResponse);
+
+ PKIX_CHECK(PKIX_PL_Free
+ (client->rcvBuf, plContext), PKIX_FREEFAILED);
+
+ PKIX_PL_NSSCALL
+ (LDAPDEFAULTCLIENT,
+ PORT_FreeArena,
+ (client->arena, PR_FALSE));
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL;
+ PKIX_UInt32 tempHash = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext),
+ PKIX_OBJECTNOTANLDAPDEFAULTCLIENT);
+
+ ldapDefaultClient = (PKIX_PL_LdapDefaultClient *)object;
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode
+ ((PKIX_PL_Object *)ldapDefaultClient->clientSocket,
+ &tempHash,
+ plContext),
+ PKIX_SOCKETHASHCODEFAILED);
+
+ if (ldapDefaultClient->bindAPI != NULL) {
+ tempHash = (tempHash << 7) +
+ ldapDefaultClient->bindAPI->selector;
+ }
+
+ *pHashcode = tempHash;
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_LdapDefaultClient *firstClientContext = NULL;
+ PKIX_PL_LdapDefaultClient *secondClientContext = NULL;
+ PKIX_Int32 compare = 0;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ *pResult = PKIX_FALSE;
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject,
+ secondObject,
+ PKIX_LDAPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_OBJECTNOTANLDAPDEFAULTCLIENT);
+
+ firstClientContext = (PKIX_PL_LdapDefaultClient *)firstObject;
+ secondClientContext = (PKIX_PL_LdapDefaultClient *)secondObject;
+
+ if (firstClientContext == secondClientContext) {
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Equals
+ ((PKIX_PL_Object *)firstClientContext->clientSocket,
+ (PKIX_PL_Object *)secondClientContext->clientSocket,
+ &compare,
+ plContext),
+ PKIX_SOCKETEQUALSFAILED);
+
+ if (!compare) {
+ goto cleanup;
+ }
+
+ if (PKIX_EXACTLY_ONE_NULL
+ (firstClientContext->bindAPI, secondClientContext->bindAPI)) {
+ goto cleanup;
+ }
+
+ if (firstClientContext->bindAPI) {
+ if (firstClientContext->bindAPI->selector !=
+ secondClientContext->bindAPI->selector) {
+ goto cleanup;
+ }
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_LDAPDEFAULTCLIENT_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_LdapDefaultClient_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_RegisterSelf");
+
+ entry.description = "LdapDefaultClient";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_LdapDefaultClient);
+ entry.destructor = pkix_pl_LdapDefaultClient_Destroy;
+ entry.equalsFunction = pkix_pl_LdapDefaultClient_Equals;
+ entry.hashcodeFunction = pkix_pl_LdapDefaultClient_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_LDAPDEFAULTCLIENT_TYPE] = entry;
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_GetPollDesc
+ * DESCRIPTION:
+ *
+ * This function retrieves the PRPollDesc from the LdapDefaultClient
+ * pointed to by "context" and stores the address at "pPollDesc".
+ *
+ * PARAMETERS:
+ * "context"
+ * The LdapDefaultClient whose PRPollDesc is desired. Must be non-NULL.
+ * "pPollDesc"
+ * Address where PRPollDesc will be 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 Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapDefaultClient_GetPollDesc(
+ PKIX_PL_LdapDefaultClient *context,
+ PRPollDesc **pPollDesc,
+ void *plContext)
+{
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_GetPollDesc");
+ PKIX_NULLCHECK_TWO(context, pPollDesc);
+
+ *pPollDesc = &(context->pollDesc);
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/* --Private-Ldap-CertStore-I/O-Functions---------------------------- */
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_ConnectContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether a socket Connect initiated earlier for the
+ * CertStore embodied in the LdapDefaultClient "client" has completed, and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_ConnectContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_PL_Socket_Callback *callbackList;
+ PRErrorCode status;
+ PKIX_Boolean keepGoing = PKIX_FALSE;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_ConnectContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->connectcontinueCallback
+ (client->clientSocket, &status, plContext),
+ PKIX_SOCKETCONNECTCONTINUEFAILED);
+
+ if (status == 0) {
+ if (client->bindAPI != NULL) {
+ client->connectStatus = CONNECTED;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ keepGoing = PKIX_FALSE;
+ } else if (status != PR_IN_PROGRESS_ERROR) {
+ PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION);
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = keepGoing;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Bind
+ * DESCRIPTION:
+ *
+ * This function creates and sends the LDAP-protocol Bind message for the
+ * CertStore embodied in the LdapDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Bind(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ SECItem *encoded = NULL;
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Bind");
+ PKIX_NULLCHECK_ONE(client);
+
+ /* if we have not yet constructed the BIND message, build it now */
+ if (!(client->bindMsg)) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeBind
+ (client->arena,
+ 3,
+ client->bindAPI,
+ client->messageID,
+ &encoded,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEBINDFAILED);
+ client->bindMsg = encoded->data;
+ client->bindMsgLen = encoded->len;
+ }
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ client->bindMsg,
+ client->bindMsgLen,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+
+ client->lastIO = PR_Now();
+
+ if (bytesWritten < 0) {
+ client->connectStatus = BIND_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ } else {
+ client->connectStatus = BIND_RESPONSE;
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_BindContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the LDAP-protocol Bind message for the
+ * CertStore embodied in the LdapDefaultClient "client" has completed, and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient 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_LdapDefaultClient_BindContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, &bytesWritten, NULL, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * continue to poll.
+ */
+ if (bytesWritten >= 0) {
+
+ client->connectStatus = BIND_RESPONSE;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_BindResponse
+ * DESCRIPTION:
+ *
+ * This function attempts to read the LDAP-protocol BindResponse message for
+ * the CertStore embodied in the LdapDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input.
+ *
+ * If a BindResponse is received with a Result code of 0 (success), we
+ * continue with the connection. If a non-zero Result code is received,
+ * we throw an Error. Some more sophisticated handling of that condition
+ * might be in order in the future.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_BindResponse(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindResponse");
+ PKIX_NULLCHECK_TWO(client, client->rcvBuf);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->recvCallback
+ (client->clientSocket,
+ client->rcvBuf,
+ client->capacity,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+
+ client->lastIO = PR_Now();
+
+ if (bytesRead > 0) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse
+ (client, bytesRead, plContext),
+ PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED);
+ /*
+ * XXX What should we do if failure? At present if
+ * VerifyBindResponse throws an Error, we do too.
+ */
+ client->connectStatus = BOUND;
+ } else {
+ client->connectStatus = BIND_RESPONSE_PENDING;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_BindResponseContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the LDAP-protocol BindResponse message for
+ * the CertStore embodied in the LdapDefaultClient "client" has completed, and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_BindResponseContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_BindResponseContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, NULL, &bytesRead, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesRead > 0) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse
+ (client, bytesRead, plContext),
+ PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED);
+ client->connectStatus = BOUND;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Send
+ * DESCRIPTION:
+ *
+ * This function creates and sends an LDAP-protocol message for the
+ * CertStore embodied in the LdapDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input, and at "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Send(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Send");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ /* Do we have anything waiting to go? */
+ if (client->sendBuf) {
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ client->sendBuf,
+ client->bytesToWrite,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+
+ client->lastIO = PR_Now();
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * to poll for completion later.
+ */
+ if (bytesWritten >= 0) {
+ client->sendBuf = NULL;
+ client->connectStatus = RECV;
+ *pKeepGoing = PKIX_TRUE;
+
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ client->connectStatus = SEND_PENDING;
+ }
+
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_SendContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the sending of the LDAP-protocol message
+ * for the CertStore embodied in the LdapDefaultClient "client" has completed,
+ * and stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input, and at "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_SendContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_SendContinue");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, &bytesWritten, NULL, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * continue to poll.
+ */
+ if (bytesWritten >= 0) {
+ client->sendBuf = NULL;
+ client->connectStatus = RECV;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Recv
+ * DESCRIPTION:
+ *
+ * This function receives an LDAP-protocol message for the CertStore embodied
+ * in the LdapDefaultClient "client", and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Recv(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_UInt32 bytesToRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Recv");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, client->rcvBuf);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ /*
+ * If we attempt to fill our buffer with every read, we increase
+ * the risk of an ugly situation: one or two bytes of a new message
+ * left over at the end of processing one message. With such a
+ * fragment, we can't decode a byte count and so won't know how much
+ * space to allocate for the next LdapResponse. We try to avoid that
+ * case by reading just enough to complete the current message, unless
+ * there will be at least MINIMUM_MSG_LENGTH bytes left over.
+ */
+ if (client->currentResponse) {
+ PKIX_CHECK(pkix_pl_LdapResponse_GetCapacity
+ (client->currentResponse, &bytesToRead, plContext),
+ PKIX_LDAPRESPONSEGETCAPACITYFAILED);
+ if ((bytesToRead > client->capacity) ||
+ ((bytesToRead + MINIMUM_MSG_LENGTH) < client->capacity)) {
+ bytesToRead = client->capacity;
+ }
+ } else {
+ bytesToRead = client->capacity;
+ }
+
+ client->currentBytesAvailable = 0;
+
+ PKIX_CHECK(callbackList->recvCallback
+ (client->clientSocket,
+ (void *)client->rcvBuf,
+ bytesToRead,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+
+ client->currentInPtr = client->rcvBuf;
+ client->lastIO = PR_Now();
+
+ if (bytesRead > 0) {
+ client->currentBytesAvailable = bytesRead;
+ client->connectStatus = RECV_INITIAL;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = RECV_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the receiving of the LDAP-protocol message
+ * for the CertStore embodied in the LdapDefaultClient "client" has completed,
+ * and stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvContinue");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, NULL, &bytesRead, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesRead > 0) {
+ client->currentBytesAvailable += bytesRead;
+ client->connectStatus = RECV_INITIAL;
+ *pKeepGoing = PKIX_TRUE;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_AbandonContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the abandon-message request of the
+ * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient
+ * "client" has completed, and stores in "pKeepGoing" a flag indicating whether
+ * processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_AbandonContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_AbandonContinue");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, &bytesWritten, NULL, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesWritten > 0) {
+ client->connectStatus = BOUND;
+ *pKeepGoing = PKIX_TRUE;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvInitial
+ * DESCRIPTION:
+ *
+ * This function processes the contents of the first buffer of a received
+ * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient
+ * "client", and stores in "pKeepGoing" a flag indicating whether processing can
+ * continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvInitial(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ unsigned char *msgBuf = NULL;
+ unsigned char *to = NULL;
+ unsigned char *from = NULL;
+ PKIX_UInt32 dataIndex = 0;
+ PKIX_UInt32 messageIdLen = 0;
+ PKIX_UInt32 messageLength = 0;
+ PKIX_UInt32 sizeofLength = 0;
+ PKIX_UInt32 bytesProcessed = 0;
+ unsigned char messageChar = 0;
+ LDAPMessageType messageType = 0;
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvInitial");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ /*
+ * Is there an LDAPResponse in progress? I.e., have we
+ * already processed the tag and length at the beginning of
+ * the message?
+ */
+ if (client->currentResponse) {
+ client->connectStatus = RECV_NONINITIAL;
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+ msgBuf = client->currentInPtr;
+
+ /* Do we have enough of the message to decode the message length? */
+ if (client->currentBytesAvailable < MINIMUM_MSG_LENGTH) {
+ /*
+ * No! Move these few bytes to the beginning of rcvBuf
+ * and hang another read.
+ */
+
+ to = (unsigned char *)client->rcvBuf;
+ from = client->currentInPtr;
+ for (dataIndex = 0;
+ dataIndex < client->currentBytesAvailable;
+ dataIndex++) {
+ *to++ = *from++;
+ }
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+ PKIX_CHECK(callbackList->recvCallback
+ (client->clientSocket,
+ (void *)to,
+ client->capacity - client->currentBytesAvailable,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+
+ client->currentInPtr = client->rcvBuf;
+ client->lastIO = PR_Now();
+
+ if (bytesRead <= 0) {
+ client->connectStatus = RECV_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ goto cleanup;
+ } else {
+ client->currentBytesAvailable += bytesRead;
+ }
+ }
+
+ /*
+ * We have to determine whether the response is an entry, with
+ * application-specific tag LDAP_SEARCHRESPONSEENTRY_TYPE, or a
+ * resultCode, with application tag LDAP_SEARCHRESPONSERESULT_TYPE.
+ * First, we have to figure out where to look for the tag.
+ */
+
+ /* Is the message length short form (one octet) or long form? */
+ if ((msgBuf[1] & 0x80) != 0) {
+ sizeofLength = msgBuf[1] & 0x7F;
+ for (dataIndex = 0; dataIndex < sizeofLength; dataIndex++) {
+ messageLength =
+ (messageLength << 8) + msgBuf[dataIndex + 2];
+ }
+ } else {
+ messageLength = msgBuf[1];
+ }
+
+ /* How many bytes did the messageID require? */
+ messageIdLen = msgBuf[dataIndex + 3];
+
+ messageChar = msgBuf[dataIndex + messageIdLen + 4];
+
+ /* Are we looking at an Entry message or a ResultCode message? */
+ if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION |
+ LDAP_SEARCHRESPONSEENTRY_TYPE) == messageChar) {
+
+ messageType = LDAP_SEARCHRESPONSEENTRY_TYPE;
+
+ } else if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION |
+ LDAP_SEARCHRESPONSERESULT_TYPE) == messageChar) {
+
+ messageType = LDAP_SEARCHRESPONSERESULT_TYPE;
+
+ } else {
+
+ PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE);
+
+ }
+
+ /*
+ * messageLength is the length from (tag, length, value).
+ * We have to allocate space for the tag and length bits too.
+ */
+ PKIX_CHECK(pkix_pl_LdapResponse_Create
+ (messageType,
+ messageLength + dataIndex + 2,
+ client->currentBytesAvailable,
+ msgBuf,
+ &bytesProcessed,
+ &(client->currentResponse),
+ plContext),
+ PKIX_LDAPRESPONSECREATEFAILED);
+
+ client->currentBytesAvailable -= bytesProcessed;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete
+ (client, bytesProcessed, pKeepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED);
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvNonInitial
+ * DESCRIPTION:
+ *
+ * This function processes the contents of buffers, after the first, of a
+ * received LDAP-protocol message for the CertStore embodied in the
+ * LdapDefaultClient "client", and stores in "pKeepGoing" a flag indicating
+ * whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvNonInitial(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+
+ PKIX_UInt32 bytesProcessed = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvNonInitial");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_Append
+ (client->currentResponse,
+ client->currentBytesAvailable,
+ client->currentInPtr,
+ &bytesProcessed,
+ plContext),
+ PKIX_LDAPRESPONSEAPPENDFAILED);
+
+ client->currentBytesAvailable -= bytesProcessed;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete
+ (client, bytesProcessed, pKeepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED);
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Dispatch
+ * DESCRIPTION:
+ *
+ * This function is the state machine dispatcher for the CertStore embodied in
+ * the LdapDefaultClient pointed to by "client". Results are returned by
+ * changes to various fields in the context.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Dispatch(
+ PKIX_PL_LdapDefaultClient *client,
+ void *plContext)
+{
+ PKIX_UInt32 bytesTransferred = 0;
+ PKIX_Boolean keepGoing = PKIX_TRUE;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Dispatch");
+ PKIX_NULLCHECK_ONE(client);
+
+ while (keepGoing) {
+ switch (client->connectStatus) {
+ case CONNECT_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_ConnectContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTCONNECTCONTINUEFAILED);
+ break;
+ case CONNECTED:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_Bind
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDFAILED);
+ break;
+ case BIND_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_BindContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDCONTINUEFAILED);
+ break;
+ case BIND_RESPONSE:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_BindResponse
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDRESPONSEFAILED);
+ break;
+ case BIND_RESPONSE_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_BindResponseContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDRESPONSECONTINUEFAILED);
+ break;
+ case BOUND:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_Send
+ (client, &keepGoing, &bytesTransferred, plContext),
+ PKIX_LDAPDEFAULTCLIENTSENDFAILED);
+ break;
+ case SEND_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_SendContinue
+ (client, &keepGoing, &bytesTransferred, plContext),
+ PKIX_LDAPDEFAULTCLIENTSENDCONTINUEFAILED);
+ break;
+ case RECV:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_Recv
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVFAILED);
+ break;
+ case RECV_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_RecvContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVCONTINUEFAILED);
+ break;
+ case RECV_INITIAL:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_RecvInitial
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVINITIALFAILED);
+ break;
+ case RECV_NONINITIAL:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_RecvNonInitial
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVNONINITIALFAILED);
+ break;
+ case ABANDON_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_AbandonContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTABANDONCONTINUEFAILED);
+ break;
+ default:
+ PKIX_ERROR(PKIX_LDAPCERTSTOREINILLEGALSTATE);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeAndFilter
+ * DESCRIPTION:
+ *
+ * This function allocates space from the arena pointed to by "arena" to
+ * construct a filter that will match components of the X500Name pointed to by
+ * XXX...
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in creating the filter. Must be
+ * non-NULL.
+ * "nameComponent"
+ * The address of a NULL-terminated list of LDAPNameComponents
+ * Must be non-NULL.
+ * "pFilter"
+ * The address at which the result is stored.
+ * "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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeAndFilter(
+ PLArenaPool *arena,
+ LDAPNameComponent **nameComponents,
+ LDAPFilter **pFilter,
+ void *plContext)
+{
+ LDAPFilter **setOfFilter;
+ LDAPFilter *andFilter = NULL;
+ LDAPFilter *currentFilter = NULL;
+ PKIX_UInt32 componentsPresent = 0;
+ void *v = NULL;
+ unsigned char *component = NULL;
+ LDAPNameComponent **componentP = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapDefaultClient_MakeAndFilter");
+ PKIX_NULLCHECK_THREE(arena, nameComponents, pFilter);
+
+ /* count how many components we were provided */
+ for (componentP = nameComponents, componentsPresent = 0;
+ *(componentP++) != NULL;
+ componentsPresent++) {}
+
+ /* Space for (componentsPresent + 1) pointers to LDAPFilter */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc,
+ (arena, (componentsPresent + 1)*sizeof(LDAPFilter *)));
+ setOfFilter = (LDAPFilter **)v;
+
+ /* Space for AndFilter and <componentsPresent> EqualFilters */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray,
+ (arena, LDAPFilter, componentsPresent + 1));
+ setOfFilter[0] = (LDAPFilter *)v;
+
+ /* Claim the first array element for the ANDFilter */
+ andFilter = setOfFilter[0];
+
+ /* Set ANDFilter to point to the first EqualFilter pointer */
+ andFilter->selector = LDAP_ANDFILTER_TYPE;
+ andFilter->filter.andFilter.filters = setOfFilter;
+
+ currentFilter = andFilter + 1;
+
+ for (componentP = nameComponents, componentsPresent = 0;
+ *(componentP) != NULL; componentP++) {
+ setOfFilter[componentsPresent++] = currentFilter;
+ currentFilter->selector = LDAP_EQUALFILTER_TYPE;
+ component = (*componentP)->attrType;
+ currentFilter->filter.equalFilter.attrType.data = component;
+ currentFilter->filter.equalFilter.attrType.len =
+ PL_strlen((const char *)component);
+ component = (*componentP)->attrValue;
+ currentFilter->filter.equalFilter.attrValue.data = component;
+ currentFilter->filter.equalFilter.attrValue.len =
+ PL_strlen((const char *)component);
+ currentFilter++;
+ }
+
+ setOfFilter[componentsPresent] = NULL;
+
+ *pFilter = andFilter;
+
+ PKIX_RETURN(CERTSTORE);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_InitiateRequest
+ * DESCRIPTION:
+ *
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "requestParams"
+ * The address of an LdapClientParams object. Must be non-NULL.
+ * "pPollDesc"
+ * The location where the address of the PRPollDesc is stored, if the
+ * client returns with I/O pending.
+ * "pResponse"
+ * The address where the List of LDAPResponses, or NULL for an
+ * unfinished request, 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_InitiateRequest(
+ PKIX_PL_LdapClient *genericClient,
+ LDAPRequestParams *requestParams,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_List *searchResponseList = NULL;
+ SECItem *encoded = NULL;
+ LDAPFilter *filter = NULL;
+ PKIX_PL_LdapDefaultClient *client = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_InitiateRequest");
+ PKIX_NULLCHECK_FOUR(genericClient, requestParams, pPollDesc, pResponse);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)genericClient,
+ PKIX_LDAPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT);
+
+ client = (PKIX_PL_LdapDefaultClient *)genericClient;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAndFilter
+ (client->arena, requestParams->nc, &filter, plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEANDFILTERFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapRequest_Create
+ (client->arena,
+ client->messageID++,
+ requestParams->baseObject,
+ requestParams->scope,
+ requestParams->derefAliases,
+ requestParams->sizeLimit,
+ requestParams->timeLimit,
+ PKIX_FALSE, /* attrs only */
+ filter,
+ requestParams->attributes,
+ &client->currentRequest,
+ plContext),
+ PKIX_LDAPREQUESTCREATEFAILED);
+
+ /* check hashtable for matching request */
+ PKIX_CHECK(PKIX_PL_HashTable_Lookup
+ (client->cachePtr,
+ (PKIX_PL_Object *)(client->currentRequest),
+ (PKIX_PL_Object **)&searchResponseList,
+ plContext),
+ PKIX_HASHTABLELOOKUPFAILED);
+
+ if (searchResponseList != NULL) {
+ *pPollDesc = NULL;
+ *pResponse = searchResponseList;
+ PKIX_DECREF(client->currentRequest);
+ goto cleanup;
+ }
+
+ /* It wasn't cached. We'll have to actually send it. */
+
+ PKIX_CHECK(pkix_pl_LdapRequest_GetEncoded
+ (client->currentRequest, &encoded, plContext),
+ PKIX_LDAPREQUESTGETENCODEDFAILED);
+
+ client->sendBuf = encoded->data;
+ client->bytesToWrite = encoded->len;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext),
+ PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED);
+
+ /*
+ * It's not enough that we may be done with a particular read.
+ * We're still processing the transaction until we've gotten the
+ * SearchResponseResult message and returned to the BOUND state.
+ * Otherwise we must still have a read pending, and must hold off
+ * on returning results.
+ */
+ if ((client->connectStatus == BOUND) &&
+ (client->entriesFound != NULL)) {
+ *pPollDesc = NULL;
+ *pResponse = client->entriesFound;
+ client->entriesFound = NULL;
+ PKIX_DECREF(client->currentRequest);
+ } else {
+ *pPollDesc = &client->pollDesc;
+ *pResponse = NULL;
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_ResumeRequest
+ * DESCRIPTION:
+ *
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pPollDesc"
+ * The location where the address of the PRPollDesc is stored, if the
+ * client returns with I/O pending.
+ * "pResponse"
+ * The address where the List of LDAPResponses, or NULL for an
+ * unfinished request, 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 LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_ResumeRequest(
+ PKIX_PL_LdapClient *genericClient,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_PL_LdapDefaultClient *client = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_ResumeRequest");
+ PKIX_NULLCHECK_THREE(genericClient, pPollDesc, pResponse);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)genericClient,
+ PKIX_LDAPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT);
+
+ client = (PKIX_PL_LdapDefaultClient *)genericClient;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext),
+ PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED);
+
+ /*
+ * It's not enough that we may be done with a particular read.
+ * We're still processing the transaction until we've gotten the
+ * SearchResponseResult message and returned to the BOUND state.
+ * Otherwise we must still have a read pending, and must hold off
+ * on returning results.
+ */
+ if ((client->connectStatus == BOUND) &&
+ (client->entriesFound != NULL)) {
+ *pPollDesc = NULL;
+ *pResponse = client->entriesFound;
+ client->entriesFound = NULL;
+ PKIX_DECREF(client->currentRequest);
+ } else {
+ *pPollDesc = &client->pollDesc;
+ *pResponse = NULL;
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+
+}
+
+/* --Public-LdapDefaultClient-Functions----------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_LdapDefaultClient_AbandonRequest
+ * DESCRIPTION:
+ *
+ * This function creates and sends an LDAP-protocol "Abandon" message to the
+ * server connected to the LdapDefaultClient pointed to by "client".
+ *
+ * PARAMETERS:
+ * "client"
+ * The LdapDefaultClient whose connection is to be abandoned. 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 Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_LdapDefaultClient_AbandonRequest(
+ PKIX_PL_LdapDefaultClient *client,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapDefaultClient_AbandonRequest");
+ PKIX_NULLCHECK_ONE(client);
+
+ if (client->connectStatus == RECV_PENDING) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAbandon
+ (client->arena,
+ (client->messageID) - 1,
+ &encoded,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEABANDONFAILED);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ encoded->data,
+ encoded->len,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+
+ if (bytesWritten < 0) {
+ client->connectStatus = ABANDON_PENDING;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ }
+
+ PKIX_DECREF(client->entriesFound);
+ PKIX_DECREF(client->currentRequest);
+ PKIX_DECREF(client->currentResponse);
+
+cleanup:
+
+ PKIX_DECREF(client);
+
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h
new file mode 100644
index 0000000000..4abe043281
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h
@@ -0,0 +1,82 @@
+/* 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_ldapdefaultclient.h
+ *
+ * LDAPDefaultClient Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPDEFAULTCLIENT_H
+#define _PKIX_PL_LDAPDEFAULTCLIENT_H
+
+#include "pkix_pl_ldapt.h"
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * At the time of this version, there are unresolved questions about the LDAP
+ * protocol. Although RFC1777 describes a BIND and UNBIND message, it is not
+ * clear whether they are appropriate to this application. We have tested only
+ * using servers that do not expect authentication, and that reject BIND
+ * messages. It is not clear what values might be appropriate for the bindname
+ * and authentication fields, which are currently implemented as char strings
+ * supplied by the caller. (If this changes, the API and possibly the templates
+ * will have to change.) Therefore the LDAPClient_Create API contains a
+ * BindAPI structure, a union, which will have to be revised and extended when
+ * this area of the protocol is better understood.
+ *
+ */
+
+typedef enum {
+ CONNECT_PENDING,
+ CONNECTED,
+ BIND_PENDING,
+ BIND_RESPONSE,
+ BIND_RESPONSE_PENDING,
+ BOUND,
+ SEND_PENDING,
+ RECV,
+ RECV_PENDING,
+ RECV_INITIAL,
+ RECV_NONINITIAL,
+ ABANDON_PENDING
+} LdapClientConnectStatus;
+
+struct PKIX_PL_LdapDefaultClientStruct {
+ PKIX_PL_LdapClient vtable;
+ LdapClientConnectStatus connectStatus;
+ PKIX_UInt32 messageID;
+ PKIX_PL_HashTable *cachePtr;
+ PKIX_PL_Socket *clientSocket;
+ PRPollDesc pollDesc;
+ void *callbackList; /* cast this to (PKIX_PL_Socket_Callback *) */
+ LDAPBindAPI *bindAPI;
+ PLArenaPool *arena;
+ PRTime lastIO;
+ void *sendBuf;
+ PKIX_UInt32 bytesToWrite;
+ void *rcvBuf;
+ PKIX_UInt32 capacity;
+ void *currentInPtr;
+ PKIX_UInt32 currentBytesAvailable;
+ void *bindMsg;
+ PKIX_UInt32 bindMsgLen;
+ PKIX_List *entriesFound;
+ PKIX_PL_LdapRequest *currentRequest;
+ PKIX_PL_LdapResponse *currentResponse;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_LdapDefaultClient_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPDEFAULTCLIENT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c
new file mode 100644
index 0000000000..4546e339a5
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c
@@ -0,0 +1,757 @@
+/* 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_ldaprequest.c
+ *
+ */
+
+#include "pkix_pl_ldaprequest.h"
+
+/* --Private-LdapRequest-Functions------------------------------------- */
+
+/* Note: lengths do not include the NULL terminator */
+static const char caAttr[] = "caCertificate;binary";
+static unsigned int caAttrLen = sizeof(caAttr) - 1;
+static const char uAttr[] = "userCertificate;binary";
+static unsigned int uAttrLen = sizeof(uAttr) - 1;
+static const char ccpAttr[] = "crossCertificatePair;binary";
+static unsigned int ccpAttrLen = sizeof(ccpAttr) - 1;
+static const char crlAttr[] = "certificateRevocationList;binary";
+static unsigned int crlAttrLen = sizeof(crlAttr) - 1;
+static const char arlAttr[] = "authorityRevocationList;binary";
+static unsigned int arlAttrLen = sizeof(arlAttr) - 1;
+
+/*
+ * XXX If this function were moved into pkix_pl_ldapcertstore.c then all of
+ * LdapRequest and LdapResponse could be considered part of the LDAP client.
+ * But the constants, above, would have to be copied as well, and they are
+ * also needed in pkix_pl_LdapRequest_EncodeAttrs. So there would have to be
+ * two copies.
+ */
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_AttrTypeToBit
+ * DESCRIPTION:
+ *
+ * This function creates an attribute mask bit corresponding to the SECItem
+ * pointed to by "attrType", storing the result at "pAttrBit". The comparison
+ * is case-insensitive. If "attrType" does not match any of the known types,
+ * zero is stored at "pAttrBit".
+ *
+ * PARAMETERS
+ * "attrType"
+ * The address of the SECItem whose string contents are to be compared to
+ * the various known attribute types. Must be non-NULL.
+ * "pAttrBit"
+ * The address where the 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 LdapRequest 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_LdapRequest_AttrTypeToBit(
+ SECItem *attrType,
+ LdapAttrMask *pAttrBit,
+ void *plContext)
+{
+ LdapAttrMask attrBit = 0;
+ unsigned int attrLen = 0;
+ const char *s = NULL;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_AttrTypeToBit");
+ PKIX_NULLCHECK_TWO(attrType, pAttrBit);
+
+ s = (const char *)attrType->data;
+ attrLen = attrType->len;
+
+ /*
+ * Taking note of the fact that all of the comparand strings are
+ * different lengths, we do a slight optimization. If a string
+ * length matches but the string does not match, we skip comparing
+ * to the other strings. If new strings are added to the comparand
+ * list, and any are of equal length, be careful to change the
+ * grouping of tests accordingly.
+ */
+ if (attrLen == caAttrLen) {
+ if (PORT_Strncasecmp(caAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_CACERT;
+ }
+ } else if (attrLen == uAttrLen) {
+ if (PORT_Strncasecmp(uAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_USERCERT;
+ }
+ } else if (attrLen == ccpAttrLen) {
+ if (PORT_Strncasecmp(ccpAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_CROSSPAIRCERT;
+ }
+ } else if (attrLen == crlAttrLen) {
+ if (PORT_Strncasecmp(crlAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_CERTREVLIST;
+ }
+ } else if (attrLen == arlAttrLen) {
+ if (PORT_Strncasecmp(arlAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_AUTHREVLIST;
+ }
+ }
+
+ *pAttrBit = attrBit;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_AttrStringToBit
+ * DESCRIPTION:
+ *
+ * This function creates an attribute mask bit corresponding to the null-
+ * terminated string pointed to by "attrString", storing the result at
+ * "pAttrBit". The comparison is case-insensitive. If "attrString" does not
+ * match any of the known types, zero is stored at "pAttrBit".
+ *
+ * PARAMETERS
+ * "attrString"
+ * The address of the null-terminated string whose contents are to be compared to
+ * the various known attribute types. Must be non-NULL.
+ * "pAttrBit"
+ * The address where the 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 LdapRequest 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_LdapRequest_AttrStringToBit(
+ char *attrString,
+ LdapAttrMask *pAttrBit,
+ void *plContext)
+{
+ LdapAttrMask attrBit = 0;
+ unsigned int attrLen = 0;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_AttrStringToBit");
+ PKIX_NULLCHECK_TWO(attrString, pAttrBit);
+
+ attrLen = PL_strlen(attrString);
+
+ /*
+ * Taking note of the fact that all of the comparand strings are
+ * different lengths, we do a slight optimization. If a string
+ * length matches but the string does not match, we skip comparing
+ * to the other strings. If new strings are added to the comparand
+ * list, and any are of equal length, be careful to change the
+ * grouping of tests accordingly.
+ */
+ if (attrLen == caAttrLen) {
+ if (PORT_Strncasecmp(caAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_CACERT;
+ }
+ } else if (attrLen == uAttrLen) {
+ if (PORT_Strncasecmp(uAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_USERCERT;
+ }
+ } else if (attrLen == ccpAttrLen) {
+ if (PORT_Strncasecmp(ccpAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_CROSSPAIRCERT;
+ }
+ } else if (attrLen == crlAttrLen) {
+ if (PORT_Strncasecmp(crlAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_CERTREVLIST;
+ }
+ } else if (attrLen == arlAttrLen) {
+ if (PORT_Strncasecmp(arlAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_AUTHREVLIST;
+ }
+ }
+
+ *pAttrBit = attrBit;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_EncodeAttrs
+ * DESCRIPTION:
+ *
+ * This function obtains the attribute mask bits from the LdapRequest pointed
+ * to by "request", creates the corresponding array of AttributeTypes for the
+ * encoding of the SearchRequest message.
+ *
+ * PARAMETERS
+ * "request"
+ * The address of the LdapRequest whose attributes are to be encoded. 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 LdapRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_EncodeAttrs(
+ PKIX_PL_LdapRequest *request,
+ void *plContext)
+{
+ SECItem **attrArray = NULL;
+ PKIX_UInt32 attrIndex = 0;
+ LdapAttrMask attrBits;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_EncodeAttrs");
+ PKIX_NULLCHECK_ONE(request);
+
+ /* construct "attrs" according to bits in request->attrBits */
+ attrBits = request->attrBits;
+ attrArray = request->attrArray;
+ if ((attrBits & LDAPATTR_CACERT) == LDAPATTR_CACERT) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)caAttr;
+ request->attributes[attrIndex].len = caAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_USERCERT) == LDAPATTR_USERCERT) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)uAttr;
+ request->attributes[attrIndex].len = uAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_CROSSPAIRCERT) == LDAPATTR_CROSSPAIRCERT) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)ccpAttr;
+ request->attributes[attrIndex].len = ccpAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_CERTREVLIST) == LDAPATTR_CERTREVLIST) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)crlAttr;
+ request->attributes[attrIndex].len = crlAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_AUTHREVLIST) == LDAPATTR_AUTHREVLIST) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)arlAttr;
+ request->attributes[attrIndex].len = arlAttrLen;
+ attrIndex++;
+ }
+ attrArray[attrIndex] = (SECItem *)NULL;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPREQUEST_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPREQUEST);
+
+ /*
+ * All dynamic fields in an LDAPRequest are allocated
+ * in an arena, and will be freed when the arena is destroyed.
+ */
+
+cleanup:
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_UInt32 dataLen = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 idLen = 0;
+ const unsigned char *msgBuf = NULL;
+ PKIX_PL_LdapRequest *ldapRq = NULL;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPREQUEST_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPREQUEST);
+
+ ldapRq = (PKIX_PL_LdapRequest *)object;
+
+ *pHashcode = 0;
+
+ /*
+ * Two requests that differ only in msgnum are a match! Therefore,
+ * start hashcoding beyond the encoded messageID field.
+ */
+ if (ldapRq->encoded) {
+ msgBuf = (const unsigned char *)ldapRq->encoded->data;
+ /* Is message length short form (one octet) or long form? */
+ if ((msgBuf[1] & 0x80) != 0) {
+ sizeOfLength = msgBuf[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ dataLen = (dataLen << 8) + msgBuf[dindex + 2];
+ }
+ } else {
+ dataLen = msgBuf[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ idLen = msgBuf[dindex + 3] + 2;
+ dindex += idLen;
+ dataLen -= idLen;
+ msgBuf = &msgBuf[dindex + 2];
+
+ PKIX_CHECK(pkix_hash(msgBuf, dataLen, pHashcode, plContext),
+ PKIX_HASHFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPREQUEST);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_Equals(
+ PKIX_PL_Object *firstObj,
+ PKIX_PL_Object *secondObj,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_LdapRequest *firstReq = NULL;
+ PKIX_PL_LdapRequest *secondReq = NULL;
+ PKIX_UInt32 secondType = 0;
+ PKIX_UInt32 firstLen = 0;
+ const unsigned char *firstData = NULL;
+ const unsigned char *secondData = NULL;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 i = 0;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Equals");
+ PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
+
+ /* test that firstObj is a LdapRequest */
+ PKIX_CHECK(pkix_CheckType(firstObj, PKIX_LDAPREQUEST_TYPE, plContext),
+ PKIX_FIRSTOBJARGUMENTNOTLDAPREQUEST);
+
+ /*
+ * Since we know firstObj is a LdapRequest, if both references are
+ * identical, they must be equal
+ */
+ if (firstObj == secondObj){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObj isn't a LdapRequest, 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_LDAPREQUEST_TYPE) {
+ goto cleanup;
+ }
+
+ firstReq = (PKIX_PL_LdapRequest *)firstObj;
+ secondReq = (PKIX_PL_LdapRequest *)secondObj;
+
+ /* If either lacks an encoded string, they cannot be compared */
+ if (!(firstReq->encoded) || !(secondReq->encoded)) {
+ goto cleanup;
+ }
+
+ if (firstReq->encoded->len != secondReq->encoded->len) {
+ goto cleanup;
+ }
+
+ firstData = (const unsigned char *)firstReq->encoded->data;
+ secondData = (const unsigned char *)secondReq->encoded->data;
+
+ /*
+ * Two requests that differ only in msgnum are equal! Therefore,
+ * start the byte comparison beyond the encoded messageID field.
+ */
+
+ /* Is message length short form (one octet) or long form? */
+ if ((firstData[1] & 0x80) != 0) {
+ sizeOfLength = firstData[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ firstLen = (firstLen << 8) + firstData[dindex + 2];
+ }
+ } else {
+ firstLen = firstData[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ i = firstData[dindex + 3] + 2;
+ dindex += i;
+ firstLen -= i;
+ firstData = &firstData[dindex + 2];
+
+ /*
+ * In theory, we have to calculate where the second message data
+ * begins by checking its length encodings. But if these messages
+ * are equal, we can re-use the calculation we already did. If they
+ * are not equal, the byte comparisons will surely fail.
+ */
+
+ secondData = &secondData[dindex + 2];
+
+ for (i = 0; i < firstLen; i++) {
+ if (firstData[i] != secondData[i]) {
+ goto cleanup;
+ }
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_LDAPREQUEST_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_LdapRequest_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_RegisterSelf");
+
+ entry.description = "LdapRequest";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_LdapRequest);
+ entry.destructor = pkix_pl_LdapRequest_Destroy;
+ entry.equalsFunction = pkix_pl_LdapRequest_Equals;
+ entry.hashcodeFunction = pkix_pl_LdapRequest_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_LDAPREQUEST_TYPE] = entry;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Create
+ * DESCRIPTION:
+ *
+ * This function creates an LdapRequest using the PLArenaPool pointed to by
+ * "arena", a message number whose value is "msgnum", a base object pointed to
+ * by "issuerDN", a scope whose value is "scope", a derefAliases flag whose
+ * value is "derefAliases", a sizeLimit whose value is "sizeLimit", a timeLimit
+ * whose value is "timeLimit", an attrsOnly flag whose value is "attrsOnly", a
+ * filter whose value is "filter", and attribute bits whose value is
+ * "attrBits"; storing the result at "pRequestMsg".
+ *
+ * See pkix_pl_ldaptemplates.c (and below) for the ASN.1 representation of
+ * message components, and see pkix_pl_ldapt.h for data types.
+ *
+ * PARAMETERS
+ * "arena"
+ * The address of the PLArenaPool to be used in the encoding. Must be
+ * non-NULL.
+ * "msgnum"
+ * The UInt32 message number to be used for the messageID component of the
+ * LDAP message exchange.
+ * "issuerDN"
+ * The address of the string to be used for the baseObject component of the
+ * LDAP SearchRequest message. Must be non-NULL.
+ * "scope"
+ * The (enumerated) ScopeType to be used for the scope component of the
+ * LDAP SearchRequest message
+ * "derefAliases"
+ * The (enumerated) DerefType to be used for the derefAliases component of
+ * the LDAP SearchRequest message
+ * "sizeLimit"
+ * The UInt32 value to be used for the sizeLimit component of the LDAP
+ * SearchRequest message
+ * "timeLimit"
+ * The UInt32 value to be used for the timeLimit component of the LDAP
+ * SearchRequest message
+ * "attrsOnly"
+ * The Boolean value to be used for the attrsOnly component of the LDAP
+ * SearchRequest message
+ * "filter"
+ * The filter to be used for the filter component of the LDAP
+ * SearchRequest message
+ * "attrBits"
+ * The LdapAttrMask bits indicating the attributes to be included in the
+ * attributes sequence of the LDAP SearchRequest message
+ * "pRequestMsg"
+ * The address at which the address of the LdapRequest 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 LdapRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+/*
+ * SearchRequest ::=
+ * [APPLICATION 3] SEQUENCE {
+ * baseObject LDAPDN,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefAliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no sizeLimit
+ * timeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no timeLimit
+ * attrsOnly BOOLEAN,
+ * -- TRUE, if only attributes (without values)
+ * -- to be returned
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ *
+ * Filter ::=
+ * CHOICE {
+ * and [0] SET OF Filter,
+ * or [1] SET OF Filter,
+ * not [2] Filter,
+ * equalityMatch [3] AttributeValueAssertion,
+ * substrings [4] SubstringFilter,
+ * greaterOrEqual [5] AttributeValueAssertion,
+ * lessOrEqual [6] AttributeValueAssertion,
+ * present [7] AttributeType,
+ * approxMatch [8] AttributeValueAssertion
+ * }
+ *
+ * SubstringFilter ::=
+ * SEQUENCE {
+ * type AttributeType,
+ * SEQUENCE OF CHOICE {
+ * initial [0] LDAPString,
+ * any [1] LDAPString,
+ * final [2] LDAPString,
+ * }
+ * }
+ *
+ * AttributeValueAssertion ::=
+ * SEQUENCE {
+ * attributeType AttributeType,
+ * attributeValue AttributeValue,
+ * }
+ *
+ * AttributeValue ::= OCTET STRING
+ *
+ * AttributeType ::= LDAPString
+ * -- text name of the attribute, or dotted
+ * -- OID representation
+ *
+ * LDAPDN ::= LDAPString
+ *
+ * LDAPString ::= OCTET STRING
+ *
+ */
+PKIX_Error *
+pkix_pl_LdapRequest_Create(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgnum,
+ char *issuerDN,
+ ScopeType scope,
+ DerefType derefAliases,
+ PKIX_UInt32 sizeLimit,
+ PKIX_UInt32 timeLimit,
+ char attrsOnly,
+ LDAPFilter *filter,
+ LdapAttrMask attrBits,
+ PKIX_PL_LdapRequest **pRequestMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ LDAPSearch *search;
+ PKIX_PL_LdapRequest *ldapRequest = NULL;
+ char scopeTypeAsChar;
+ char derefAliasesTypeAsChar;
+ SECItem *attrArray[MAX_LDAPATTRS + 1];
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Create");
+ PKIX_NULLCHECK_THREE(arena, issuerDN, pRequestMsg);
+
+ /* create a PKIX_PL_LdapRequest object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_LDAPREQUEST_TYPE,
+ sizeof (PKIX_PL_LdapRequest),
+ (PKIX_PL_Object **)&ldapRequest,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ ldapRequest->arena = arena;
+ ldapRequest->msgnum = msgnum;
+ ldapRequest->issuerDN = issuerDN;
+ ldapRequest->scope = scope;
+ ldapRequest->derefAliases = derefAliases;
+ ldapRequest->sizeLimit = sizeLimit;
+ ldapRequest->timeLimit = timeLimit;
+ ldapRequest->attrsOnly = attrsOnly;
+ ldapRequest->filter = filter;
+ ldapRequest->attrBits = attrBits;
+
+ ldapRequest->attrArray = attrArray;
+
+ PKIX_CHECK(pkix_pl_LdapRequest_EncodeAttrs
+ (ldapRequest, plContext),
+ PKIX_LDAPREQUESTENCODEATTRSFAILED);
+
+ PKIX_PL_NSSCALL
+ (LDAPREQUEST, PORT_Memset, (&msg, 0, sizeof (LDAPMessage)));
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgnum;
+ msg.messageID.len = sizeof (msgnum);
+
+ msg.protocolOp.selector = LDAP_SEARCH_TYPE;
+
+ search = &(msg.protocolOp.op.searchMsg);
+
+ search->baseObject.type = siAsciiString;
+ search->baseObject.data = (void *)issuerDN;
+ search->baseObject.len = PL_strlen(issuerDN);
+ scopeTypeAsChar = (char)scope;
+ search->scope.type = siUnsignedInteger;
+ search->scope.data = (void *)&scopeTypeAsChar;
+ search->scope.len = sizeof (scopeTypeAsChar);
+ derefAliasesTypeAsChar = (char)derefAliases;
+ search->derefAliases.type = siUnsignedInteger;
+ search->derefAliases.data =
+ (void *)&derefAliasesTypeAsChar;
+ search->derefAliases.len =
+ sizeof (derefAliasesTypeAsChar);
+ search->sizeLimit.type = siUnsignedInteger;
+ search->sizeLimit.data = (void *)&sizeLimit;
+ search->sizeLimit.len = sizeof (PKIX_UInt32);
+ search->timeLimit.type = siUnsignedInteger;
+ search->timeLimit.data = (void *)&timeLimit;
+ search->timeLimit.len = sizeof (PKIX_UInt32);
+ search->attrsOnly.type = siBuffer;
+ search->attrsOnly.data = (void *)&attrsOnly;
+ search->attrsOnly.len = sizeof (attrsOnly);
+
+ PKIX_PL_NSSCALL
+ (LDAPREQUEST,
+ PORT_Memcpy,
+ (&search->filter, filter, sizeof (LDAPFilter)));
+
+ search->attributes = attrArray;
+
+ PKIX_PL_NSSCALLRV
+ (LDAPREQUEST, ldapRequest->encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+
+ if (!(ldapRequest->encoded)) {
+ PKIX_ERROR(PKIX_FAILEDINENCODINGSEARCHREQUEST);
+ }
+
+ *pRequestMsg = ldapRequest;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(ldapRequest);
+ }
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_GetEncoded
+ * DESCRIPTION:
+ *
+ * This function obtains the encoded message from the LdapRequest pointed to
+ * by "request", storing the result at "pRequestBuf".
+ *
+ * PARAMETERS
+ * "request"
+ * The address of the LdapRequest whose encoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pRequestBuf"
+ * The address at which is stored the address of the encoded message. 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 LdapRequest 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_LdapRequest_GetEncoded(
+ PKIX_PL_LdapRequest *request,
+ SECItem **pRequestBuf,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_GetEncoded");
+ PKIX_NULLCHECK_TWO(request, pRequestBuf);
+
+ *pRequestBuf = request->encoded;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h
new file mode 100644
index 0000000000..1d05a9447e
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h
@@ -0,0 +1,86 @@
+/* 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_ldaprequest.h
+ *
+ * LdapRequest Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPREQUEST_H
+#define _PKIX_PL_LDAPREQUEST_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ USER_CERT,
+ CA_CERT,
+ CROSS_CERT,
+ CRL,
+ ARL,
+ DELTA_CRL
+} PKIX_PL_LdapAttr;
+
+struct PKIX_PL_LdapRequestStruct{
+ PLArenaPool *arena;
+ PKIX_UInt32 msgnum;
+ char *issuerDN;
+ ScopeType scope;
+ DerefType derefAliases;
+ PKIX_UInt32 sizeLimit;
+ PKIX_UInt32 timeLimit;
+ char attrsOnly;
+ LDAPFilter *filter;
+ LdapAttrMask attrBits;
+ SECItem attributes[MAX_LDAPATTRS];
+ SECItem **attrArray;
+ SECItem *encoded;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_LdapRequest_Create(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgnum,
+ char *issuerDN,
+ ScopeType scope,
+ DerefType derefAliases,
+ PKIX_UInt32 sizeLimit,
+ PKIX_UInt32 timeLimit,
+ char attrsOnly,
+ LDAPFilter *filter,
+ LdapAttrMask attrBits,
+ PKIX_PL_LdapRequest **pRequestMsg,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapRequest_AttrTypeToBit(
+ SECItem *attrType,
+ LdapAttrMask *pAttrBit,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapRequest_AttrStringToBit(
+ char *attrString,
+ LdapAttrMask *pAttrBit,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapRequest_GetEncoded(
+ PKIX_PL_LdapRequest *request,
+ SECItem **pRequestBuf,
+ void *plContext);
+
+PKIX_Error *pkix_pl_LdapRequest_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPREQUEST_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c
new file mode 100644
index 0000000000..cd2543f3be
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c
@@ -0,0 +1,786 @@
+/* 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_ldapresponse.c
+ *
+ */
+
+#include <fcntl.h>
+#include "pkix_pl_ldapresponse.h"
+
+/* --Private-LdapResponse-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapResponse_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_LdapResponse *ldapRsp = NULL;
+ LDAPMessage *m = NULL;
+ LDAPSearchResponseEntry *entry = NULL;
+ LDAPSearchResponseResult *result = NULL;
+ LDAPSearchResponseAttr **attributes = NULL;
+ LDAPSearchResponseAttr *attr = NULL;
+ SECItem **valp = NULL;
+ SECItem *val = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPRESPONSE);
+
+ ldapRsp = (PKIX_PL_LdapResponse *)object;
+
+ m = &ldapRsp->decoded;
+
+ if (m->messageID.data != NULL) {
+ PR_Free(m->messageID.data);
+ }
+
+ if (m->protocolOp.selector ==
+ LDAP_SEARCHRESPONSEENTRY_TYPE) {
+ entry = &m->protocolOp.op.searchResponseEntryMsg;
+ if (entry->objectName.data != NULL) {
+ PR_Free(entry->objectName.data);
+ }
+ if (entry->attributes != NULL) {
+ for (attributes = entry->attributes;
+ *attributes != NULL;
+ attributes++) {
+ attr = *attributes;
+ PR_Free(attr->attrType.data);
+ for (valp = attr->val; *valp != NULL; valp++) {
+ val = *valp;
+ if (val->data != NULL) {
+ PR_Free(val->data);
+ }
+ PR_Free(val);
+ }
+ PR_Free(attr->val);
+ PR_Free(attr);
+ }
+ PR_Free(entry->attributes);
+ }
+ } else if (m->protocolOp.selector ==
+ LDAP_SEARCHRESPONSERESULT_TYPE) {
+ result = &m->protocolOp.op.searchResponseResultMsg;
+ if (result->resultCode.data != NULL) {
+ PR_Free(result->resultCode.data);
+ }
+ }
+
+ PKIX_FREE(ldapRsp->derEncoded.data);
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapResponse_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_UInt32 dataLen = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 idLen = 0;
+ const unsigned char *msgBuf = NULL;
+ PKIX_PL_LdapResponse *ldapRsp = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPRESPONSE);
+
+ ldapRsp = (PKIX_PL_LdapResponse *)object;
+
+ *pHashcode = 0;
+
+ /*
+ * Two responses that differ only in msgnum are a match! Therefore,
+ * start hashcoding beyond the encoded messageID field.
+ */
+ if (ldapRsp->derEncoded.data) {
+ msgBuf = (const unsigned char *)ldapRsp->derEncoded.data;
+ /* Is message length short form (one octet) or long form? */
+ if ((msgBuf[1] & 0x80) != 0) {
+ sizeOfLength = msgBuf[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ dataLen = (dataLen << 8) + msgBuf[dindex + 2];
+ }
+ } else {
+ dataLen = msgBuf[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ idLen = msgBuf[dindex + 3] + 2;
+ dindex += idLen;
+ dataLen -= idLen;
+ msgBuf = &msgBuf[dindex + 2];
+
+ PKIX_CHECK(pkix_hash(msgBuf, dataLen, pHashcode, plContext),
+ PKIX_HASHFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapResponse_Equals(
+ PKIX_PL_Object *firstObj,
+ PKIX_PL_Object *secondObj,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_LdapResponse *rsp1 = NULL;
+ PKIX_PL_LdapResponse *rsp2 = NULL;
+ PKIX_UInt32 secondType = 0;
+ PKIX_UInt32 firstLen = 0;
+ const unsigned char *firstData = NULL;
+ const unsigned char *secondData = NULL;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 i = 0;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Equals");
+ PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
+
+ /* test that firstObj is a LdapResponse */
+ PKIX_CHECK(pkix_CheckType(firstObj, PKIX_LDAPRESPONSE_TYPE, plContext),
+ PKIX_FIRSTOBJARGUMENTNOTLDAPRESPONSE);
+
+ /*
+ * Since we know firstObj is a LdapResponse, if both references are
+ * identical, they must be equal
+ */
+ if (firstObj == secondObj){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObj isn't a LdapResponse, 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_LDAPRESPONSE_TYPE) {
+ goto cleanup;
+ }
+
+ rsp1 = (PKIX_PL_LdapResponse *)firstObj;
+ rsp2 = (PKIX_PL_LdapResponse *)secondObj;
+
+ /* If either lacks an encoded string, they cannot be compared */
+ if (!(rsp1->derEncoded.data) || !(rsp2->derEncoded.data)) {
+ goto cleanup;
+ }
+
+ if (rsp1->derEncoded.len != rsp2->derEncoded.len) {
+ goto cleanup;
+ }
+
+ firstData = (const unsigned char *)rsp1->derEncoded.data;
+ secondData = (const unsigned char *)rsp2->derEncoded.data;
+
+ /*
+ * Two responses that differ only in msgnum are equal! Therefore,
+ * start the byte comparison beyond the encoded messageID field.
+ */
+
+ /* Is message length short form (one octet) or long form? */
+ if ((firstData[1] & 0x80) != 0) {
+ sizeOfLength = firstData[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ firstLen = (firstLen << 8) + firstData[dindex + 2];
+ }
+ } else {
+ firstLen = firstData[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ i = firstData[dindex + 3] + 2;
+ dindex += i;
+ firstLen -= i;
+ firstData = &firstData[dindex + 2];
+
+ /*
+ * In theory, we have to calculate where the second message data
+ * begins by checking its length encodings. But if these messages
+ * are equal, we can re-use the calculation we already did. If they
+ * are not equal, the byte comparisons will surely fail.
+ */
+
+ secondData = &secondData[dindex + 2];
+
+ for (i = 0; i < firstLen; i++) {
+ if (firstData[i] != secondData[i]) {
+ goto cleanup;
+ }
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_LDAPRESPONSE_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_LdapResponse_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_RegisterSelf");
+
+ entry.description = "LdapResponse";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_LdapResponse);
+ entry.destructor = pkix_pl_LdapResponse_Destroy;
+ entry.equalsFunction = pkix_pl_LdapResponse_Equals;
+ entry.hashcodeFunction = pkix_pl_LdapResponse_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_LDAPRESPONSE_TYPE] = entry;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Create
+ * DESCRIPTION:
+ *
+ * This function creates an LdapResponse for the LDAPMessageType provided in
+ * "responseType" and a buffer capacity provided by "totalLength". It copies
+ * into its buffer either "totalLength" or "bytesAvailable" bytes, whichever
+ * is less, from the buffer pointed to by "partialData", storing the number of
+ * bytes copied at "pBytesConsumed" and storing the address of the LdapResponse
+ * at "pLdapResponse".
+ *
+ * If a message is complete in a single I/O buffer, the LdapResponse will be
+ * complete when this function returns. If the message carries over into
+ * additional buffers, their contents will be added to the LdapResponse by
+ * susequent calls to pkix_pl_LdapResponse_Append.
+ *
+ * PARAMETERS
+ * "responseType"
+ * The value of the message type (LDAP_SEARCHRESPONSEENTRY_TYPE or
+ * LDAP_SEARCHRESPONSERESULT_TYPE) for the LdapResponse being created
+ * "totalLength"
+ * The UInt32 value for the total length of the encoded message to be
+ * stored in the LdapResponse
+ * "bytesAvailable"
+ * The UInt32 value for the number of bytes of data available in the
+ * current buffer.
+ * "partialData"
+ * The address from which data is to be copied.
+ * "pBytesConsumed"
+ * The address at which is stored the UInt32 number of bytes taken from the
+ * current buffer. If this number is less than "bytesAvailable", then bytes
+ * remain in the buffer for the next LdapResponse. Must be non-NULL.
+ * "pLdapResponse"
+ * The address where the created LdapResponse 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 LdapResponse 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_LdapResponse_Create(
+ LDAPMessageType responseType,
+ PKIX_UInt32 totalLength,
+ PKIX_UInt32 bytesAvailable,
+ void *partialData,
+ PKIX_UInt32 *pBytesConsumed,
+ PKIX_PL_LdapResponse **pLdapResponse,
+ void *plContext)
+{
+ PKIX_UInt32 bytesConsumed = 0;
+ PKIX_PL_LdapResponse *ldapResponse = NULL;
+ void *data = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Create");
+ PKIX_NULLCHECK_ONE(pLdapResponse);
+
+ if (bytesAvailable <= totalLength) {
+ bytesConsumed = bytesAvailable;
+ } else {
+ bytesConsumed = totalLength;
+ }
+
+ /* create a PKIX_PL_LdapResponse object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_LDAPRESPONSE_TYPE,
+ sizeof (PKIX_PL_LdapResponse),
+ (PKIX_PL_Object **)&ldapResponse,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ ldapResponse->decoded.protocolOp.selector = responseType;
+ ldapResponse->totalLength = totalLength;
+ ldapResponse->partialLength = bytesConsumed;
+
+ if (totalLength != 0){
+ /* Alloc space for array */
+ PKIX_NULLCHECK_ONE(partialData);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (totalLength,
+ &data,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_PL_NSSCALL
+ (LDAPRESPONSE,
+ PORT_Memcpy,
+ (data, partialData, bytesConsumed));
+ }
+
+ ldapResponse->derEncoded.type = siBuffer;
+ ldapResponse->derEncoded.data = data;
+ ldapResponse->derEncoded.len = totalLength;
+ *pBytesConsumed = bytesConsumed;
+ *pLdapResponse = ldapResponse;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(ldapResponse);
+ }
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Append
+ * DESCRIPTION:
+ *
+ * This function updates the LdapResponse pointed to by "response" with up to
+ * "incrLength" from the buffer pointer to by "incrData", storing the number of
+ * bytes copied at "pBytesConsumed".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse being updated. Must be non-zero.
+ * "incrLength"
+ * The UInt32 value for the number of bytes of data available in the
+ * current buffer.
+ * "incrData"
+ * The address from which data is to be copied.
+ * "pBytesConsumed"
+ * The address at which is stored the UInt32 number of bytes taken from the
+ * current buffer. If this number is less than "incrLength", then bytes
+ * remain in the buffer for the next LdapResponse. 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 LdapResponse 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_LdapResponse_Append(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 incrLength,
+ void *incrData,
+ PKIX_UInt32 *pBytesConsumed,
+ void *plContext)
+{
+ PKIX_UInt32 newPartialLength = 0;
+ PKIX_UInt32 bytesConsumed = 0;
+ void *dest = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Append");
+ PKIX_NULLCHECK_TWO(response, pBytesConsumed);
+
+ if (incrLength > 0) {
+
+ /* Calculate how many bytes we have room for. */
+ bytesConsumed =
+ response->totalLength - response->partialLength;
+
+ if (bytesConsumed > incrLength) {
+ bytesConsumed = incrLength;
+ }
+
+ newPartialLength = response->partialLength + bytesConsumed;
+
+ PKIX_NULLCHECK_ONE(incrData);
+
+ dest = &(((char *)response->derEncoded.data)[
+ response->partialLength]);
+
+ PKIX_PL_NSSCALL
+ (LDAPRESPONSE,
+ PORT_Memcpy,
+ (dest, incrData, bytesConsumed));
+
+ response->partialLength = newPartialLength;
+ }
+
+ *pBytesConsumed = bytesConsumed;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_IsComplete
+ * DESCRIPTION:
+ *
+ * This function determines whether the LdapResponse pointed to by "response"
+ * contains all the data called for by the "totalLength" parameter provided
+ * when it was created, storing PKIX_TRUE at "pIsComplete" if so, and
+ * PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse being evaluaTED. Must be non-zero.
+ * "incrLength"
+ * The UInt32 value for the number of bytes of data available in the
+ * current buffer.
+ * "incrData"
+ * The address from which data is to be copied.
+ * "pIsComplete"
+ * The address at which is stored the Boolean indication of whether the
+ * LdapResponse 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 LdapResponse 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_LdapResponse_IsComplete(
+ PKIX_PL_LdapResponse *response,
+ PKIX_Boolean *pIsComplete,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_IsComplete");
+ PKIX_NULLCHECK_TWO(response, pIsComplete);
+
+ if (response->totalLength == response->partialLength) {
+ *pIsComplete = PKIX_TRUE;
+ } else {
+ *pIsComplete = PKIX_FALSE;
+ }
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Decode
+ * DESCRIPTION:
+ *
+ * This function decodes the DER data contained in the LdapResponse pointed to
+ * by "response", using the arena pointed to by "arena", and storing at
+ * "pStatus" SECSuccess if the decoding was successful and SECFailure
+ * otherwise. The decoded message is stored in an element of "response".
+ *
+ * PARAMETERS
+ * "arena"
+ * The address of the PLArenaPool to be used in the decoding. Must be
+ * non-NULL.
+ * "response"
+ * The address of the LdapResponse whose DER data is to be decoded. Must
+ * be non-NULL.
+ * "pStatus"
+ * The address at which is stored the status from the decoding, SECSuccess
+ * if successful, SECFailure otherwise. 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 LdapResponse 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_LdapResponse_Decode(
+ PLArenaPool *arena,
+ PKIX_PL_LdapResponse *response,
+ SECStatus *pStatus,
+ void *plContext)
+{
+ LDAPMessage *msg;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Decode");
+ PKIX_NULLCHECK_THREE(arena, response, pStatus);
+
+ if (response->totalLength != response->partialLength) {
+ PKIX_ERROR(PKIX_ATTEMPTTODECODEANINCOMPLETERESPONSE);
+ }
+
+ msg = &(response->decoded);
+
+ PKIX_PL_NSSCALL
+ (LDAPRESPONSE, PORT_Memset, (msg, 0, sizeof (LDAPMessage)));
+
+ PKIX_PL_NSSCALLRV(LDAPRESPONSE, rv, SEC_ASN1DecodeItem,
+ (NULL, msg, PKIX_PL_LDAPMessageTemplate, &(response->derEncoded)));
+
+ *pStatus = rv;
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetMessage
+ * DESCRIPTION:
+ *
+ * This function obtains the decoded message from the LdapResponse pointed to
+ * by "response", storing the result at "pMessage".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose decoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pMessage"
+ * The address at which is stored the address of the decoded message. 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 Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessage(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessage **pMessage,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessage");
+ PKIX_NULLCHECK_TWO(response, pMessage);
+
+ *pMessage = &response->decoded;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetCapacity
+ * DESCRIPTION:
+ *
+ * This function obtains from the LdapResponse pointed to by "response" the
+ * number of bytes remaining to be read, based on the totalLength that was
+ * provided to LdapResponse_Create and the data subsequently provided to
+ * LdapResponse_Append, storing the result at "pMessage".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose remaining capacity is to be
+ * retrieved. Must be non-NULL.
+ * "pCapacity"
+ * The address at which is stored the address of the decoded message. 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 LdapResponse 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_LdapResponse_GetCapacity(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 *pCapacity,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetCapacity");
+ PKIX_NULLCHECK_TWO(response, pCapacity);
+
+ *pCapacity = response->totalLength - response->partialLength;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetMessageType
+ * DESCRIPTION:
+ *
+ * This function obtains the message type from the LdapResponse pointed to
+ * by "response", storing the result at "pMessageType".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose message type is to be
+ * retrieved. Must be non-NULL.
+ * "pMessageType"
+ * The address at which is stored the type of the response message. 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 Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessageType(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessageType *pMessageType,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessageType");
+ PKIX_NULLCHECK_TWO(response, pMessageType);
+
+ *pMessageType = response->decoded.protocolOp.selector;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetResultCode
+ * DESCRIPTION:
+ *
+ * This function obtains the result code from the LdapResponse pointed to
+ * by "response", storing the result at "pResultCode".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose result code is to be
+ * retrieved. Must be non-NULL.
+ * "pResultCode"
+ * The address at which is stored the address of the decoded message. 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 LdapResponse 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_LdapResponse_GetResultCode(
+ PKIX_PL_LdapResponse *response,
+ LDAPResultCode *pResultCode,
+ void *plContext)
+{
+ LDAPMessageType messageType = 0;
+ LDAPSearchResponseResult *resultMsg = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode");
+ PKIX_NULLCHECK_TWO(response, pResultCode);
+
+ messageType = response->decoded.protocolOp.selector;
+
+ if (messageType != LDAP_SEARCHRESPONSERESULT_TYPE) {
+ PKIX_ERROR(PKIX_GETRESULTCODECALLEDFORNONRESULTMESSAGE);
+ }
+
+ resultMsg = &response->decoded.protocolOp.op.searchResponseResultMsg;
+
+ *pResultCode = *(resultMsg->resultCode.data);
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetAttributes
+ * DESCRIPTION:
+ *
+ * This function obtains the attributes from the LdapResponse pointed to
+ * by "response", storing the result at "pAttributes".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose decoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pAttributes"
+ * The address at which is stored the attributes of the message. 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 LdapResponse 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_LdapResponse_GetAttributes(
+ PKIX_PL_LdapResponse *response,
+ LDAPSearchResponseAttr ***pAttributes,
+ void *plContext)
+{
+ LDAPMessageType messageType = 0;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode");
+ PKIX_NULLCHECK_TWO(response, pAttributes);
+
+ messageType = response->decoded.protocolOp.selector;
+
+ if (messageType != LDAP_SEARCHRESPONSEENTRY_TYPE) {
+ PKIX_ERROR(PKIX_GETATTRIBUTESCALLEDFORNONENTRYMESSAGE);
+ }
+
+ *pAttributes = response->
+ decoded.protocolOp.op.searchResponseEntryMsg.attributes;
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h
new file mode 100644
index 0000000000..37dc916b1e
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h
@@ -0,0 +1,96 @@
+/* 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_ldapresponse.h
+ *
+ * LdapResponse Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPRESPONSE_H
+#define _PKIX_PL_LDAPRESPONSE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_LdapResponseStruct{
+ LDAPMessage decoded;
+ PKIX_UInt32 partialLength;
+ PKIX_UInt32 totalLength;
+ SECItem derEncoded;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_LdapResponse_Create(
+ LDAPMessageType responseType,
+ PKIX_UInt32 totalLength,
+ PKIX_UInt32 bytesAvailable,
+ void *partialData,
+ PKIX_UInt32 *pBytesConsumed,
+ PKIX_PL_LdapResponse **pResponse,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_Append(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 partialLength,
+ void *partialData,
+ PKIX_UInt32 *bytesConsumed,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_IsComplete(
+ PKIX_PL_LdapResponse *response,
+ PKIX_Boolean *pIsComplete,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_Decode(
+ PLArenaPool *arena,
+ PKIX_PL_LdapResponse *response,
+ SECStatus *pStatus,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessage(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessage **pMessage,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessageType(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessageType *pMessageType,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetCapacity(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 *pCapacity,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetResultCode(
+ PKIX_PL_LdapResponse *response,
+ LDAPResultCode *pResultCode,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetAttributes(
+ PKIX_PL_LdapResponse *response,
+ LDAPSearchResponseAttr ***pAttributes,
+ void *plContext);
+
+PKIX_Error *pkix_pl_LdapResponse_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPRESPONSE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h
new file mode 100644
index 0000000000..539803638c
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h
@@ -0,0 +1,314 @@
+/* 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/. */
+
+#ifndef _LDAP_H_
+#define _LDAP_H_
+
+#include "certt.h"
+#include "pkixt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const SEC_ASN1Template PKIX_PL_LDAPCrossCertPairTemplate[];
+SEC_ASN1_CHOOSER_DECLARE(PKIX_PL_LDAPCrossCertPairTemplate)
+extern const SEC_ASN1Template PKIX_PL_LDAPMessageTemplate[];
+SEC_ASN1_CHOOSER_DECLARE(PKIX_PL_LDAPMessageTemplate)
+extern const SEC_ASN1Template LDAPFilterTemplate[];
+SEC_ASN1_CHOOSER_DECLARE(LDAPFilterTemplate)
+
+/* ********************************************************************** */
+
+#define SEC_ASN1_LDAP_STRING SEC_ASN1_OCTET_STRING
+
+#define LDAPATTR_CACERT (1<<0)
+#define LDAPATTR_USERCERT (1<<1)
+#define LDAPATTR_CROSSPAIRCERT (1<<2)
+#define LDAPATTR_CERTREVLIST (1<<3)
+#define LDAPATTR_AUTHREVLIST (1<<4)
+#define MAX_LDAPATTRS 5
+typedef PKIX_UInt32 LdapAttrMask;
+
+typedef enum {
+ SIMPLE_AUTH = 0,
+ KRBV42LDAP_AUTH = 1,
+ KRBV42DSA_AUTH = 2
+} AuthType;
+
+typedef enum {
+ BASE_OBJECT = 0,
+ SINGLE_LEVEL = 1,
+ WHOLE_SUBTREE = 2
+} ScopeType;
+
+typedef enum {
+ NEVER_DEREF = 0,
+ DEREF_IN_SEARCHING = 1,
+ DEREF_FINDING_BASEOBJ = 2,
+ ALWAYS_DEREF = 3
+} DerefType;
+
+typedef enum {
+ LDAP_INITIALSUBSTRING_TYPE = 0,
+ LDAP_ANYSUBSTRING_TYPE = 1,
+ LDAP_FINALSUBSTRING_TYPE = 2
+} LDAPSubstringFilterType;
+
+typedef enum {
+ LDAP_ANDFILTER_TYPE = 0,
+ LDAP_ORFILTER_TYPE = 1,
+ LDAP_NOTFILTER_TYPE = 2,
+ LDAP_EQUALFILTER_TYPE = 3,
+ LDAP_SUBSTRINGFILTER_TYPE = 4,
+ LDAP_GREATEROREQUALFILTER_TYPE = 5,
+ LDAP_LESSOREQUALFILTER_TYPE = 6,
+ LDAP_PRESENTFILTER_TYPE = 7,
+ LDAP_APPROXMATCHFILTER_TYPE = 8
+} LDAPFilterType;
+
+typedef enum {
+ LDAP_BIND_TYPE = 0,
+ LDAP_BINDRESPONSE_TYPE = 1,
+ LDAP_UNBIND_TYPE = 2,
+ LDAP_SEARCH_TYPE = 3,
+ LDAP_SEARCHRESPONSEENTRY_TYPE = 4,
+ LDAP_SEARCHRESPONSERESULT_TYPE = 5,
+ LDAP_ABANDONREQUEST_TYPE = 16
+} LDAPMessageType;
+
+typedef enum {
+ SUCCESS = 0,
+ OPERATIONSERROR = 1,
+ PROTOCOLERROR = 2,
+ TIMELIMITEXCEEDED = 3,
+ SIZELIMITEXCEEDED = 4,
+ COMPAREFALSE = 5,
+ COMPARETRUE = 6,
+ AUTHMETHODNOTSUPPORTED = 7,
+ STRONGAUTHREQUIRED = 8,
+ NOSUCHATTRIBUTE = 16,
+ UNDEFINEDATTRIBUTETYPE = 17,
+ INAPPROPRIATEMATCHING = 18,
+ CONSTRAINTVIOLATION = 19,
+ ATTRIBUTEORVALUEEXISTS = 20,
+ INVALIDATTRIBUTESYNTAX = 21,
+ NOSUCHOBJECT = 32,
+ ALIASPROBLEM = 33,
+ INVALIDDNSYNTAX = 34,
+ ISLEAF = 35,
+ ALIASDEREFERENCINGPROBLEM = 36,
+ INAPPROPRIATEAUTHENTICATION = 48,
+ INVALIDCREDENTIALS = 49,
+ INSUFFICIENTACCESSRIGHTS = 50,
+ BUSY = 51,
+ UNAVAILABLE = 52,
+ UNWILLINGTOPERFORM = 53,
+ LOOPDETECT = 54,
+ NAMINGVIOLATION = 64,
+ OBJECTCLASSVIOLATION = 65,
+ NOTALLOWEDONNONLEAF = 66,
+ NOTALLOWEDONRDN = 67,
+ ENTRYALREADYEXISTS = 68,
+ OBJECTCLASSMODSPROHIBITED = 69,
+ OTHER = 80
+} LDAPResultCode;
+
+typedef struct LDAPLocationStruct LDAPLocation;
+typedef struct LDAPCertPairStruct LDAPCertPair;
+typedef struct LDAPSimpleBindStruct LDAPSimpleBind;
+typedef struct LDAPBindAPIStruct LDAPBindAPI;
+typedef struct LDAPBindStruct LDAPBind;
+typedef struct LDAPResultStruct LDAPBindResponse;
+typedef struct LDAPResultStruct LDAPResult;
+typedef struct LDAPSearchResponseAttrStruct LDAPSearchResponseAttr;
+typedef struct LDAPSearchResponseEntryStruct LDAPSearchResponseEntry;
+typedef struct LDAPResultStruct LDAPSearchResponseResult;
+typedef struct LDAPUnbindStruct LDAPUnbind;
+typedef struct LDAPFilterStruct LDAPFilter;
+typedef struct LDAPAndFilterStruct LDAPAndFilter;
+typedef struct LDAPNotFilterStruct LDAPNotFilter;
+typedef struct LDAPSubstringStruct LDAPSubstring;
+typedef struct LDAPSubstringFilterStruct LDAPSubstringFilter;
+typedef struct LDAPPresentFilterStruct LDAPPresentFilter;
+typedef struct LDAPAttributeValueAssertionStruct LDAPAttributeValueAssertion;
+typedef struct LDAPNameComponentStruct LDAPNameComponent;
+typedef struct LDAPRequestParamsStruct LDAPRequestParams;
+typedef struct LDAPSearchStruct LDAPSearch;
+typedef struct LDAPAbandonRequestStruct LDAPAbandonRequest;
+typedef struct protocolOpStruct LDAPProtocolOp;
+typedef struct LDAPMessageStruct LDAPMessage;
+typedef LDAPAndFilter LDAPOrFilter;
+typedef LDAPAttributeValueAssertion LDAPEqualFilter;
+typedef LDAPAttributeValueAssertion LDAPGreaterOrEqualFilter;
+typedef LDAPAttributeValueAssertion LDAPLessOrEqualFilter;
+typedef LDAPAttributeValueAssertion LDAPApproxMatchFilter;
+
+struct LDAPLocationStruct {
+ PLArenaPool *arena;
+ void *serverSite;
+ void **filterString;
+ void **attrBitString;
+};
+
+struct LDAPCertPairStruct {
+ SECItem forward;
+ SECItem reverse;
+};
+
+struct LDAPSimpleBindStruct {
+ char *bindName;
+ char *authentication;
+};
+
+struct LDAPBindAPIStruct {
+ AuthType selector;
+ union {
+ LDAPSimpleBind simple;
+ } chooser;
+};
+
+struct LDAPBindStruct {
+ SECItem version;
+ SECItem bindName;
+ SECItem authentication;
+};
+
+struct LDAPResultStruct {
+ SECItem resultCode;
+ SECItem matchedDN;
+ SECItem errorMessage;
+};
+
+struct LDAPSearchResponseAttrStruct {
+ SECItem attrType;
+ SECItem **val;
+};
+
+struct LDAPSearchResponseEntryStruct {
+ SECItem objectName;
+ LDAPSearchResponseAttr **attributes;
+};
+
+struct LDAPUnbindStruct {
+ SECItem dummy;
+};
+
+struct LDAPAndFilterStruct {
+ LDAPFilter **filters;
+};
+
+struct LDAPNotFilterStruct {
+ LDAPFilter *filter;
+};
+
+struct LDAPSubstringStruct {
+ LDAPSubstringFilterType selector;
+ SECItem item;
+};
+
+struct LDAPSubstringFilterStruct {
+ SECItem attrType;
+ LDAPSubstring *strings;
+};
+
+struct LDAPPresentFilterStruct {
+ SECItem attrType;
+};
+
+struct LDAPAttributeValueAssertionStruct {
+ SECItem attrType;
+ SECItem attrValue;
+};
+
+struct LDAPFilterStruct {
+ LDAPFilterType selector;
+ union {
+ LDAPAndFilter andFilter;
+ LDAPOrFilter orFilter;
+ LDAPNotFilter notFilter;
+ LDAPEqualFilter equalFilter;
+ LDAPSubstringFilter substringFilter;
+ LDAPGreaterOrEqualFilter greaterOrEqualFilter;
+ LDAPLessOrEqualFilter lessOrEqualFilter;
+ LDAPPresentFilter presentFilter;
+ LDAPApproxMatchFilter approxMatchFilter;
+ } filter;
+};
+
+struct LDAPNameComponentStruct {
+ unsigned char *attrType;
+ unsigned char *attrValue;
+};
+
+struct LDAPRequestParamsStruct {
+ char *baseObject; /* e.g. "c=US" */
+ ScopeType scope;
+ DerefType derefAliases;
+ PKIX_UInt32 sizeLimit; /* 0 = no limit */
+ PRIntervalTime timeLimit; /* 0 = no limit */
+ LDAPNameComponent **nc; /* e.g. {{"cn","xxx"},{"o","yyy"},NULL} */
+ LdapAttrMask attributes;
+};
+
+struct LDAPSearchStruct {
+ SECItem baseObject;
+ SECItem scope;
+ SECItem derefAliases;
+ SECItem sizeLimit;
+ SECItem timeLimit;
+ SECItem attrsOnly;
+ LDAPFilter filter;
+ SECItem **attributes;
+};
+
+struct LDAPAbandonRequestStruct {
+ SECItem messageID;
+};
+
+struct protocolOpStruct {
+ LDAPMessageType selector;
+ union {
+ LDAPBind bindMsg;
+ LDAPBindResponse bindResponseMsg;
+ LDAPUnbind unbindMsg;
+ LDAPSearch searchMsg;
+ LDAPSearchResponseEntry searchResponseEntryMsg;
+ LDAPSearchResponseResult searchResponseResultMsg;
+ LDAPAbandonRequest abandonRequestMsg;
+ } op;
+};
+
+struct LDAPMessageStruct {
+ SECItem messageID;
+ LDAPProtocolOp protocolOp;
+};
+
+typedef struct PKIX_PL_LdapClientStruct PKIX_PL_LdapClient;
+
+typedef PKIX_Error *
+(*PKIX_PL_LdapClient_InitiateFcn)(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext);
+
+typedef PKIX_Error *
+(*PKIX_PL_LdapClient_ResumeFcn)(
+ PKIX_PL_LdapClient *client,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext);
+
+struct PKIX_PL_LdapClientStruct {
+ PKIX_PL_LdapClient_InitiateFcn initiateFcn;
+ PKIX_PL_LdapClient_ResumeFcn resumeFcn;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c
new file mode 100644
index 0000000000..ecb681929b
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c
@@ -0,0 +1,417 @@
+/* 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/. */
+
+#include "pkix_pl_ldapt.h"
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_NullTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+
+/*
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL
+ * -- at least one of the pair shall be present --
+ * }
+ */
+
+const SEC_ASN1Template PKIX_PL_LDAPCrossCertPairTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(LDAPCertPair) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0,
+ offsetof(LDAPCertPair, forward), SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 1,
+ offsetof(LDAPCertPair, reverse), SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { 0 }
+};
+
+/*
+ * BindRequest ::=
+ * [APPLICATION 0] SEQUENCE {
+ * version INTEGER (1..127),
+ * name LDAPDN,
+ * authentication CHOICE {
+ * simple [0] OCTET STRING,
+ * krbv42LDAP [1] OCTET STRING,
+ * krbv42DSA [2] OCTET STRING
+ * }
+ * }
+ *
+ * LDAPDN ::= LDAPString
+ *
+ * LDAPString ::= OCTET STRING
+ */
+
+#define LDAPStringTemplate SEC_ASN1_SUB(SEC_OctetStringTemplate)
+
+static const SEC_ASN1Template LDAPBindApplTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_INTEGER, offsetof(LDAPBind, version) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPBind, bindName) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPBind, authentication) },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPBindTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_BIND_TYPE, 0,
+ LDAPBindApplTemplate, sizeof (LDAPBind) }
+};
+
+/*
+ * BindResponse ::= [APPLICATION 1] LDAPResult
+ *
+ * LDAPResult ::=
+ * SEQUENCE {
+ * resultCode ENUMERATED {
+ * success (0),
+ * operationsError (1),
+ * protocolError (2),
+ * timeLimitExceeded (3),
+ * sizeLimitExceeded (4),
+ * compareFalse (5),
+ * compareTrue (6),
+ * authMethodNotSupported (7),
+ * strongAuthRequired (8),
+ * noSuchAttribute (16),
+ * undefinedAttributeType (17),
+ * inappropriateMatching (18),
+ * constraintViolation (19),
+ * attributeOrValueExists (20),
+ * invalidAttributeSyntax (21),
+ * noSuchObject (32),
+ * aliasProblem (33),
+ * invalidDNSyntax (34),
+ * isLeaf (35),
+ * aliasDereferencingProblem (36),
+ * inappropriateAuthentication (48),
+ * invalidCredentials (49),
+ * insufficientAccessRights (50),
+ * busy (51),
+ * unavailable (52),
+ * unwillingToPerform (53),
+ * loopDetect (54),
+ * namingViolation (64),
+ * objectClassViolation (65),
+ * notAllowedOnNonLeaf (66),
+ * notAllowedOnRDN (67),
+ * entryAlreadyExists (68),
+ * objectClassModsProhibited (69),
+ * other (80)
+ * },
+ * matchedDN LDAPDN,
+ * errorMessage LDAPString
+ * }
+ */
+
+static const SEC_ASN1Template LDAPResultTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_ENUMERATED, offsetof(LDAPResult, resultCode) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPResult, matchedDN) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPResult, errorMessage) },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPBindResponseTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_BINDRESPONSE_TYPE, 0,
+ LDAPResultTemplate, sizeof (LDAPBindResponse) }
+};
+
+/*
+ * UnbindRequest ::= [APPLICATION 2] NULL
+ */
+
+static const SEC_ASN1Template LDAPUnbindTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | SEC_ASN1_XTRN |
+ LDAP_UNBIND_TYPE , 0, SEC_ASN1_SUB(SEC_NullTemplate) }
+};
+
+/*
+ * AttributeValueAssertion ::=
+ * SEQUENCE {
+ * attributeType AttributeType,
+ * attributeValue AttributeValue,
+ * }
+ *
+ * AttributeType ::= LDAPString
+ * -- text name of the attribute, or dotted
+ * -- OID representation
+ *
+ * AttributeValue ::= OCTET STRING
+ */
+
+#define LDAPAttributeTypeTemplate LDAPStringTemplate
+
+/*
+ * SubstringFilter ::=
+ * SEQUENCE {
+ * type AttributeType,
+ * SEQUENCE OF CHOICE {
+ * initial [0] LDAPString,
+ * any [1] LDAPString,
+ * final [2] LDAPString,
+ * }
+ * }
+ */
+
+#define LDAPSubstringFilterInitialTemplate LDAPStringTemplate
+#define LDAPSubstringFilterAnyTemplate LDAPStringTemplate
+#define LDAPSubstringFilterFinalTemplate LDAPStringTemplate
+
+static const SEC_ASN1Template LDAPSubstringFilterChoiceTemplate[] = {
+ { SEC_ASN1_CHOICE, offsetof(LDAPSubstring, selector), 0,
+ sizeof (LDAPFilter) },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+ offsetof(LDAPSubstring, item),
+ LDAPSubstringFilterInitialTemplate,
+ LDAP_INITIALSUBSTRING_TYPE },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
+ offsetof(LDAPSubstring, item),
+ LDAPSubstringFilterAnyTemplate,
+ LDAP_ANYSUBSTRING_TYPE },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
+ offsetof(LDAPSubstring, item),
+ LDAPSubstringFilterFinalTemplate,
+ LDAP_FINALSUBSTRING_TYPE },
+ { 0 }
+};
+
+/*
+ * Filter ::=
+ * CHOICE {
+ * and [0] SET OF Filter,
+ * or [1] SET OF Filter,
+ * not [2] Filter,
+ * equalityMatch [3] AttributeValueAssertion,
+ * substrings [4] SubstringFilter,
+ * greaterOrEqual [5] AttributeValueAssertion,
+ * lessOrEqual [6] AttributeValueAssertion,
+ * present [7] AttributeType,
+ * approxMatch [8] AttributeValueAssertion
+ }
+ */
+
+static const SEC_ASN1Template LDAPSubstringFilterTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (LDAPSubstringFilter) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSubstringFilter, attrType) },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSubstringFilter, strings),
+ LDAPSubstringFilterChoiceTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template LDAPFilterTemplate[]; /* forward reference */
+
+static const SEC_ASN1Template LDAPSetOfFiltersTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, LDAPFilterTemplate }
+};
+
+static const SEC_ASN1Template LDAPAVAFilterTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (LDAPAttributeValueAssertion) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPAttributeValueAssertion, attrType) },
+ { SEC_ASN1_OCTET_STRING, offsetof(LDAPAttributeValueAssertion, attrValue) },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPPresentFilterTemplate[] = {
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPPresentFilter, attrType) }
+};
+
+#define LDAPEqualFilterTemplate LDAPAVAFilterTemplate
+#define LDAPGreaterOrEqualFilterTemplate LDAPAVAFilterTemplate
+#define LDAPLessOrEqualFilterTemplate LDAPAVAFilterTemplate
+#define LDAPApproxMatchFilterTemplate LDAPAVAFilterTemplate
+
+const SEC_ASN1Template LDAPFilterTemplate[] = {
+ { SEC_ASN1_CHOICE, offsetof(LDAPFilter, selector), 0, sizeof(LDAPFilter) },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_ANDFILTER_TYPE,
+ offsetof(LDAPFilter, filter.andFilter.filters),
+ LDAPSetOfFiltersTemplate, LDAP_ANDFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_ORFILTER_TYPE,
+ offsetof(LDAPFilter, filter.orFilter.filters),
+ LDAPSetOfFiltersTemplate, LDAP_ORFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_NOTFILTER_TYPE | SEC_ASN1_POINTER,
+ offsetof(LDAPFilter, filter.notFilter),
+ LDAPFilterTemplate, LDAP_NOTFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_EQUALFILTER_TYPE,
+ offsetof(LDAPFilter, filter.equalFilter),
+ LDAPEqualFilterTemplate, LDAP_EQUALFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_SUBSTRINGFILTER_TYPE, offsetof(LDAPFilter, filter.substringFilter),
+ LDAPSubstringFilterTemplate, LDAP_SUBSTRINGFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_GREATEROREQUALFILTER_TYPE,
+ offsetof(LDAPFilter, filter.greaterOrEqualFilter),
+ LDAPGreaterOrEqualFilterTemplate, LDAP_GREATEROREQUALFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_LESSOREQUALFILTER_TYPE,
+ offsetof(LDAPFilter, filter.lessOrEqualFilter),
+ LDAPLessOrEqualFilterTemplate, LDAP_LESSOREQUALFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_PRESENTFILTER_TYPE,
+ offsetof(LDAPFilter, filter.presentFilter),
+ LDAPPresentFilterTemplate, LDAP_PRESENTFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_APPROXMATCHFILTER_TYPE,
+ offsetof(LDAPFilter, filter.approxMatchFilter),
+ LDAPApproxMatchFilterTemplate, LDAP_APPROXMATCHFILTER_TYPE },
+ { 0 }
+};
+
+/*
+ * SearchRequest ::=
+ * [APPLICATION 3] SEQUENCE {
+ * baseObject LDAPDN,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefAliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no sizeLimit
+ * timeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no timeLimit
+ * attrsOnly BOOLEAN,
+ * -- TRUE, if only attributes (without values)
+ * -- to be returned
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ */
+
+static const SEC_ASN1Template LDAPAttributeTemplate[] = {
+ { SEC_ASN1_LDAP_STRING, 0, NULL, sizeof (SECItem) }
+};
+
+static const SEC_ASN1Template LDAPSearchApplTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearch, baseObject) },
+ { SEC_ASN1_ENUMERATED, offsetof(LDAPSearch, scope) },
+ { SEC_ASN1_ENUMERATED, offsetof(LDAPSearch, derefAliases) },
+ { SEC_ASN1_INTEGER, offsetof(LDAPSearch, sizeLimit) },
+ { SEC_ASN1_INTEGER, offsetof(LDAPSearch, timeLimit) },
+ { SEC_ASN1_BOOLEAN, offsetof(LDAPSearch, attrsOnly) },
+ { SEC_ASN1_INLINE, offsetof(LDAPSearch, filter), LDAPFilterTemplate },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSearch, attributes), LDAPAttributeTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPSearchTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCH_TYPE, 0,
+ LDAPSearchApplTemplate, sizeof (LDAPSearch) }
+};
+
+/*
+ * SearchResponse ::=
+ * CHOICE {
+ * entry [APPLICATION 4] SEQUENCE {
+ * objectName LDAPDN,
+ * attributes SEQUENCE OF SEQUENCE {
+ * AttributeType,
+ * SET OF AttributeValue
+ * }
+ * }
+ * resultCode [APPLICATION 5] LDAPResult
+ * }
+ */
+
+static const SEC_ASN1Template LDAPSearchResponseAttrTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(LDAPSearchResponseAttr) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearchResponseAttr, attrType) },
+ { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(LDAPSearchResponseAttr, val),
+ LDAPStringTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPEntryTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearchResponseEntry, objectName) },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSearchResponseEntry, attributes),
+ LDAPSearchResponseAttrTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPSearchResponseEntryTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSEENTRY_TYPE, 0,
+ LDAPEntryTemplate, sizeof (LDAPSearchResponseEntry) }
+};
+
+static const SEC_ASN1Template LDAPSearchResponseResultTemplate[] = {
+ { SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSERESULT_TYPE, 0,
+ LDAPResultTemplate, sizeof (LDAPSearchResponseResult) }
+};
+
+/*
+ * AbandonRequest ::=
+ * [APPLICATION 16] MessageID
+ */
+
+static const SEC_ASN1Template LDAPAbandonTemplate[] = {
+ { SEC_ASN1_INTEGER, offsetof(LDAPAbandonRequest, messageID) }
+};
+
+static const SEC_ASN1Template LDAPAbandonRequestTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_ABANDONREQUEST_TYPE, 0,
+ LDAPAbandonTemplate, sizeof (LDAPAbandonRequest) }
+};
+
+/*
+ * LDAPMessage ::=
+ * SEQUENCE {
+ * messageID MessageID,
+ * protocolOp CHOICE {
+ * bindRequest BindRequest,
+ * bindResponse BindResponse,
+ * unbindRequest UnbindRequest,
+ * searchRequest SearchRequest,
+ * searchResponse SearchResponse,
+ * abandonRequest AbandonRequest
+ * }
+ * }
+ *
+ * (other choices exist, not shown)
+ *
+ * MessageID ::= INTEGER (0 .. maxInt)
+ */
+
+static const SEC_ASN1Template LDAPMessageProtocolOpTemplate[] = {
+ { SEC_ASN1_CHOICE, offsetof(LDAPProtocolOp, selector), 0, sizeof (LDAPProtocolOp) },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.bindMsg),
+ LDAPBindTemplate, LDAP_BIND_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.bindResponseMsg),
+ LDAPBindResponseTemplate, LDAP_BINDRESPONSE_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.unbindMsg),
+ LDAPUnbindTemplate, LDAP_UNBIND_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchMsg),
+ LDAPSearchTemplate, LDAP_SEARCH_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchResponseEntryMsg),
+ LDAPSearchResponseEntryTemplate, LDAP_SEARCHRESPONSEENTRY_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchResponseResultMsg),
+ LDAPSearchResponseResultTemplate, LDAP_SEARCHRESPONSERESULT_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.abandonRequestMsg),
+ LDAPAbandonRequestTemplate, LDAP_ABANDONREQUEST_TYPE },
+ { 0 }
+};
+
+const SEC_ASN1Template PKIX_PL_LDAPMessageTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_INTEGER, offsetof(LDAPMessage, messageID) },
+ { SEC_ASN1_INLINE, offsetof(LDAPMessage, protocolOp),
+ LDAPMessageProtocolOpTemplate },
+ { 0 }
+};
+
+/* This function simply returns the address of the message template.
+ * This is necessary for Windows DLLs.
+ */
+SEC_ASN1_CHOOSER_IMPLEMENT(PKIX_PL_LDAPMessageTemplate)
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c
new file mode 100644
index 0000000000..966c6f37e4
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c
@@ -0,0 +1,389 @@
+/* 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_nsscontext.c
+ *
+ * NSSContext Function Definitions
+ *
+ */
+
+
+#include "pkix_pl_nsscontext.h"
+
+#define PKIX_DEFAULT_MAX_RESPONSE_LENGTH 64 * 1024
+#define PKIX_DEFAULT_COMM_TIMEOUT_SECONDS 60
+
+#define PKIX_DEFAULT_CRL_RELOAD_DELAY_SECONDS 6 * 24 * 60 * 60
+#define PKIX_DEFAULT_BAD_CRL_RELOAD_DELAY_SECONDS 60 * 60
+
+/* --Public-NSSContext-Functions--------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_NssContext_Create(
+ PKIX_UInt32 certificateUsage,
+ PKIX_Boolean useNssArena,
+ void *wincx,
+ void **pNssContext)
+{
+ PKIX_PL_NssContext *context = NULL;
+ PLArenaPool *arena = NULL;
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_Create");
+ PKIX_NULLCHECK_ONE(pNssContext);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (sizeof(PKIX_PL_NssContext), (void **)&context, NULL),
+ PKIX_MALLOCFAILED);
+
+ if (useNssArena == PKIX_TRUE) {
+ PKIX_CONTEXT_DEBUG("\t\tCalling PORT_NewArena\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ }
+
+ context->arena = arena;
+ context->certificateUsage = (SECCertificateUsage)certificateUsage;
+ context->wincx = wincx;
+ context->timeoutSeconds = PKIX_DEFAULT_COMM_TIMEOUT_SECONDS;
+ context->maxResponseLength = PKIX_DEFAULT_MAX_RESPONSE_LENGTH;
+ context->crlReloadDelay = PKIX_DEFAULT_CRL_RELOAD_DELAY_SECONDS;
+ context->badDerCrlReloadDelay =
+ PKIX_DEFAULT_BAD_CRL_RELOAD_DELAY_SECONDS;
+ context->certSignatureCheck = PKIX_TRUE;
+ context->chainVerifyCallback.isChainValid = NULL;
+ context->chainVerifyCallback.isChainValidArg = NULL;
+ *pNssContext = context;
+
+cleanup:
+
+ PKIX_RETURN(CONTEXT);
+}
+
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_Destroy
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_NssContext_Destroy(
+ void *nssContext)
+{
+ void *plContext = NULL;
+ PKIX_PL_NssContext *context = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_Destroy");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ context = (PKIX_PL_NssContext*)nssContext;
+
+ if (context->arena != NULL) {
+ PKIX_CONTEXT_DEBUG("\t\tCalling PORT_FreeArena\n");
+ PORT_FreeArena(context->arena, PKIX_FALSE);
+ }
+
+ PKIX_PL_Free(nssContext, NULL);
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_GetCertUsage
+ * DESCRIPTION:
+ *
+ * This function obtains the platform-dependent SECCertificateUsage parameter
+ * from the context object pointed to by "nssContext", storing the result at
+ * "pCertUsage".
+ *
+ * PARAMETERS:
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * "pCertUsage"
+ * The address where the result is stored. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_GetCertUsage(
+ PKIX_PL_NssContext *nssContext,
+ SECCertificateUsage *pCertUsage)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetCertUsage");
+ PKIX_NULLCHECK_TWO(nssContext, pCertUsage);
+
+ *pCertUsage = nssContext->certificateUsage;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_SetCertUsage
+ * DESCRIPTION:
+ *
+ * This function sets the platform-dependent SECCertificateUsage parameter in
+ * the context object pointed to by "nssContext" to the value provided in
+ * "certUsage".
+ *
+ * PARAMETERS:
+ * "certUsage"
+ * Platform-dependent value to be stored.
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_SetCertUsage(
+ SECCertificateUsage certUsage,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetCertUsage");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->certificateUsage = certUsage;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_GetCertSignatureCheck
+ * DESCRIPTION:
+ *
+ * This function obtains the platform-dependent flag to turn on or off
+ * signature checks.
+ *
+ * PARAMETERS:
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * "pCheckSig"
+ * The address where the result is stored. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_GetCertSignatureCheck(
+ PKIX_PL_NssContext *nssContext,
+ PKIX_Boolean *pCheckSig)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetCertUsage");
+ PKIX_NULLCHECK_TWO(nssContext, pCheckSig);
+
+ *pCheckSig = nssContext->certSignatureCheck;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_SetCertSignatureCheck
+ * DESCRIPTION:
+ *
+ * This function sets the check signature flag in
+ * the context object pointed to by "nssContext" to the value provided in
+ * "checkSig".
+ *
+ * PARAMETERS:
+ * "checkSig"
+ * Boolean that tells whether or not to check the signatues on certs.
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_SetCertSignatureCheck(
+ PKIX_Boolean checkSig,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetCertUsage");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->certSignatureCheck = checkSig;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_GetWincx
+ * DESCRIPTION:
+ *
+ * This function obtains the platform-dependent wincx parameter from the
+ * context object pointed to by "nssContext", storing the result at "pWincx".
+ *
+ * PARAMETERS:
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * "pWincx"
+ * The address where the result is stored. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_GetWincx(
+ PKIX_PL_NssContext *nssContext,
+ void **pWincx)
+{
+ void *plContext = NULL;
+ PKIX_PL_NssContext *context = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetWincx");
+ PKIX_NULLCHECK_TWO(nssContext, pWincx);
+
+ context = (PKIX_PL_NssContext *)nssContext;
+
+ *pWincx = context->wincx;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_SetWincx
+ * DESCRIPTION:
+ *
+ * This function sets the platform-dependent wincx parameter in the context
+ * object pointed to by "nssContext" to the value provided in "wincx".
+ *
+ * PARAMETERS:
+ * "wincx"
+ * Platform-dependent value to be stored.
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_SetWincx(
+ void *wincx,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetWincx");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->wincx = wincx;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetTimeout
+ * DESCRIPTION:
+ *
+ * Sets user defined socket timeout for the validation
+ * session. Default is 60 seconds.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetTimeout(PKIX_UInt32 timeout,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetTimeout");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->timeoutSeconds = timeout;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetMaxResponseLen
+ * DESCRIPTION:
+ *
+ * Sets user defined maximum transmission length of a message.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetMaxResponseLen(PKIX_UInt32 len,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetMaxResponseLen");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->maxResponseLength = len;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetCrlReloadDelay
+ * DESCRIPTION:
+ *
+ * Sets user defined delay between attempts to load crl using
+ * CRLDP.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetCrlReloadDelay(PKIX_UInt32 delay,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetCrlReloadDelay");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->crlReloadDelay = delay;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetBadDerCrlReloadDelay
+ * DESCRIPTION:
+ *
+ * Sets user defined delay between attempts to load crl that
+ * failed to decode.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetBadDerCrlReloadDelay(PKIX_UInt32 delay,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetBadDerCrlReloadDelay");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->badDerCrlReloadDelay = delay;
+
+ PKIX_RETURN(CONTEXT);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h
new file mode 100644
index 0000000000..5de44214e5
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h
@@ -0,0 +1,61 @@
+/* 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_nsscontext.h
+ *
+ * NSSContext Object Type Definition
+ *
+ */
+
+
+#ifndef _PKIX_PL_NSSCONTEXT_H
+#define _PKIX_PL_NSSCONTEXT_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_NssContextStruct {
+ SECCertificateUsage certificateUsage;
+ PLArenaPool *arena;
+ void *wincx;
+ PKIX_UInt32 timeoutSeconds;
+ PKIX_UInt32 maxResponseLength;
+ PRTime crlReloadDelay;
+ PRTime badDerCrlReloadDelay;
+ CERTChainVerifyCallback chainVerifyCallback;
+ PKIX_Boolean certSignatureCheck;
+};
+
+PKIX_Error *
+pkix_pl_NssContext_GetCertUsage
+ (PKIX_PL_NssContext *nssContext, SECCertificateUsage *pCertUsage);
+
+/* XXX move the setter into the public header. */
+PKIX_Error *
+pkix_pl_NssContext_SetCertUsage
+ (SECCertificateUsage certUsage, PKIX_PL_NssContext *nssContext);
+
+PKIX_Error *
+pkix_pl_NssContext_GetCertSignatureCheck
+ (PKIX_PL_NssContext *nssContext, PKIX_Boolean *pCheckSig);
+
+PKIX_Error *
+pkix_pl_NssContext_SetCertSignatureCheck
+ (PKIX_Boolean checkSig, PKIX_PL_NssContext *nssContext);
+
+PKIX_Error *
+pkix_pl_NssContext_GetWincx(PKIX_PL_NssContext *nssContext, void **pWincx);
+
+/* XXX move the setter into the public header. */
+PKIX_Error *
+pkix_pl_NssContext_SetWincx(void *wincx, PKIX_PL_NssContext *nssContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_NSSCONTEXT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c
new file mode 100644
index 0000000000..7de614ea68
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c
@@ -0,0 +1,1039 @@
+/* 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_pk11certstore.c
+ *
+ * PKCS11CertStore Function Definitions
+ *
+ */
+
+#include "pkix_pl_pk11certstore.h"
+
+/*
+ * PKIX_DEFAULT_MAX_RESPONSE_LENGTH (64 * 1024) is too small for downloading
+ * CRLs. We observed CRLs of sizes 338759 and 439035 in practice. So we
+ * need to use a higher max response length for CRLs.
+ */
+#define PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH (512 * 1024)
+
+/* --Private-Pk11CertStore-Functions---------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CheckTrust
+ * DESCRIPTION:
+ * This function checks the trust status of this "cert" that was retrieved
+ * from the CertStore "store" and returns its trust status at "pTrusted".
+ *
+ * PARAMETERS:
+ * "store"
+ * Address of the CertStore. Must be non-NULL.
+ * "cert"
+ * Address of the Cert. Must be non-NULL.
+ * "pTrusted"
+ * Address of PKIX_Boolean where the "cert" trust status is returned.
+ * 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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CheckTrust(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ SECCertUsage certUsage = 0;
+ SECCertificateUsage certificateUsage;
+ unsigned int requiredFlags;
+ SECTrustType trustType;
+ CERTCertTrust trust;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckTrust");
+ PKIX_NULLCHECK_THREE(store, cert, pTrusted);
+ PKIX_NULLCHECK_ONE(cert->nssCert);
+
+ certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
+
+ /* ensure we obtained a single usage bit only */
+ PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
+
+ /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
+ while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
+
+ rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType);
+ if (rv == SECSuccess) {
+ rv = CERT_GetCertTrust(cert->nssCert, &trust);
+ }
+
+ if (rv == SECSuccess) {
+ unsigned int certFlags;
+
+ if (certUsage != certUsageAnyCA &&
+ certUsage != certUsageStatusResponder) {
+ CERTCertificate *nssCert = cert->nssCert;
+
+ if (certUsage == certUsageVerifyCA) {
+ if (nssCert->nsCertType & NS_CERT_TYPE_EMAIL_CA) {
+ trustType = trustEmail;
+ } else if (nssCert->nsCertType & NS_CERT_TYPE_SSL_CA) {
+ trustType = trustSSL;
+ } else {
+ trustType = trustObjectSigning;
+ }
+ }
+
+ certFlags = SEC_GET_TRUST_FLAGS((&trust), trustType);
+ if ((certFlags & requiredFlags) == requiredFlags) {
+ trusted = PKIX_TRUE;
+ }
+ } else {
+ for (trustType = trustSSL; trustType < trustTypeNone;
+ trustType++) {
+ certFlags =
+ SEC_GET_TRUST_FLAGS((&trust), trustType);
+ if ((certFlags & requiredFlags) == requiredFlags) {
+ trusted = PKIX_TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ *pTrusted = trusted;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CertQuery
+ * DESCRIPTION:
+ *
+ * This function obtains from the database the Certs specified by the
+ * ComCertSelParams pointed to by "params" and stores the resulting
+ * List at "pSelected". If no matching Certs are found, a NULL pointer
+ * will be stored.
+ *
+ * This function uses a "smart" database query if the Subject has been set
+ * in ComCertSelParams. Otherwise, it uses a very inefficient call to
+ * retrieve all Certs in the database (and run them through the selector).
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCertSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be 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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CertQuery(
+ PKIX_ComCertSelParams *params,
+ PKIX_List **pSelected,
+ void *plContext)
+{
+ PRBool validOnly = PR_FALSE;
+ PRTime prtime = 0;
+ PKIX_PL_X500Name *subjectName = NULL;
+ PKIX_PL_Date *certValid = NULL;
+ PKIX_List *certList = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ CERTCertList *pk11CertList = NULL;
+ CERTCertListNode *node = NULL;
+ CERTCertificate *nssCert = NULL;
+ CERTCertDBHandle *dbHandle = NULL;
+
+ PLArenaPool *arena = NULL;
+ SECItem *nameItem = NULL;
+ void *wincx = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CertQuery");
+ PKIX_NULLCHECK_TWO(params, pSelected);
+
+ /* avoid multiple calls to retrieve a constant */
+ PKIX_PL_NSSCALLRV(CERTSTORE, dbHandle, CERT_GetDefaultCertDB, ());
+
+ /*
+ * Any of the ComCertSelParams may be obtained and used to constrain
+ * the database query, to allow the use of a "smart" query. See
+ * pkix_certsel.h for a list of the PKIX_ComCertSelParams_Get*
+ * calls available. No corresponding "smart" queries exist at present,
+ * except for CERT_CreateSubjectCertList based on Subject. When others
+ * are added, corresponding code should be added to
+ * pkix_pl_Pk11CertStore_CertQuery to use them when appropriate
+ * selector parameters have been set.
+ */
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
+ (params, &subjectName, plContext),
+ PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetCertificateValid
+ (params, &certValid, plContext),
+ PKIX_COMCERTSELPARAMSGETCERTIFICATEVALIDFAILED);
+
+ /* If caller specified a Date, convert it to PRTime */
+ if (certValid) {
+ PKIX_CHECK(pkix_pl_Date_GetPRTime
+ (certValid, &prtime, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ validOnly = PR_TRUE;
+ }
+
+ /*
+ * If we have the subject name for the desired subject,
+ * ask the database for Certs with that subject. Otherwise
+ * ask the database for all Certs.
+ */
+ if (subjectName) {
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena) {
+
+ PKIX_CHECK(pkix_pl_X500Name_GetDERName
+ (subjectName, arena, &nameItem, plContext),
+ PKIX_X500NAMEGETSECNAMEFAILED);
+
+ if (nameItem) {
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ pk11CertList,
+ CERT_CreateSubjectCertList,
+ (NULL, dbHandle, nameItem, prtime, validOnly));
+ }
+ PKIX_PL_NSSCALL
+ (CERTSTORE, PORT_FreeArena, (arena, PR_FALSE));
+ arena = NULL;
+ }
+
+ } else {
+
+ PKIX_CHECK(pkix_pl_NssContext_GetWincx
+ ((PKIX_PL_NssContext *)plContext, &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ pk11CertList,
+ PK11_ListCerts,
+ (PK11CertListAll, wincx));
+ }
+
+ if (pk11CertList) {
+
+ PKIX_CHECK(PKIX_List_Create(&certList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (node = CERT_LIST_HEAD(pk11CertList);
+ !(CERT_LIST_END(node, pk11CertList));
+ node = CERT_LIST_NEXT(node)) {
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ nssCert,
+ CERT_DupCertificate,
+ (node->cert));
+
+ if (!nssCert) {
+ continue; /* just skip bad certs */
+ }
+
+ PKIX_CHECK_ONLY_FATAL(pkix_pl_Cert_CreateWithNSSCert
+ (nssCert, &cert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+ if (PKIX_ERROR_RECEIVED) {
+ CERT_DestroyCertificate(nssCert);
+ nssCert = NULL;
+ continue; /* just skip bad certs */
+ }
+
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
+ (certList, (PKIX_PL_Object *)cert, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(cert);
+
+ }
+
+ /* Don't throw away the list if one cert was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+ }
+
+ *pSelected = certList;
+ certList = NULL;
+
+cleanup:
+
+ if (pk11CertList) {
+ CERT_DestroyCertList(pk11CertList);
+ }
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ PKIX_DECREF(subjectName);
+ PKIX_DECREF(certValid);
+ PKIX_DECREF(cert);
+ PKIX_DECREF(certList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_ImportCrl
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCRLSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be 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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_ImportCrl(
+ PKIX_CertStore *store,
+ PKIX_PL_X500Name *issuerName,
+ PKIX_List *crlList,
+ void *plContext)
+{
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+ PKIX_PL_CRL *crl = NULL;
+ SECItem *derCrl = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ImportCrl");
+ PKIX_NULLCHECK_TWO(store, plContext);
+
+ if (!crlList) {
+ goto cleanup;
+ }
+ while (crlList->length > 0) {
+ PKIX_CHECK(
+ PKIX_List_GetItem(crlList, 0, (PKIX_PL_Object**)&crl,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ /* Delete crl from the list to keep controll of the
+ * last reference. crl need to be destroyed right after
+ * it released the ownership of the crl der. */
+ PKIX_CHECK(
+ PKIX_List_DeleteItem(crlList, 0, plContext),
+ PKIX_LISTDELETEITEMFAILED);
+
+ /* acquire the crlder ownership */
+ pkixErrorResult =
+ PKIX_PL_CRL_ReleaseDerCrl(crl, &derCrl, plContext);
+ PORT_Assert(!pkixErrorResult && derCrl);
+ if (pkixErrorResult || !derCrl) {
+ /* All pkix delivered crls should be able to
+ * release their ders. */
+ PKIX_DECREF(pkixErrorResult);
+ PKIX_DECREF(crl);
+ continue;
+ }
+ cert_CacheCRLByGeneralName(certHandle, derCrl,
+ crl->derGenName);
+ /* Do not check the status. If it is a SECFailure,
+ * derCrl is already destroyed. */
+ derCrl = NULL;
+ PKIX_DECREF(crl);
+ }
+
+cleanup:
+ PKIX_DECREF(crl);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+static PKIX_Error *
+NameCacheHasFetchedCrlInfo(PKIX_PL_Cert *pkixCert,
+ PRTime time,
+ PKIX_Boolean *pHasFetchedCrlInCache,
+ void *plContext)
+{
+ /* Returning true result in this case will mean, that case info
+ * is currect and should used as is. */
+ NamedCRLCache* nameCrlCache = NULL;
+ PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
+ PKIX_List *dpList = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ PKIX_UInt32 dpIndex = 0;
+ SECStatus rv = SECSuccess;
+ PRTime reloadDelay = 0, badCrlInvalDelay = 0;
+
+ PKIX_ENTER(CERTSTORE, "ChechCacheHasFetchedCrl");
+
+ reloadDelay =
+ ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
+ PR_USEC_PER_SEC;
+ badCrlInvalDelay =
+ ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
+ PR_USEC_PER_SEC;
+ if (!time) {
+ time = PR_Now();
+ }
+ /* If we already download the crl and inserted into the cache, then
+ * there is no need to check for fetched crl. We have what we have. */
+ PKIX_CHECK(
+ PKIX_PL_Cert_GetCrlDp(pkixCert, &dpList, plContext),
+ PKIX_CERTGETCRLDPFAILED);
+ if (dpList && dpList->length) {
+ hasFetchedCrlInCache = PKIX_FALSE;
+ rv = cert_AcquireNamedCRLCache(&nameCrlCache);
+ if (rv != SECSuccess) {
+ PKIX_DECREF(dpList);
+ }
+ } else {
+ /* If no dp then treat it as if we already have
+ * a fetched crl. */
+ PKIX_DECREF(dpList);
+ }
+ for (;!hasFetchedCrlInCache &&
+ dpList && dpIndex < dpList->length;dpIndex++) {
+ SECItem **derDpNames = NULL;
+ pkixErrorResult =
+ PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ if (dp->nssdp->distPointType == generalName) {
+ /* dp can only be created from nssdp. */
+ derDpNames = dp->nssdp->derFullName;
+ }
+ while (derDpNames && *derDpNames != NULL) {
+ NamedCRLCacheEntry* cacheEntry = NULL;
+ const SECItem *derDpName = *derDpNames++;
+ rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
+ &cacheEntry);
+ if (rv == SECSuccess && cacheEntry) {
+ if ((cacheEntry->inCRLCache &&
+ (cacheEntry->successfulInsertionTime + reloadDelay > time ||
+ (cacheEntry->dupe &&
+ cacheEntry->lastAttemptTime + reloadDelay > time))) ||
+ (cacheEntry->badDER &&
+ cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
+ hasFetchedCrlInCache = PKIX_TRUE;
+ break;
+ }
+ }
+ }
+ PKIX_DECREF(dp);
+ }
+cleanup:
+ *pHasFetchedCrlInCache = hasFetchedCrlInCache;
+ if (nameCrlCache) {
+ cert_ReleaseNamedCRLCache(nameCrlCache);
+ }
+ PKIX_DECREF(dpList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CheckCrl
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCRLSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be 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 CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CheckRevByCrl(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *pkixCert,
+ PKIX_PL_Cert *pkixIssuer,
+ PKIX_PL_Date *date,
+ PKIX_Boolean crlDownloadDone,
+ CERTCRLEntryReasonCode *pReasonCode,
+ PKIX_RevocationStatus *pStatus,
+ void *plContext)
+{
+ PKIX_RevocationStatus pkixRevStatus = PKIX_RevStatus_NoInfo;
+ CERTRevocationStatus revStatus = certRevocationStatusUnknown;
+ PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
+ CERTCertificate *cert = NULL, *issuer = NULL;
+ SECStatus rv = SECSuccess;
+ void *wincx = NULL;
+ PRTime time = 0;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckRevByCrl");
+ PKIX_NULLCHECK_FOUR(store, pkixCert, pkixIssuer, plContext);
+
+ cert = pkixCert->nssCert;
+ issuer = pkixIssuer->nssCert;
+ if (date) {
+ PKIX_CHECK(
+ pkix_pl_Date_GetPRTime(date, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ }
+ PKIX_CHECK(
+ pkix_pl_NssContext_GetWincx((PKIX_PL_NssContext*)plContext,
+ &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+ /* No need to check any cDPs, since partitioned crls are not
+ * supported. If a ds does not point to partitioned crl, then
+ * the crl should be in issuer cache that is unrelated to any
+ * dp. Using NULL as a dp pointer to check it.*/
+ rv = cert_CheckCertRevocationStatus(cert, issuer, NULL,
+ /* Will not validate the signature
+ * on the crl if time is not specified.*/
+ time, wincx, &revStatus, pReasonCode);
+ if (rv == SECFailure) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ goto cleanup;
+ }
+ if (crlDownloadDone) {
+ if (revStatus == certRevocationStatusRevoked) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ } else if (revStatus == certRevocationStatusValid) {
+ pkixRevStatus = PKIX_RevStatus_Success;
+ }
+ } else {
+ pkixErrorResult =
+ NameCacheHasFetchedCrlInfo(pkixCert, time, &hasFetchedCrlInCache,
+ plContext);
+ if (pkixErrorResult) {
+ goto cleanup;
+ }
+ if (revStatus == certRevocationStatusRevoked &&
+ (hasFetchedCrlInCache ||
+ *pReasonCode != crlEntryReasoncertificatedHold)) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ } else if (revStatus == certRevocationStatusValid &&
+ hasFetchedCrlInCache) {
+ pkixRevStatus = PKIX_RevStatus_Success;
+ }
+ }
+cleanup:
+ *pStatus = pkixRevStatus;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_GetCert
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_Pk11CertStore_GetCert(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *parentVerifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ PKIX_UInt32 i = 0;
+ PKIX_UInt32 numFound = 0;
+ PKIX_PL_Cert *candidate = NULL;
+ PKIX_List *selected = NULL;
+ PKIX_List *filtered = NULL;
+ PKIX_CertSelector_MatchCallback selectorCallback = NULL;
+ PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
+ PKIX_ComCertSelParams *params = NULL;
+ PKIX_Boolean cacheFlag = PKIX_FALSE;
+ PKIX_VerifyNode *verifyNode = NULL;
+ PKIX_Error *selectorError = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCert");
+ PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCertList);
+
+ *pNBIOContext = NULL; /* We don't use non-blocking I/O */
+
+ PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
+ (selector, &selectorCallback, plContext),
+ PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (selector, &params, plContext),
+ PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED);
+
+ PKIX_CHECK(pkix_pl_Pk11CertStore_CertQuery
+ (params, &selected, plContext),
+ PKIX_PK11CERTSTORECERTQUERYFAILED);
+
+ if (selected) {
+ PKIX_CHECK(PKIX_List_GetLength(selected, &numFound, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+ }
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (store, &cacheFlag, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ PKIX_CHECK(PKIX_CertStore_GetTrustCallback
+ (store, &trustCallback, plContext),
+ PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_List_Create(&filtered, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; i < numFound; i++) {
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
+ (selected,
+ i,
+ (PKIX_PL_Object **)&candidate,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (PKIX_ERROR_RECEIVED) {
+ continue; /* just skip bad certs */
+ }
+
+ selectorError =
+ selectorCallback(selector, candidate, plContext);
+ if (!selectorError) {
+ PKIX_CHECK(PKIX_PL_Cert_SetCacheFlag
+ (candidate, cacheFlag, plContext),
+ PKIX_CERTSETCACHEFLAGFAILED);
+
+ if (trustCallback) {
+ PKIX_CHECK(PKIX_PL_Cert_SetTrustCertStore
+ (candidate, store, plContext),
+ PKIX_CERTSETTRUSTCERTSTOREFAILED);
+ }
+
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
+ (filtered,
+ (PKIX_PL_Object *)candidate,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ } else if (parentVerifyNode) {
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_Create(candidate, 0, selectorError,
+ &verifyNode, plContext),
+ PKIX_VERIFYNODECREATEFAILED);
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_AddToTree(parentVerifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ PKIX_DECREF(selectorError);
+ PKIX_DECREF(candidate);
+ }
+
+ /* Don't throw away the list if one cert was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pCertList = filtered;
+ filtered = NULL;
+
+cleanup:
+fatal:
+ PKIX_DECREF(filtered);
+ PKIX_DECREF(candidate);
+ PKIX_DECREF(selected);
+ PKIX_DECREF(params);
+ PKIX_DECREF(verifyNode);
+ PKIX_DECREF(selectorError);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+static PKIX_Error *
+RemovePartitionedDpsFromList(PKIX_List *dpList, PKIX_PL_Date *date,
+ void *plContext)
+{
+ NamedCRLCache* nameCrlCache = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ unsigned int dpIndex = 0;
+ PRTime time;
+ PRTime reloadDelay = 0, badCrlInvalDelay = 0;
+ SECStatus rv;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ListRemovePrtDp");
+
+ if (!dpList || !dpList->length) {
+ PKIX_RETURN(CERTSTORE);
+ }
+ reloadDelay =
+ ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
+ PR_USEC_PER_SEC;
+ badCrlInvalDelay =
+ ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
+ PR_USEC_PER_SEC;
+ PKIX_CHECK(pkix_pl_Date_GetPRTime(date, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ rv = cert_AcquireNamedCRLCache(&nameCrlCache);
+ if (rv == SECFailure) {
+ /* Baling out. Wont find out any thing useful. */
+ PKIX_RETURN(CERTSTORE);
+ }
+ while (dpIndex < dpList->length) {
+ SECItem **derDpNames = NULL;
+ PKIX_Boolean removeDp = PKIX_FALSE;
+
+ PKIX_CHECK(
+ PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ if (!dp->isPartitionedByReasonCode) {
+ /* See if we know about this dp anything why we should
+ * not use it to download a crl. */
+ if (dp->nssdp->distPointType == generalName) {
+ /* dp can only be created from nssdp. */
+ derDpNames = dp->nssdp->derFullName;
+ } else {
+ removeDp = PKIX_TRUE;
+ }
+ while (derDpNames && *derDpNames != NULL) {
+ NamedCRLCacheEntry* cacheEntry = NULL;
+ const SECItem *derDpName = *derDpNames++;
+ /* Removing from the list all dps that we know about. */
+ rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
+ &cacheEntry);
+ if (rv && cacheEntry) {
+ if (cacheEntry->unsupported ||
+ (cacheEntry->inCRLCache &&
+ (cacheEntry->successfulInsertionTime + reloadDelay > time ||
+ (cacheEntry->dupe &&
+ cacheEntry->lastAttemptTime + reloadDelay > time))) ||
+ (cacheEntry->badDER &&
+ cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
+ removeDp = PKIX_TRUE;
+ }
+ }
+ }
+ } else {
+ /* Remove dp that point to a partitioned crl . RFC 5280
+ * recommends against crl partitioned by reason code.
+ * Will skip such crls */
+ removeDp = PKIX_TRUE;
+ }
+ if (removeDp) {
+ PKIX_CHECK_ONLY_FATAL(
+ pkix_List_Remove(dpList,(PKIX_PL_Object*)dp,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ } else {
+ dpIndex += 1;
+ }
+ PKIX_DECREF(dp);
+ }
+
+cleanup:
+ if (nameCrlCache) {
+ cert_ReleaseNamedCRLCache(nameCrlCache);
+ }
+ PKIX_DECREF(dp);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_DownloadCrl
+ */
+static PKIX_Error *
+DownloadCrl(pkix_pl_CrlDp *dp, PKIX_PL_CRL **crl,
+ const SEC_HttpClientFcnV1 *hcv1, void *plContext)
+{
+ char *location = NULL;
+ char *hostname = NULL;
+ char *path = NULL;
+ PRUint16 port;
+ SEC_HTTP_SERVER_SESSION pServerSession = NULL;
+ SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
+ PRUint16 myHttpResponseCode;
+ const char *myHttpResponseData = NULL;
+ PRUint32 myHttpResponseDataLen;
+ SECItem *uri = NULL;
+ SECItem *derCrlCopy = NULL;
+ CERTSignedCrl *nssCrl = NULL;
+ CERTGeneralName *genName = NULL;
+ SECItem **derGenNames = NULL;
+ SECItem *derGenName = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_DownloadCrl");
+
+ /* Do not support dps others than a one with GeneralName
+ * name type. */
+ if (dp->distPointType != generalName ||
+ !dp->nssdp->derFullName) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDCRLDPTYPE);
+ }
+ genName = dp->name.fullName;
+ derGenNames = dp->nssdp->derFullName;
+ do {
+ derGenName = *derGenNames;
+ do {
+ if (!derGenName ||
+ !genName->name.other.data) {
+ /* get to next name if no data. */
+ break;
+ }
+ uri = &genName->name.other;
+ location = (char*)PR_Malloc(1 + uri->len);
+ if (!location) {
+ break;
+ }
+ PORT_Memcpy(location, uri->data, uri->len);
+ location[uri->len] = 0;
+ if (CERT_ParseURL(location, &hostname,
+ &port, &path) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
+ break;
+ }
+
+ PORT_Assert(hostname != NULL);
+ PORT_Assert(path != NULL);
+
+ if ((*hcv1->createSessionFcn)(hostname, port,
+ &pServerSession) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
+ break;
+ }
+
+ if ((*hcv1->createFcn)(pServerSession, "http", path, "GET",
+ /* Users with slow connections might not get CRL revocation
+ checking for certs that use big CRLs because of the timeout
+ We absolutely need code that limits our retry attempts.
+ */
+ PR_SecondsToInterval(
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
+ &pRequestSession) != SECSuccess) {
+ break;
+ }
+
+ myHttpResponseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+ if (myHttpResponseDataLen < PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH)
+ myHttpResponseDataLen = PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH;
+
+ /* We use a non-zero timeout, which means:
+ - the client will use blocking I/O
+ - TryFcn will not return WOULD_BLOCK nor a poll descriptor
+ - it's sufficient to call TryFcn once
+ */
+ /* we don't want result objects larger than this: */
+ if ((*hcv1->trySendAndReceiveFcn)(
+ pRequestSession,
+ NULL,
+ &myHttpResponseCode,
+ NULL,
+ NULL,
+ &myHttpResponseData,
+ &myHttpResponseDataLen) != SECSuccess) {
+ break;
+ }
+
+ if (myHttpResponseCode != 200) {
+ break;
+ }
+ } while(0);
+ if (!myHttpResponseData) {
+ /* Going to the next one. */
+ genName = CERT_GetNextGeneralName(genName);
+ derGenNames++;
+ }
+ /* Staing in the loop through all the names until
+ * we have a successful download. */
+ } while (!myHttpResponseData && *derGenNames &&
+ genName != dp->name.fullName);
+ /* Need this name to track the crl source location. */
+ PORT_Assert(derGenName);
+
+ if (!myHttpResponseData) {
+ /* Generating fake bad CRL to keep track of this dp */
+ SECItem derCrl = {siBuffer, (void*)"BadCrl", 6 };
+
+ derCrlCopy = SECITEM_DupItem(&derCrl);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ derGenName = *dp->nssdp->derFullName;
+ } else {
+ SECItem derCrl = { siBuffer,
+ (void*)myHttpResponseData,
+ myHttpResponseDataLen };
+ derCrlCopy = SECITEM_DupItem(&derCrl);
+ 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);
+ }
+ /* pkix crl owns the der. */
+ PKIX_CHECK(
+ pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy,
+ derGenName,
+ crl, plContext),
+ PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
+ /* pkix crl now own both objects. */
+ derCrlCopy = NULL;
+ nssCrl = NULL;
+
+cleanup:
+ if (derCrlCopy)
+ PORT_Free(derCrlCopy);
+ if (nssCrl)
+ SEC_DestroyCrl(nssCrl);
+ if (pRequestSession != NULL)
+ (*hcv1->freeFcn)(pRequestSession);
+ if (pServerSession != NULL)
+ (*hcv1->freeSessionFcn)(pServerSession);
+ if (path != NULL)
+ PORT_Free(path);
+ if (hostname != NULL)
+ PORT_Free(hostname);
+ if (location) {
+ PORT_Free(location);
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_GetCRL
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_GetCRL(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ PKIX_UInt32 dpIndex = 0;
+ PKIX_PL_CRL *crl = NULL;
+ PKIX_List *crlList = NULL;
+ PKIX_List *dpList = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ PKIX_PL_Date *date = NULL;
+ const SEC_HttpClientFcn *registeredHttpClient = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCRL");
+ PKIX_NULLCHECK_THREE(store, pNBIOContext, pCrlList);
+ PKIX_NULLCHECK_TWO(selector, selector->params);
+
+ registeredHttpClient = SEC_GetRegisteredHttpClient();
+ if (!registeredHttpClient || registeredHttpClient->version != 1) {
+ goto cleanup;
+ }
+ dpList = selector->params->crldpList;
+ date = selector->params->date;
+ PKIX_CHECK(
+ RemovePartitionedDpsFromList(dpList, date,
+ plContext),
+ PKIX_FAILTOREMOVEDPFROMLIST);
+ for (;dpIndex < dpList->length;dpIndex++) {
+ PKIX_DECREF(dp);
+ pkixErrorResult =
+ PKIX_List_GetItem(dpList, dpIndex,
+ (PKIX_PL_Object **)&dp,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ pkixErrorResult =
+ DownloadCrl(dp, &crl,
+ &registeredHttpClient->fcnTable.ftable1,
+ plContext);
+ if (pkixErrorResult || !crl) {
+ /* continue to next dp in case of unsuccesfull
+ * download attempt. */
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ if (!crlList) {
+ PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+ pkixErrorResult =
+ PKIX_List_AppendItem(crlList, (PKIX_PL_Object *)crl,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ }
+ PKIX_DECREF(crl);
+ }
+ *pCrlList = crlList;
+ crlList = NULL;
+
+cleanup:
+ PKIX_DECREF(dp);
+ PKIX_DECREF(crl);
+ PKIX_DECREF(crlList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+
+/* --Public-Pk11CertStore-Functions----------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Pk11CertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_Pk11CertStore_Create(
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_CertStore *certStore = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_Pk11CertStore_Create");
+ PKIX_NULLCHECK_ONE(pCertStore);
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_Pk11CertStore_GetCert,
+ pkix_pl_Pk11CertStore_GetCRL,
+ NULL, /* getCertContinue */
+ NULL, /* getCrlContinue */
+ pkix_pl_Pk11CertStore_CheckTrust,
+ pkix_pl_Pk11CertStore_ImportCrl,
+ pkix_pl_Pk11CertStore_CheckRevByCrl,
+ NULL,
+ PKIX_TRUE, /* cache flag */
+ PKIX_TRUE, /* local - no network I/O */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ *pCertStore = certStore;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h
new file mode 100644
index 0000000000..506707683d
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h
@@ -0,0 +1,31 @@
+/* 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_pk11certstore.h
+ *
+ * PK11Certstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_PK11CERTSTORE_H
+#define _PKIX_PL_PK11CERTSTORE_H
+
+#include "pkix_pl_common.h"
+#include "certi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* see source file for function documentation */
+PKIX_Error *
+PKIX_PL_Pk11CertStore_Create(
+ PKIX_CertStore **pCertStore,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_PK11CERTSTORE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
new file mode 100644
index 0000000000..ac5e9d3796
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
@@ -0,0 +1,1695 @@
+/* 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_socket.c
+ *
+ * Socket Function Definitions
+ *
+ */
+
+/*
+ * If Socket Tracing is active, messages sent and received will be
+ * timestamped and dumped (to stdout) in standard hex-dump format. E.g.,
+ *
+ * 1116612359156140:
+ * 28F0: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 Hello, world!.
+ *
+ * The timestamp is not formatted to be meaningful except as an increasing
+ * value of seconds.microseconds, which is good enough to correlate two
+ * sides of a message exchange and to figure durations.
+ *
+ * Code to perform Socket tracing will be compiled in if PKIX_SOCKETTRACE
+ * is defined, but that doesn't mean socket tracing is active. Tracing also
+ * requires that the Boolean socketTraceFlag is set to PKIX_TRUE. That is
+ * the default value, but it can be overridden by using the debugger to
+ * change its value -- allowing tracing to be turned on and off at various
+ * breakpoints -- or by setting the environment variable SOCKETTRACE. A
+ * value of 1 sets socketTraceFlag to PKIX_TRUE (tracing on), and any other
+ * value sets socketTraceFlag to PKIX_FALSE (tracing off). The environment
+ * value is checked during system initialization.
+ */
+#ifndef BUILD_OPT
+#define PKIX_SOCKETTRACE 1
+#endif
+
+#ifdef PKIX_SOCKETDEBUG
+#define PKIX_SOCKETTRACE 1
+#endif
+
+#include "pkix_pl_socket.h"
+
+/* --Private-Socket-Functions---------------------------------- */
+
+#ifdef PKIX_SOCKETTRACE
+static PKIX_Boolean socketTraceFlag = PKIX_FALSE;
+
+/*
+ * FUNCTION: pkix_pl_socket_timestamp
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the time of day, as obtained from the
+ * system function gettimeofday, as seconds.microseconds. Its resolution
+ * is whatever the system call provides.
+ *
+ * PARAMETERS:
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_timestamp() {
+ PRInt64 prTime;
+ prTime = PR_Now();
+/* We shouldn't use PR_ALTERNATE_INT64_TYPEDEF, but nor can we use PRId64 */
+#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF)
+ printf("%ld:\n", prTime);
+#else
+ printf("%lld:\n", prTime);
+#endif
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_hexDigit
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the byte "byteVal" as two hex digits.
+ *
+ * PARAMETERS:
+ * "byteVal"
+ * The value to be printed.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_hexDigit(char byteVal) {
+ int n = 0;
+ char cHi = '\0';
+ char cLow = '\0';
+ n = ((byteVal >> 4) & 0xf);
+ if (n > 9) {
+ cHi = (char) ((n - 10) + 'A');
+ } else {
+ cHi = (char) (n + '0');
+ }
+ n = byteVal & 0xf;
+ if (n > 9) {
+ cLow = (char) ((n - 10) + 'A');
+ } else {
+ cLow = (char) (n + '0');
+ }
+ (void) printf("%c%c", cHi, cLow);
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_linePrefix
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the address provided by "addr" as four
+ * hexadecimal digits followed by a colon and a space.
+ *
+ * PARAMETERS:
+ * "addr"
+ * The address to be printed
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_linePrefix(PKIX_UInt32 addr) {
+ pkix_pl_socket_hexDigit((char)((addr >> 8) & 0xff));
+ pkix_pl_socket_hexDigit((char)(addr & 0xff));
+ (void) printf(": ");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_traceLine
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the sixteen bytes beginning at the
+ * address pointed to by "ptr". The bytes are printed as sixteen pairs
+ * of hexadecimal characters followed by an ascii interpretation, in which
+ * characters from 0x20 to 0x7d are shown as their ascii equivalents, and
+ * other values are represented as periods.
+ *
+ * PARAMETERS:
+ * "ptr"
+ * The address of the first of the bytes to be printed
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_traceLine(char *ptr) {
+ PKIX_UInt32 i = 0;
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL));
+ for (i = 0; i < 16; i++) {
+ printf(" ");
+ pkix_pl_socket_hexDigit(ptr[i]);
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ printf(" ");
+ for (i = 0; i < 16; i++) {
+ if ((ptr[i] < ' ') || (ptr[i] > '}')) {
+ printf(".");
+ } else {
+ printf("%c", ptr[i]);
+ }
+ }
+ printf("\n");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_tracePartialLine
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the number of bytes given by "nBytes",
+ * beginning at the address pointed to by "ptr". The bytes are printed as
+ * pairs of hexadecimal characters followed by an ascii interpretation, in
+ * which characters from 0x20 to 0x7d are shown as their ascii equivalents,
+ * and other values are represented as periods.
+ *
+ * PARAMETERS:
+ * "ptr"
+ * The address of the first of the bytes to be printed
+ * "nBytes"
+ * The Int32 value giving the number of bytes to be printed. If "nBytes"
+ * is greater than sixteen, the results will be unattractive.
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_tracePartialLine(char *ptr, PKIX_UInt32 nBytes) {
+ PKIX_UInt32 i = 0;
+ if (nBytes > 0) {
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL));
+ }
+ for (i = 0; i < nBytes; i++) {
+ printf(" ");
+ pkix_pl_socket_hexDigit(ptr[i]);
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ for (i = nBytes; i < 16; i++) {
+ printf(" ");
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ printf(" ");
+ for (i = 0; i < nBytes; i++) {
+ if ((ptr[i] < ' ') || (ptr[i] > '}')) {
+ printf(".");
+ } else {
+ printf("%c", ptr[i]);
+ }
+ }
+ printf("\n");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_tracebuff
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the number of bytes given by "nBytes",
+ * beginning with the byte pointed to by "buf". The output is preceded by
+ * a timestamp, and each group of sixteen (and a remainder, if any) is
+ * preceded by its address. The contents are shown in hexadecimal and as
+ * ascii characters. If "nBytes" is zero, the timestamp and starting
+ * address are displayed.
+ *
+ * PARAMETERS:
+ * "buf"
+ * The starting address of the bytes to be printed
+ * "nBytes"
+ * The number of bytes to be printed
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+void pkix_pl_socket_tracebuff(void *buf, PKIX_UInt32 nBytes) {
+ PKIX_UInt32 bytesRemaining = nBytes;
+ PKIX_UInt32 offset = 0;
+ char *bufptr = (char *)buf;
+
+ if (socketTraceFlag == PKIX_FALSE) return;
+
+ pkix_pl_socket_timestamp();
+ /*
+ * Special case: if called with length of zero, just do address
+ */
+ if (nBytes == 0) {
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)buf - (char *)NULL));
+ printf("\n");
+ } else {
+ while (bytesRemaining >= 16) {
+ pkix_pl_socket_traceLine(&bufptr[offset]);
+ bytesRemaining -= 16;
+ offset += 16;
+ }
+ pkix_pl_socket_tracePartialLine
+ (&bufptr[offset], bytesRemaining);
+ }
+}
+
+#endif
+
+/*
+ * FUNCTION: pkix_pl_Socket_SetNonBlocking
+ * DESCRIPTION:
+ *
+ * This functions sets the socket represented by the PRFileDesc "fileDesc"
+ * to nonblocking mode.
+ *
+ * PARAMETERS:
+ * "fileDesc"
+ * The address of the PRFileDesc whose I/O mode is to be set
+ * non-blocking. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_SetNonBlocking(
+ PRFileDesc *fileDesc,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRSocketOptionData sockOptionData;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_SetNonBlocking");
+ PKIX_NULLCHECK_ONE(fileDesc);
+
+ sockOptionData.option = PR_SockOpt_Nonblocking;
+ sockOptionData.value.non_blocking = PR_TRUE;
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, fileDesc->methods->setsocketoption,
+ (fileDesc, &sockOptionData));
+
+ if (rv != PR_SUCCESS) {
+ PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
+ }
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateClient
+ * DESCRIPTION:
+ *
+ * This functions creates a client socket for the PKIX_PL_Socket pointed to
+ * by "socket". If "socket" was created with a timeout value of zero, the
+ * client socket is set to use nonblocking I/O.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a client socket is to be
+ * created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+
+static PKIX_Error *
+pkix_pl_Socket_CreateClient(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRFileDesc *mySock = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateClient");
+ PKIX_NULLCHECK_ONE(socket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, mySock, PR_NewTCPSocket, ());
+ if (!mySock) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateClient: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Created socket, PRFileDesc @ %#X\n", mySock);
+#endif
+
+ socket->clientSock = mySock;
+ socket->status = SOCKET_UNCONNECTED;
+ if (socket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(mySock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateServer
+ * DESCRIPTION:
+ *
+ * This functions creates a server socket for the PKIX_PL_Socket pointed to
+ * by "socket". If "socket" was created with a timeout value of zero, the
+ * server socket is set to use nonblocking I/O.
+ *
+ * Warning: there seems to be a problem with operating a server socket in
+ * non-blocking mode. If the server calls Recv prior to a corresponding
+ * Send, the message may be lost.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a server socket is to be
+ * created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_CreateServer(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+/* #ifdef PKIX_SOCKETDEBUG */
+ PRErrorCode errorcode = 0;
+/* #endif */
+ PRStatus rv = PR_FAILURE;
+ PRFileDesc *serverSock = NULL;
+ PRSocketOptionData sockOptionData;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateServer");
+ PKIX_NULLCHECK_ONE(socket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, serverSock, PR_NewTCPSocket, ());
+ if (!serverSock) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateServer: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+ }
+
+ socket->serverSock = serverSock;
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Created socket, PRFileDesc @ %#X\n", serverSock);
+#endif
+
+ if (socket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(serverSock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+ sockOptionData.option = PR_SockOpt_Reuseaddr;
+ sockOptionData.value.reuse_addr = PR_TRUE;
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, serverSock->methods->setsocketoption,
+ (serverSock, &sockOptionData));
+
+ if (rv != PR_SUCCESS) {
+ PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Bind, (serverSock, socket->netAddr));
+
+ if (rv == PR_FAILURE) {
+/* #ifdef PKIX_SOCKETDEBUG */
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateServer: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+/* #endif */
+ PKIX_ERROR(PKIX_PRBINDFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful bind!\n");
+#endif
+
+ socket->status = SOCKET_BOUND;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Connect
+ * DESCRIPTION:
+ *
+ * This functions performs the connect function for the client socket
+ * specified in "socket", storing the status at "pStatus".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a connect is to be performed.
+ * Must be non-NULL.
+ * "pStatus"
+ * The address at which the connection status is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Connect(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRErrorCode errorcode = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Connect");
+ PKIX_NULLCHECK_TWO(socket, socket->clientSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Connect,
+ (socket->clientSock, socket->netAddr, socket->timeout));
+
+ if (rv == PR_FAILURE) {
+ errorcode = PR_GetError();
+ *pStatus = errorcode;
+ if (errorcode == PR_IN_PROGRESS_ERROR) {
+ socket->status = SOCKET_CONNECTPENDING;
+ goto cleanup;
+ } else {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Connect: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRCONNECTFAILED);
+ }
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful connect!\n");
+#endif
+
+ *pStatus = 0;
+ socket->status = SOCKET_CONNECTED;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_ConnectContinue
+ * DESCRIPTION:
+ *
+ * This functions continues the connect function for the client socket
+ * specified in "socket", storing the status at "pStatus". It is expected that
+ * the non-blocking connect has returned PR_IN_PROGRESS_ERROR.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a connect is to be continued.
+ * Must be non-NULL.
+ * "pStatus"
+ * The address at which the connection status is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_ConnectContinue(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRErrorCode errorcode = 0;
+ PRPollDesc pollDesc;
+ PRInt32 numEvents = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_ConnectContinue");
+ PKIX_NULLCHECK_TWO(socket, socket->clientSock);
+
+ pollDesc.fd = socket->clientSock;
+ pollDesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ pollDesc.out_flags = 0;
+ PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
+ if (numEvents < 0) {
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ }
+
+ if (numEvents == 0) {
+ *pStatus = PR_IN_PROGRESS_ERROR;
+ goto cleanup;
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_ConnectContinue,
+ (socket->clientSock, pollDesc.out_flags));
+
+ /*
+ * PR_ConnectContinue sometimes lies. It returns PR_SUCCESS
+ * even though the connection is not yet ready. But its deceit
+ * is betrayed by the contents of out_flags!
+ */
+ if ((rv == PR_SUCCESS) && (pollDesc.out_flags == PR_POLL_ERR)) {
+ *pStatus = PR_IN_PROGRESS_ERROR;
+ goto cleanup;
+ }
+
+ if (rv == PR_FAILURE) {
+ errorcode = PR_GetError();
+ *pStatus = errorcode;
+ if (errorcode == PR_IN_PROGRESS_ERROR) {
+ goto cleanup;
+ } else {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_ConnectContinue: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRCONNECTCONTINUEFAILED);
+ }
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful connect!\n");
+#endif
+
+ *pStatus = 0;
+ socket->status = SOCKET_CONNECTED;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTANSOCKET);
+
+ socket = (PKIX_PL_Socket *)object;
+
+ if (socket->isServer) {
+ if (socket->serverSock) {
+ PR_Close(socket->serverSock);
+ }
+ } else {
+ if (socket->clientSock) {
+ PR_Close(socket->clientSock);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTSOCKET);
+
+ socket = (PKIX_PL_Socket *)object;
+
+ *pHashcode = (((socket->timeout << 3) +
+ (socket->netAddr->inet.family << 3)) +
+ (*((PKIX_UInt32 *)&(socket->netAddr->inet.ip)))) +
+ socket->netAddr->inet.port;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_Socket *firstSocket = NULL;
+ PKIX_PL_Socket *secondSocket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ *pResult = PKIX_FALSE;
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject, secondObject, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTSOCKET);
+
+ firstSocket = (PKIX_PL_Socket *)firstObject;
+ secondSocket = (PKIX_PL_Socket *)secondObject;
+
+ if (firstSocket->timeout != secondSocket->timeout) {
+ goto cleanup;
+ }
+
+ if (firstSocket->netAddr == secondSocket->netAddr) {
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ if ((firstSocket->netAddr->inet.family !=
+ secondSocket->netAddr->inet.family) ||
+ (*((PKIX_UInt32 *)&(firstSocket->netAddr->inet.ip)) !=
+ *((PKIX_UInt32 *)&(secondSocket->netAddr->inet.ip))) ||
+ (firstSocket->netAddr->inet.port !=
+ secondSocket->netAddr->inet.port)) {
+
+ goto cleanup;
+
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_SOCKET_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_Socket_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_RegisterSelf");
+
+ entry.description = "Socket";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_Socket);
+ entry.destructor = pkix_pl_Socket_Destroy;
+ entry.equalsFunction = pkix_pl_Socket_Equals;
+ entry.hashcodeFunction = pkix_pl_Socket_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_SOCKET_TYPE] = entry;
+
+#ifdef PKIX_SOCKETTRACE
+ {
+ char *val = NULL;
+ val = PR_GetEnvSecure("SOCKETTRACE");
+ /* Is SOCKETTRACE set in the environment? */
+ if ((val != NULL) && (*val != '\0')) {
+ socketTraceFlag =
+ ((*val == '1')?PKIX_TRUE:PKIX_FALSE);
+ }
+ }
+#endif
+
+ PKIX_RETURN(SOCKET);
+}
+
+/* --Public-Socket-Functions----------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Socket_Listen
+ * DESCRIPTION:
+ *
+ * This functions establishes a listening queue for the server Socket
+ * pointed to by "socket".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the server socket for which the queue is to be
+ * established. Must be non-NULL.
+ * "backlog"
+ * The UInt32 value of the length of the queue to be established.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Listen(
+ PKIX_PL_Socket *socket,
+ PKIX_UInt32 backlog,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRStatus rv = PR_FAILURE;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Listen");
+ PKIX_NULLCHECK_TWO(socket, socket->serverSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Listen,
+ (socket->serverSock, (PRIntn)backlog));
+
+ if (rv == PR_FAILURE) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_Listen: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRLISTENFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful listen!\n");
+#endif
+
+ socket->status = SOCKET_LISTENING;
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Shutdown
+ * DESCRIPTION:
+ *
+ * This functions performs the shutdown of any connections controlled by the
+ * socket pointed to by "socket".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the socket to be shut down. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Shutdown(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRStatus rv = PR_FAILURE;
+ PRFileDesc *fileDesc = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Shutdown");
+ PKIX_NULLCHECK_ONE(socket);
+
+ fileDesc =
+ (socket->isServer)?(socket->serverSock):(socket->clientSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Shutdown,
+ (fileDesc, PR_SHUTDOWN_BOTH));
+
+ if (rv == PR_FAILURE) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_Shutdown: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRSHUTDOWNFAILED);
+ }
+ socket->status = SOCKET_SHUTDOWN;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Send
+ * DESCRIPTION:
+ *
+ * This functions sends a message using the socket pointed to by "sendSock",
+ * from the buffer pointed to by "buf", of the number of bytes given by
+ * "bytesToWrite", storing the number of bytes actually written at
+ * "pBytesWritten". If "socket" is in non-blocking mode, the send operation
+ * may store -1 at "pBytesWritten" and the write is not complete until a
+ * corresponding pkix_pl_Poll call has indicated its completion by returning
+ * a non-negative value for bytes written.
+ *
+ * PARAMETERS:
+ * "sendSock"
+ * The address of the Socket on which the message is to be sent. Must
+ * be non-NULL.
+ * "buf"
+ * The address of the data to be sent. Must be non-NULL.
+ * "bytesToWrite""
+ * The UInt32 value indicating the number of bytes to write.
+ * "pBytesWritten"
+ * The address at which the Int32 value indicating the number of bytes
+ * actually written is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Send(
+ PKIX_PL_Socket *sendSock,
+ void *buf,
+ PKIX_UInt32 bytesToWrite,
+ PKIX_Int32 *pBytesWritten,
+ void *plContext)
+{
+ PRInt32 bytesWritten = 0;
+ PRErrorCode errorcode = 0;
+ PRFileDesc *fd = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Send");
+ PKIX_NULLCHECK_TWO(buf, pBytesWritten);
+
+ fd = sendSock->clientSock;
+
+ PKIX_PL_NSSCALLRV(SOCKET, bytesWritten, PR_Send,
+ (fd, buf, (PRInt32)bytesToWrite, 0, sendSock->timeout));
+
+ if (bytesWritten >= 0) {
+ if (sendSock->status == SOCKET_SENDRCVPENDING) {
+ sendSock->status = SOCKET_RCVPENDING;
+ } else {
+ sendSock->status = SOCKET_CONNECTED;
+ }
+#ifdef PKIX_SOCKETTRACE
+ pkix_pl_socket_tracebuff(buf, bytesWritten);
+#endif
+ } else {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Send: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRSENDFAILED);
+ }
+
+ sendSock->writeBuf = buf;
+ sendSock->writeBufSize = bytesToWrite;
+ if (sendSock->status == SOCKET_RCVPENDING) {
+ sendSock->status = SOCKET_SENDRCVPENDING;
+ } else {
+ sendSock->status = SOCKET_SENDPENDING;
+ }
+ }
+
+ *pBytesWritten = (PKIX_Int32)bytesWritten;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Recv
+ * DESCRIPTION:
+ *
+ * This functions receives a message on the socket pointed to by "rcvSock",
+ * into the buffer pointed to by "buf", of capacity given by "capacity",
+ * storing the number of bytes actually received at "pBytesRead". If "socket"
+ * is in non-blocking mode, the receive operation may store -1 at
+ * "pBytesWritten". In that case the write is not complete until a
+ * corresponding pkix_pl_Poll call has indicated its completion by returning
+ * a non-negative value for bytes read.
+ *
+ * PARAMETERS:
+ * "rcvSock"
+ * The address of the Socket on which the message is to be received.
+ * Must be non-NULL.
+ * "buf"
+ * The address of the buffer into which the message is to be received.
+ * Must be non-NULL.
+ * "capacity"
+ * The UInt32 value of the size of the buffer; that is, the maximum
+ * number of bytes that can be received.
+ * "pBytesRead"
+ * The address at which is stored the Int32 value of the number of bytes
+ * actually received.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Recv(
+ PKIX_PL_Socket *rcvSock,
+ void *buf,
+ PKIX_UInt32 capacity,
+ PKIX_Int32 *pBytesRead,
+ void *plContext)
+{
+ PRErrorCode errorcode = 0;
+ PRInt32 bytesRead = 0;
+ PRFileDesc *fd = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Recv");
+ PKIX_NULLCHECK_THREE(rcvSock, buf, pBytesRead);
+
+ fd = rcvSock->clientSock;
+
+ PKIX_PL_NSSCALLRV(SOCKET, bytesRead, PR_Recv,
+ (fd, buf, (PRInt32)capacity, 0, rcvSock->timeout));
+
+ if (bytesRead > 0) {
+ if (rcvSock->status == SOCKET_SENDRCVPENDING) {
+ rcvSock->status = SOCKET_SENDPENDING;
+ } else {
+ rcvSock->status = SOCKET_CONNECTED;
+ }
+#ifdef PKIX_SOCKETTRACE
+ pkix_pl_socket_tracebuff(buf, bytesRead);
+#endif
+ } else if (bytesRead == 0) {
+ PKIX_ERROR(PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED);
+ } else {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Recv: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRRECVFAILED);
+ }
+ rcvSock->readBuf = buf;
+ rcvSock->readBufSize = capacity;
+ if (rcvSock->status == SOCKET_SENDPENDING) {
+ rcvSock->status = SOCKET_SENDRCVPENDING;
+ } else {
+ rcvSock->status = SOCKET_RCVPENDING;
+ }
+
+ }
+
+ *pBytesRead = (PKIX_Int32)bytesRead;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Poll
+ * DESCRIPTION:
+ *
+ * This functions checks for completion of an earlier Send or Recv on the
+ * socket pointed to by "sock", storing in "pBytesWritten" the number of bytes
+ * written by a completed Send and in "pBytesRead" the number of bytes
+ * received in a completed Recv. A value of -1 returned indicates the
+ * operation has still not completed. A NULL pointer may be supplied for
+ * "pBytesWritten" to avoid checking for completion of a Send. A NULL pointer
+ * may be supplied for "pBytesRead" to avoid checking for completion of a Recv.
+ *
+ * PARAMETERS:
+ * "sock"
+ * The address of the socket for which completions are to be checked.
+ * "pBytesWritten"
+ * The address at which the number of bytes written is to be stored, if
+ * a pending Send has completed. If NULL, Sends are not checked.
+ * "pBytesRead"
+ * The address at which the number of bytes read is to be stored, if
+ * a pending Recv has completed. If NULL, Recvs are not checked.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Poll(
+ PKIX_PL_Socket *sock,
+ PKIX_Int32 *pBytesWritten,
+ PKIX_Int32 *pBytesRead,
+ void *plContext)
+{
+ PRPollDesc pollDesc;
+ PRInt32 numEvents = 0;
+ PKIX_Int32 bytesRead = 0;
+ PKIX_Int32 bytesWritten = 0;
+ PRErrorCode errorcode = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Poll");
+ PKIX_NULLCHECK_ONE(sock);
+
+ pollDesc.fd = sock->clientSock;
+ pollDesc.in_flags = 0;
+ pollDesc.out_flags = 0;
+
+ if ((pBytesWritten) &&
+ ((sock->status == SOCKET_SENDPENDING) ||
+ (sock->status == SOCKET_SENDRCVPENDING))) {
+ pollDesc.in_flags = PR_POLL_WRITE;
+ }
+
+ if ((pBytesRead) &&
+ ((sock->status == SOCKET_RCVPENDING) ||
+ (sock->status == SOCKET_SENDRCVPENDING))) {
+ pollDesc.in_flags |= PR_POLL_READ;
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
+
+ if (numEvents < 0) {
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ } else if (numEvents > 0) {
+ if (pollDesc.out_flags & PR_POLL_WRITE) {
+ PKIX_CHECK(pkix_pl_Socket_Send
+ (sock,
+ sock->writeBuf,
+ sock->writeBufSize,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+ *pBytesWritten = (PKIX_Int32)bytesWritten;
+ if (bytesWritten >= 0) {
+ sock->writeBuf = NULL;
+ sock->writeBufSize = 0;
+ }
+ }
+
+ if (pollDesc.out_flags & PR_POLL_READ) {
+ PKIX_CHECK(pkix_pl_Socket_Recv
+ (sock,
+ sock->readBuf,
+ sock->readBufSize,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+ *pBytesRead = (PKIX_Int32)bytesRead;
+ if (bytesRead >= 0) {
+ sock->readBuf = NULL;
+ sock->readBufSize = 0;
+ }
+ }
+ } else if (numEvents == 0) {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Poll: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ }
+ if (pBytesWritten) {
+ *pBytesWritten = 0;
+ }
+ if (pBytesRead) {
+ *pBytesRead = 0;
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Accept
+ * DESCRIPTION:
+ *
+ * This functions accepts a client connection for the server Socket pointed
+ * to by "serverSocket", creating a new Socket and storing the result at
+ * "pRendezvousSocket". If "serverSocket" is in non-blocking mode, this
+ * function will return NULL if there is no client connection to accept.
+ * Otherwise this function will block until a connection is available.
+ * When a client connection is available the new Socket will have the same
+ * blocking/non-blocking property as "serverSocket".
+ *
+ * PARAMETERS:
+ * "serverSocket"
+ * The address of the Socket for which a client connection is to be
+ * accepted. Must be non-NULL.
+ * "pRendezvousSocket"
+ * The address at which the created Socket is stored, when a client
+ * connection is available, or at which NULL is stored, if no connection
+ * is available for a non-blocking "serverSocket". Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Accept(
+ PKIX_PL_Socket *serverSocket,
+ PKIX_PL_Socket **pRendezvousSocket,
+ void *plContext)
+{
+ PRErrorCode errorcode = 0;
+ PRFileDesc *rendezvousSock = NULL;
+ PRNetAddr *clientAddr = NULL;
+ PKIX_PL_Socket *newSocket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Accept");
+ PKIX_NULLCHECK_TWO(serverSocket, pRendezvousSocket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rendezvousSock, PR_Accept,
+ (serverSocket->serverSock, clientAddr, serverSocket->timeout));
+
+ if (!rendezvousSock) {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Accept: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRACCEPTFAILED);
+ }
+ serverSocket->status = SOCKET_ACCEPTPENDING;
+ *pRendezvousSocket = NULL;
+ goto cleanup;
+
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful accept!\n");
+#endif
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&newSocket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ newSocket->isServer = PKIX_FALSE;
+ newSocket->timeout = serverSocket->timeout;
+ newSocket->clientSock = rendezvousSock;
+ newSocket->serverSock = NULL;
+ newSocket->netAddr = NULL;
+ newSocket->status = SOCKET_CONNECTED;
+ newSocket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+ newSocket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ newSocket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ newSocket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ newSocket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ newSocket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ newSocket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+
+ if (serverSocket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking
+ (rendezvousSock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+ *pRendezvousSocket = newSocket;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Create
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout" and server address from "netAddr", and stores the created Socket
+ * at "pSocket".
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "netAddr"
+ * The PRNetAddr to be used for the Bind function, if this is a server
+ * socket, or for the Connect, if this is a client socket.
+ * "pSocket"
+ * The address at which the Socket is to be 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 Socket 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_Socket_Create(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ PRNetAddr *netAddr,
+ PRErrorCode *status,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Create");
+ PKIX_NULLCHECK_ONE(pSocket);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *status = 0;
+ } else {
+ socket->timeout = timeout;
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, status, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateByName
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout" and server address and port number from "serverName", and stores
+ * the status at "pStatus" and the created Socket at "pSocket".
+ *
+ * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
+ * address of PR_INADDR_ANY.
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "serverName"
+ * Address of a character string consisting of the server's domain name
+ * followed by a colon and a port number for the desired socket.
+ * "pStatus"
+ * Address at which the PRErrorCode resulting from the create is
+ * stored. Must be non-NULL.
+ * "pSocket"
+ * The address at which the Socket is to be 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 Socket 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_Socket_CreateByName(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *serverName,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PRNetAddr netAddr;
+ PKIX_PL_Socket *socket = NULL;
+ char *sepPtr = NULL;
+ PRHostEnt hostent;
+ PRIntn hostenum;
+ PRStatus prstatus = PR_FAILURE;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRUint16 portNum = 0;
+ char *localCopyName = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByName");
+ PKIX_NULLCHECK_TWO(serverName, pSocket);
+
+ localCopyName = PL_strdup(serverName);
+
+ sepPtr = strchr(localCopyName, ':');
+ /* First strip off the portnum, if present, from the end of the name */
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ portNum = (PRUint16)atoi(sepPtr);
+ } else {
+ portNum = (PRUint16)LDAP_PORT;
+ }
+
+ prstatus = PR_GetHostByName(localCopyName, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ /*
+ * The hostname may be a fully-qualified name. Try using just
+ * the leftmost component in our lookup.
+ */
+ sepPtr = strchr(localCopyName, '.');
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ }
+ prstatus = PR_GetHostByName
+ (localCopyName, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ PKIX_ERROR
+ (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
+ }
+ }
+
+ netAddr.inet.family = PR_AF_INET;
+ netAddr.inet.port = PR_htons(portNum);
+
+ if (isServer) {
+
+ netAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ } else {
+
+ hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &netAddr);
+ if (hostenum == -1) {
+ PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = &netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *pStatus = 0;
+ } else {
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ PL_strfree(localCopyName);
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateByHostAndPort
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout", host from "hostname", and port number from "portNum", and stores
+ * the status at "pStatus" and the created Socket at "pSocket".
+ *
+ * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
+ * address of PR_INADDR_ANY.
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "hostname"
+ * Address of a character string consisting of the server's domain name.
+ * "portNum"
+ * UInt16 value of the port number for the desired socket.
+ * "pStatus"
+ * Address at which the PRErrorCode resulting from the create is
+ * stored. Must be non-NULL.
+ * "pSocket"
+ * The address at which the Socket is to be 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 Socket 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_Socket_CreateByHostAndPort(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PRNetAddr netAddr;
+ PKIX_PL_Socket *socket = NULL;
+ char *sepPtr = NULL;
+ PRHostEnt hostent;
+ PRIntn hostenum;
+ PRStatus prstatus = PR_FAILURE;
+ char buf[PR_NETDB_BUF_SIZE];
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort");
+ PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket);
+
+
+ prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ /*
+ * The hostname may be a fully-qualified name. Try using just
+ * the leftmost component in our lookup.
+ */
+ sepPtr = strchr(hostname, '.');
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ }
+ prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ PKIX_ERROR
+ (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
+ }
+ }
+
+ netAddr.inet.family = PR_AF_INET;
+ netAddr.inet.port = PR_htons(portnum);
+
+ if (isServer) {
+
+ netAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
+
+ } else {
+
+ hostenum = PR_EnumerateHostEnt(0, &hostent, portnum, &netAddr);
+ if (hostenum == -1) {
+ PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = &netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *pStatus = 0;
+ } else {
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_GetCallbackList
+ */
+PKIX_Error *
+pkix_pl_Socket_GetCallbackList(
+ PKIX_PL_Socket *socket,
+ PKIX_PL_Socket_Callback **pCallbackList,
+ void *plContext)
+{
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetCallbackList");
+ PKIX_NULLCHECK_TWO(socket, pCallbackList);
+
+ *pCallbackList = &(socket->callbackList);
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_GetPRFileDesc
+ */
+PKIX_Error *
+pkix_pl_Socket_GetPRFileDesc(
+ PKIX_PL_Socket *socket,
+ PRFileDesc **pDesc,
+ void *plContext)
+{
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetPRFileDesc");
+ PKIX_NULLCHECK_TWO(socket, pDesc);
+
+ *pDesc = socket->clientSock;
+
+ PKIX_RETURN(SOCKET);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h
new file mode 100644
index 0000000000..abf6628b32
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h
@@ -0,0 +1,209 @@
+/* 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_socket.h
+ *
+ * Socket Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_SOCKET_H
+#define _PKIX_PL_SOCKET_H
+
+#include <errno.h>
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ SOCKET_BOUND,
+ SOCKET_LISTENING,
+ SOCKET_ACCEPTPENDING,
+ SOCKET_UNCONNECTED,
+ SOCKET_CONNECTPENDING,
+ SOCKET_CONNECTED,
+ SOCKET_SENDPENDING,
+ SOCKET_RCVPENDING,
+ SOCKET_SENDRCVPENDING,
+ SOCKET_SHUTDOWN
+} SockStatus;
+
+/* This is the default port number, if none is supplied to CreateByName. */
+#define LDAP_PORT 389
+
+/*
+ * These callbacks allow a user to substitute a counterfeit socket in places
+ * where a PKIX_PL_Socket is expected. A conforming usage will use the
+ * ListenCallback function instead of Listen, AcceptCallback instead of Accept,
+ * etc. The counterfeit socket may have special capabilites such as the
+ * ability to do proxy authentication, etc.
+ */
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_ListenCallback)(
+ PKIX_PL_Socket *socket,
+ PKIX_UInt32 backlog,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_AcceptCallback)(
+ PKIX_PL_Socket *socket,
+ PKIX_PL_Socket **pRendezvousSock,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_ConnectContinueCallback)(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_SendCallback)(
+ PKIX_PL_Socket *sendSock,
+ void *buf,
+ PKIX_UInt32 bytesToWrite,
+ PKIX_Int32 *pBytesWritten,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_RecvCallback)(
+ PKIX_PL_Socket *rcvSock,
+ void *buf,
+ PKIX_UInt32 capacity,
+ PKIX_Int32 *pBytesRead,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_PollCallback)(
+ PKIX_PL_Socket *sock,
+ PKIX_Int32 *pBytesWritten,
+ PKIX_Int32 *pBytesRead,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_ShutdownCallback)(
+ PKIX_PL_Socket *socket, void *plContext);
+
+typedef struct PKIX_PL_Socket_CallbackStruct {
+ pkix_pl_Socket_ListenCallback listenCallback;
+ pkix_pl_Socket_AcceptCallback acceptCallback;
+ pkix_pl_Socket_ConnectContinueCallback connectcontinueCallback;
+ pkix_pl_Socket_SendCallback sendCallback;
+ pkix_pl_Socket_RecvCallback recvCallback;
+ pkix_pl_Socket_PollCallback pollCallback;
+ pkix_pl_Socket_ShutdownCallback shutdownCallback;
+} PKIX_PL_Socket_Callback;
+
+struct PKIX_PL_SocketStruct {
+ PKIX_Boolean isServer;
+ PRIntervalTime timeout; /* zero for non-blocking I/O */
+ SockStatus status;
+ PRFileDesc *clientSock;
+ PRFileDesc *serverSock;
+ void *readBuf;
+ void *writeBuf;
+ PKIX_UInt32 readBufSize;
+ PKIX_UInt32 writeBufSize;
+ PRNetAddr *netAddr;
+ PKIX_PL_Socket_Callback callbackList;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_Socket_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_Create(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout, /* zero for non-blocking I/O */
+ PRNetAddr *netAddr,
+ PRErrorCode *status,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_CreateByName(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *serverName,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_CreateByHostAndPort(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+/* Do not use these functions directly; use their callback variants instead
+ * static PKIX_Error *
+ * pkix_pl_Socket_Listen(
+ * PKIX_PL_Socket *socket,
+ * PKIX_UInt32 backlog,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Accept(
+ * PKIX_PL_Socket *socket,
+ * PKIX_PL_Socket **pRendezvousSock,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_ConnectContinue(
+ * PKIX_PL_Socket *socket,
+ * PRErrorCode *pStatus,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Send(
+ * PKIX_PL_Socket *sendSock,
+ * void *buf,
+ * PKIX_UInt32 bytesToWrite,
+ * PKIX_Int32 *pBytesWritten,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Recv(
+ * PKIX_PL_Socket *rcvSock,
+ * void *buf,
+ * PKIX_UInt32 capacity,
+ * PKIX_Int32 *pBytesRead,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Poll(
+ * PKIX_PL_Socket *sock,
+ * PKIX_Int32 *pBytesWritten,
+ * PKIX_Int32 *pBytesRead,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Shutdown(
+ * PKIX_PL_Socket *socket, void *plContext);
+ */
+
+PKIX_Error *
+pkix_pl_Socket_GetCallbackList(
+ PKIX_PL_Socket *socket,
+ PKIX_PL_Socket_Callback **pCallbackList,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_GetPRFileDesc(
+ PKIX_PL_Socket *socket,
+ PRFileDesc **pDesc,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_SOCKET_H */