diff options
Diffstat (limited to 'mozilla/security/nss/lib/libpkix/pkix_pl_nss/module')
27 files changed, 15635 insertions, 0 deletions
diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile new file mode 100755 index 0000000..a06b8be --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile @@ -0,0 +1,81 @@ +#! gmake +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the PKIX-C library. +# +# The Initial Developer of the Original Code is +# Sun Microsystems, Inc. +# Portions created by the Initial Developer are +# Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. +# +# Contributor(s): +# Sun Microsystems, Inc. +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +####################################################################### +# (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). # +####################################################################### + +include config.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +export:: private_export + diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/config.mk b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/config.mk new file mode 100755 index 0000000..6f3fb7b --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/config.mk @@ -0,0 +1,48 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the PKIX-C library. +# +# The Initial Developer of the Original Code is +# Sun Microsystems, Inc. +# Portions created by the Initial Developer are +# Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. +# +# Contributor(s): +# Sun Microsystems, Inc. +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PROGRAM = + diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn new file mode 100755 index 0000000..c757dfe --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn @@ -0,0 +1,81 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the PKIX-C library. +# +# The Initial Developer of the Original Code is +# Sun Microsystems, Inc. +# Portions created by the Initial Developer are +# Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. +# +# Contributor(s): +# Sun Microsystems, Inc. +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +CORE_DEPTH = ../../../../.. + +EXPORTS = \ + $(NULL) + +PRIVATE_EXPORTS = \ + pkix_pl_aiamgr.h \ + pkix_pl_colcertstore.h \ + pkix_pl_httpcertstore.h \ + pkix_pl_httpdefaultclient.h \ + pkix_pl_ldapt.h \ + pkix_pl_ldapcertstore.h \ + pkix_pl_ldapresponse.h \ + pkix_pl_ldaprequest.h \ + pkix_pl_ldapdefaultclient.h \ + 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 \ + pkix_pl_ldaptemplates.c \ + pkix_pl_ldapcertstore.c \ + pkix_pl_ldapresponse.c \ + pkix_pl_ldaprequest.c \ + pkix_pl_ldapdefaultclient.c \ + pkix_pl_nsscontext.c \ + pkix_pl_pk11certstore.c \ + pkix_pl_socket.c \ + $(NULL) + +REQUIRES = dbm + +LIBRARY_NAME = pkixmodule + diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c new file mode 100644 index 0000000..29be9dd --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c @@ -0,0 +1,707 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * pkix_pl_aiamgr.c + * + * AIAMgr Object Definitions + * + */ + +#include "pkix_pl_aiamgr.h" +extern PKIX_PL_HashTable *aiaConnectionCache; + +/* --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); + +} + +/* --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); + PKIX_DECREF(aiaMgr->client.ldapClient); + +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); +} + +/* + * 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. + * "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); + + /* 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); +} + +PKIX_Error * +pkix_pl_AIAMgr_GetHTTPCerts( + PKIX_PL_AIAMgr *aiaMgr, + PKIX_PL_InfoAccess *ia, + void **pNBIOContext, + PKIX_List **pCerts, + void *plContext) +{ + PKIX_PL_GeneralName *location = NULL; + PKIX_PL_String *locationString = NULL; + PKIX_UInt32 len = 0; + PRUint16 port = 0; + const SEC_HttpClientFcn *httpClient = NULL; + const SEC_HttpClientFcnV1 *hcv1 = NULL; + SECStatus rv = SECFailure; + SEC_HTTP_SERVER_SESSION serverSession = NULL; + SEC_HTTP_REQUEST_SESSION requestSession = NULL; + char *path = NULL; + char *hostname = NULL; + char *locationAscii = NULL; + void *nbio = NULL; + PRUint16 responseCode = 0; + const char *responseContentType = NULL; + const char *responseData = NULL; + + PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts"); + PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts); + + nbio = *pNBIOContext; + *pNBIOContext = NULL; + *pCerts = NULL; + + if (nbio == NULL) { /* a new request */ + + PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation + (ia, &location, plContext), + PKIX_INFOACCESSGETLOCATIONFAILED); + + /* find or create httpClient = default client */ + httpClient = SEC_GetRegisteredHttpClient(); + aiaMgr->client.hdata.httpClient = httpClient; + if (!httpClient) + PKIX_ERROR(PKIX_OUTOFMEMORY); + + if (httpClient->version == 1) { + + PKIX_UInt32 timeout = + ((PKIX_PL_NssContext*)plContext)->timeoutSeconds; + + hcv1 = &(httpClient->fcnTable.ftable1); + + /* create server session */ + PKIX_TOSTRING(location, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (locationString, + PKIX_ESCASCII, + (void **)&locationAscii, + &len, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + rv = CERT_ParseURL(locationAscii, &hostname, &port, + &path); + if ((rv != SECSuccess) || + (hostname == NULL) || + (path == NULL)) { + PKIX_ERROR(PKIX_URLPARSINGFAILED); + } + + rv = (*hcv1->createSessionFcn)(hostname, port, + &serverSession); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED); + } + + aiaMgr->client.hdata.serverSession = serverSession; + + /* create request session */ + rv = (*hcv1->createFcn)(serverSession, "http", path, + "GET", PR_SecondsToInterval(timeout), + &requestSession); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + aiaMgr->client.hdata.requestSession = requestSession; + } else { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + } + + httpClient = aiaMgr->client.hdata.httpClient; + + if (httpClient->version == 1) { + PRUint32 responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + hcv1 = &(httpClient->fcnTable.ftable1); + requestSession = aiaMgr->client.hdata.requestSession; + + /* trySendAndReceive */ + rv = (*hcv1->trySendAndReceiveFcn)(requestSession, + (PRPollDesc **)&nbio, + &responseCode, + (const char **)&responseContentType, + NULL, /* &responseHeaders */ + (const char **)&responseData, + &responseDataLen); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + if (nbio != 0) { + *pNBIOContext = nbio; + goto cleanup; + } + + PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse + (responseCode, + responseContentType, + responseData, + responseDataLen, + pCerts, + plContext), + PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); + + /* Session and request cleanup in case of success */ + if (aiaMgr->client.hdata.requestSession != NULL) { + (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); + aiaMgr->client.hdata.requestSession = NULL; + } + if (aiaMgr->client.hdata.serverSession != NULL) { + (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); + aiaMgr->client.hdata.serverSession = NULL; + } + aiaMgr->client.hdata.httpClient = 0; /* callback fn */ + + } else { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + +cleanup: + /* Session and request cleanup in case of error. Passing through without cleanup + * if interrupted by blocked IO. */ + if (PKIX_ERROR_RECEIVED && aiaMgr) { + if (aiaMgr->client.hdata.requestSession != NULL) { + (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); + aiaMgr->client.hdata.requestSession = NULL; + } + if (aiaMgr->client.hdata.serverSession != NULL) { + (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); + aiaMgr->client.hdata.serverSession = NULL; + } + aiaMgr->client.hdata.httpClient = 0; /* callback fn */ + } + + PKIX_DECREF(location); + PKIX_DECREF(locationString); + + if (locationAscii) { + PORT_Free(locationAscii); + } + if (hostname) { + PORT_Free(hostname); + } + if (path) { + PORT_Free(path); + } + + PKIX_RETURN(AIAMGR); +} + +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; + PRArenaPool *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); +} + +/* + * 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); + } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) { + PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts + (aiaMgr, ia, &nbio, &certs, plContext), + PKIX_AIAMGRGETLDAPCERTSFAILED); + } 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); + PKIX_DECREF(aiaMgr->client.ldapClient); + } + + PKIX_DECREF(certs); + PKIX_DECREF(ia); + + PKIX_RETURN(AIAMGR); +} diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h new file mode 100644 index 0000000..4922ea7 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h @@ -0,0 +1,94 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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 { + PKIX_PL_LdapClient *ldapClient; + 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); + +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); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_AIAMGR_H */ diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c new file mode 100755 index 0000000..bf40ea3 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c @@ -0,0 +1,1315 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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; + char *asc, *body; + + /* Read in ascii data */ + rv = SECU_FileToItem(&filedata, inFile); + asc = (char *)filedata.data; + if (!asc) { + fprintf(stderr, "unable to read data from input file\n"); + return SECFailure; + } + + /* 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h new file mode 100755 index 0000000..4e837f7 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h @@ -0,0 +1,67 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c new file mode 100755 index 0000000..69f5f48 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c @@ -0,0 +1,1180 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h new file mode 100644 index 0000000..97e45b7 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h @@ -0,0 +1,95 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c new file mode 100644 index 0000000..1bd0a5a --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c @@ -0,0 +1,1688 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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. + * "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 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 *plContext) +{ + 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 **)©, plContext), + 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 > 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 && + 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 (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, plContext), + 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, plContext), + 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. + * "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 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 *plContext) +{ + 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, + plContext), + 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 plContext argument in its + * function calls. Save it here. + */ + client->plContext = plContext; + + *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 *plContext) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_HTTPDEFAULTCLIENT_TYPE, plContext), + PKIX_OBJECTNOTANHTTPDEFAULTCLIENT); + + client = (PKIX_PL_HttpDefaultClient *)object; + + if (client->rcvHeaders) { + PKIX_PL_Free(client->rcvHeaders, plContext); + 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, plContext); + client->POSTBuf = NULL; + } + if (client->rcvBuf != NULL) { + PKIX_PL_Free(client->rcvBuf, plContext); + 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 *plContext) +{ + 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. + * "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 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 *plContext) +{ + 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, plContext), + 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. + * "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 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 *plContext) +{ + 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, + plContext), + 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. + * "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 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 *plContext) +{ + 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, 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 = 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. + * "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 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 *plContext) +{ + 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), + plContext), + 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, + plContext), + PKIX_SOCKETRECVFAILED); + + if (bytesRead > 0) { + /* client->filledupBytes will be adjusted by + * pkix_pl_HttpDefaultClient_HdrCheckComplete */ + PKIX_CHECK( + pkix_pl_HttpDefaultClient_HdrCheckComplete(client, bytesRead, + pKeepGoing, + plContext), + 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. + * "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 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 *plContext) +{ + 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, plContext), + PKIX_SOCKETPOLLFAILED); + + if (bytesRead > 0) { + client->filledupBytes += bytesRead; + + PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete + (client, bytesRead, pKeepGoing, plContext), + 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. + * "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 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 *plContext) +{ + 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 */ + 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, plContext), + 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, plContext), + PKIX_SOCKETPOLLFAILED); + } else { + PKIX_CHECK(callbackList->recvCallback + (client->socket, + (void *)&(client->rcvBuf[client->filledupBytes]), + bytesToRead, + &bytesRead, + plContext), + 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. + * "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 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 *plContext) +{ + 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, plContext), + PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED); + break; + case HTTP_CONNECTED: + PKIX_CHECK(pkix_pl_HttpDefaultClient_Send + (client, &keepGoing, &bytesTransferred, plContext), + PKIX_HTTPDEFAULTCLIENTSENDFAILED); + break; + case HTTP_SEND_PENDING: + PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue + (client, &keepGoing, &bytesTransferred, plContext), + PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED); + break; + case HTTP_RECV_HDR: + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr + (client, &keepGoing, plContext), + PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED); + break; + case HTTP_RECV_HDR_PENDING: + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue + (client, &keepGoing, plContext), + PKIX_HTTPDEFAULTCLIENTRECVHDRCONTINUEFAILED); + break; + case HTTP_RECV_BODY: + case HTTP_RECV_BODY_PENDING: + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvBody + (client, &keepGoing, plContext), + 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 *plContext) +{ + 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, plContext), + 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 *plContext) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_KeepAliveSession"); + PKIX_NULLCHECK_TWO(session, pPollDesc); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)session, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plContext), + PKIX_SESSIONNOTANHTTPDEFAULTCLIENT); + + client = (PKIX_PL_HttpDefaultClient *)session; + + /* 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 *plContext) +{ + 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, + plContext), + 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, + plContext), + PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED); +#else + PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection + (timeout, + (char *)client->host, + client->portnum, + &status, + &socket, + plContext), + PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED); +#endif + + client->socket = socket; + + PKIX_CHECK(pkix_pl_Socket_GetCallbackList + (socket, &callbackList, plContext), + PKIX_SOCKETGETCALLBACKLISTFAILED); + + client->callbackList = (void *)callbackList; + + PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc + (socket, &fileDesc, plContext), + 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 *plContext) +{ + 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, + plContext), + 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 *plContext) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + PKIX_UInt32 postLen = 0; + PRPollDesc *pollDesc = NULL; + char *sendbuf = NULL; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_TrySendAndReceive"); + + PKIX_NULLCHECK_ONE(request); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)request, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plContext), + 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 */ + if (client->send_http_method == HTTP_POST_METHOD) { + sendbuf = PR_smprintf + ("POST %s HTTP/1.0\r\nHost: %s:%d\r\n" + "Content-Type: %s\r\nContent-Length: %u\r\n\r\n", + client->path, + client->host, + client->portnum, + 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), + plContext), + 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.1\r\nHost: %s:%d\r\n\r\n", + client->path, + client->host, + client->portnum); + client->GETLen = PORT_Strlen(client->GETBuf); + } + + } + + /* continue according to state */ + PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plContext), + 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 *plContext) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel"); + PKIX_NULLCHECK_ONE(request); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)request, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plContext), + PKIX_REQUESTNOTANHTTPDEFAULTCLIENT); + + client = (PKIX_PL_HttpDefaultClient *)request; + + /* 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h new file mode 100644 index 0000000..0534779 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h @@ -0,0 +1,172 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c new file mode 100644 index 0000000..8f7863f --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c @@ -0,0 +1,1149 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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; + + PRArenaPool *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 PRArenaPool 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( + PRArenaPool *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) +{ + PRArenaPool *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, ¶ms, 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; + PRArenaPool *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, ¶ms, 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) { + for (thisName = 0; thisName < numNames; thisName++) { + 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; + } + + /* + * LDAP Servers don't seem to be able to handle + * requests with more than more than one name. + */ + break; + } + } 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h new file mode 100644 index 0000000..249c229 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h @@ -0,0 +1,108 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c new file mode 100644 index 0000000..45da0ab --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c @@ -0,0 +1,2526 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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 PRArenaPool 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( + PRArenaPool *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 PRArenaPool 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( + PRArenaPool *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 PRArenaPool 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( + PRArenaPool *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 PRArenaPool 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( + PRArenaPool *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 = NULL; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_VerifyBindResponse"); + PKIX_NULLCHECK_TWO(client, client->rcvBuf); + + decode.data = (void *)(client->rcvBuf); + decode.len = bufLen; + + PKIX_CHECK(pkix_pl_LdapDefaultClient_DecodeBindResponse + (client->arena, &decode, &msg, &rv, plContext), + PKIX_LDAPDEFAULTCLIENTDECODEBINDRESPONSEFAILED); + + if (rv == SECSuccess) { + ldapBindResponse = &msg.protocolOp.op.bindResponseMsg; + 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; + PRArenaPool *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 PRArenaPool 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( + PRArenaPool *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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h new file mode 100644 index 0000000..9bc2418 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h @@ -0,0 +1,115 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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; + PRArenaPool *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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c new file mode 100644 index 0000000..b728f3c --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c @@ -0,0 +1,794 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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_PL_LdapRequest *ldapRq = NULL; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPREQUEST_TYPE, plContext), + PKIX_OBJECTNOTLDAPREQUEST); + + ldapRq = (PKIX_PL_LdapRequest *)object; + + /* + * 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 PRArenaPool 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 PRArenaPool 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( + PRArenaPool *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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h new file mode 100644 index 0000000..11be678 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h @@ -0,0 +1,119 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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{ + PRArenaPool *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( + PRArenaPool *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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c new file mode 100644 index 0000000..a3915b1 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c @@ -0,0 +1,819 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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 PRArenaPool 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( + PRArenaPool *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 = *(char *)(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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h new file mode 100644 index 0000000..81a837f --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h @@ -0,0 +1,129 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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( + PRArenaPool *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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h new file mode 100644 index 0000000..66eda1f --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h @@ -0,0 +1,348 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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 { + PRArenaPool *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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c new file mode 100644 index 0000000..abd9fcb --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c @@ -0,0 +1,451 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c new file mode 100755 index 0000000..bf22e44 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c @@ -0,0 +1,350 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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; + PRArenaPool *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; + *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_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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h new file mode 100755 index 0000000..d579303 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h @@ -0,0 +1,84 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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; + PRArenaPool *arena; + void *wincx; + PKIX_UInt32 timeoutSeconds; + PKIX_UInt32 maxResponseLength; + PRTime crlReloadDelay; + PRTime badDerCrlReloadDelay; +}; + +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_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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c new file mode 100755 index 0000000..083197e --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c @@ -0,0 +1,1086 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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; + + PRArenaPool *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_NewTempCertificate, + (dbHandle, + &(node->cert->derCert), + NULL, /* nickname */ + PR_FALSE, + PR_TRUE)); /* copyDER */ + + 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; + CERTCertificate *cert; + PKIX_UInt32 dpIndex = 0; + SECStatus rv = SECSuccess; + PRTime reloadDelay = 0, badCrlInvalDelay = 0; + + PKIX_ENTER(CERTSTORE, "ChechCacheHasFetchedCrl"); + + cert = pkixCert->nssCert; + 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, + PKIX_UInt32 *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, ¶ms, 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; + 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; + PKIX_Int32 savedError = -1; + 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. */ + savedError = PKIX_UNSUPPORTEDCRLDPTYPE; + break; + } + uri = &genName->name.other; + location = (char*)PR_Malloc(1 + uri->len); + if (!location) { + savedError = PKIX_ALLOCERROR; + 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); + savedError = PKIX_URLPARSINGFAILED; + break; + } + + PORT_Assert(hostname != NULL); + PORT_Assert(path != NULL); + + if ((*hcv1->createSessionFcn)(hostname, port, + &pServerSession) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL); + savedError = PKIX_URLPARSINGFAILED; + 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) { + savedError = PKIX_HTTPSERVERERROR; + 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) { + savedError = PKIX_HTTPSERVERERROR; + break; + } + + if (myHttpResponseCode != 200) { + savedError = PKIX_HTTPSERVERERROR; + 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, + ®isteredHttpClient->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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h new file mode 100755 index 0000000..ab9ad89 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h @@ -0,0 +1,64 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c new file mode 100644 index 0000000..d5d3ea0 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c @@ -0,0 +1,1723 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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(); + printf("%lld:\n", prTime); +} + +/* + * 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)ptr); + 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)ptr); + } + 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)buf); + 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_GetEnv("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_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_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/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h new file mode 100644 index 0000000..133c620 --- /dev/null +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h @@ -0,0 +1,242 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the PKIX-C library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sun Microsystems, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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 */ |