diff options
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss')
99 files changed, 37137 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/Makefile new file mode 100644 index 0000000000..2b5492506c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/Makefile @@ -0,0 +1,44 @@ +#! gmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### diff --git a/security/nss/lib/libpkix/pkix_pl_nss/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/manifest.mn new file mode 100644 index 0000000000..f3c83511a9 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/manifest.mn @@ -0,0 +1,11 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +CORE_DEPTH = ../../.. +DEPTH = ../../.. + +# +DIRS = pki system module \ + $(NULL) + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile new file mode 100644 index 0000000000..e97ad8e4de --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile @@ -0,0 +1,66 @@ +#! gmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +ifdef NSS_PKIX_NO_LDAP +LDAP_HEADERS = +LDAP_CSRCS = +else +LDAP_HEADERS = \ + pkix_pl_ldapt.h \ + pkix_pl_ldapcertstore.h \ + pkix_pl_ldapresponse.h \ + pkix_pl_ldaprequest.h \ + pkix_pl_ldapdefaultclient.h \ + $(NULL) + +LDAP_CSRCS = \ + pkix_pl_ldaptemplates.c \ + pkix_pl_ldapcertstore.c \ + pkix_pl_ldapresponse.c \ + pkix_pl_ldaprequest.c \ + pkix_pl_ldapdefaultclient.c \ + $(NULL) +endif + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp new file mode 100644 index 0000000000..064a17ce44 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp @@ -0,0 +1,36 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'lib_libpkix_pkix_pl_nss_module_exports', + 'type': 'none', + 'copies': [ + { + 'files': [ + 'pkix_pl_aiamgr.h', + 'pkix_pl_colcertstore.h', + 'pkix_pl_httpcertstore.h', + 'pkix_pl_httpdefaultclient.h', + 'pkix_pl_ldapcertstore.h', + 'pkix_pl_ldapdefaultclient.h', + 'pkix_pl_ldaprequest.h', + 'pkix_pl_ldapresponse.h', + 'pkix_pl_ldapt.h', + 'pkix_pl_nsscontext.h', + 'pkix_pl_pk11certstore.h', + 'pkix_pl_socket.h' + ], + 'destination': '<(nss_private_dist_dir)/<(module)' + } + ] + } + ], + 'variables': { + 'module': 'nss' + } +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn new file mode 100644 index 0000000000..31231e4edf --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn @@ -0,0 +1,34 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +CORE_DEPTH = ../../../.. + +PRIVATE_EXPORTS = \ + pkix_pl_aiamgr.h \ + pkix_pl_colcertstore.h \ + pkix_pl_httpcertstore.h \ + pkix_pl_httpdefaultclient.h \ + $(LDAP_HEADERS) \ + pkix_pl_nsscontext.h \ + pkix_pl_pk11certstore.h \ + pkix_pl_socket.h \ + $(NULL) + +MODULE = nss + +DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DSHLIB_VERSION=\"$(LIBRARY_VERSION)\" + +CSRCS = \ + pkix_pl_aiamgr.c \ + pkix_pl_colcertstore.c \ + pkix_pl_httpcertstore.c \ + pkix_pl_httpdefaultclient.c \ + $(LDAP_CSRCS) \ + pkix_pl_nsscontext.c \ + pkix_pl_pk11certstore.c \ + pkix_pl_socket.c \ + $(NULL) + +LIBRARY_NAME = pkixmodule +SHARED_LIBRARY = $(NULL) diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp b/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp new file mode 100644 index 0000000000..8d7459ded6 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp @@ -0,0 +1,41 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'pkixmodule', + 'type': 'static_library', + 'sources': [ + 'pkix_pl_aiamgr.c', + 'pkix_pl_colcertstore.c', + 'pkix_pl_httpcertstore.c', + 'pkix_pl_httpdefaultclient.c', + 'pkix_pl_ldapcertstore.c', + 'pkix_pl_ldapdefaultclient.c', + 'pkix_pl_ldaprequest.c', + 'pkix_pl_ldapresponse.c', + 'pkix_pl_ldaptemplates.c', + 'pkix_pl_nsscontext.c', + 'pkix_pl_pk11certstore.c', + 'pkix_pl_socket.c' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports' + ] + } + ], + 'target_defaults': { + 'defines': [ + 'SHLIB_SUFFIX=\"<(dll_suffix)\"', + 'SHLIB_PREFIX=\"<(dll_prefix)\"', + 'SHLIB_VERSION=\"\"' + ] + }, + 'variables': { + 'module': 'nss' + } +}
\ No newline at end of file diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c new file mode 100644 index 0000000000..d9f5662303 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c @@ -0,0 +1,699 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_aiamgr.c + * + * AIAMgr Object Definitions + * + */ + +#include "pkix_pl_aiamgr.h" +extern PKIX_PL_HashTable *aiaConnectionCache; + +#ifndef NSS_PKIX_NO_LDAP +/* --Virtual-LdapClient-Functions------------------------------------ */ + +PKIX_Error * +PKIX_PL_LdapClient_InitiateRequest( + PKIX_PL_LdapClient *client, + LDAPRequestParams *requestParams, + void **pNBIO, + PKIX_List **pResponse, + void *plContext) +{ + PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_InitiateRequest"); + PKIX_NULLCHECK_TWO(client, client->initiateFcn); + + PKIX_CHECK(client->initiateFcn + (client, requestParams, pNBIO, pResponse, plContext), + PKIX_LDAPCLIENTINITIATEREQUESTFAILED); +cleanup: + + PKIX_RETURN(LDAPCLIENT); + +} + +PKIX_Error * +PKIX_PL_LdapClient_ResumeRequest( + PKIX_PL_LdapClient *client, + void **pNBIO, + PKIX_List **pResponse, + void *plContext) +{ + PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_ResumeRequest"); + PKIX_NULLCHECK_TWO(client, client->resumeFcn); + + PKIX_CHECK(client->resumeFcn + (client, pNBIO, pResponse, plContext), + PKIX_LDAPCLIENTRESUMEREQUESTFAILED); +cleanup: + + PKIX_RETURN(LDAPCLIENT); + +} +#endif /* !NSS_PKIX_NO_LDAP */ + +/* --Private-AIAMgr-Functions----------------------------------*/ + +/* + * FUNCTION: pkix_pl_AIAMgr_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_AIAMgr_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_AIAMgr *aiaMgr = NULL; + + PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_AIAMGR_TYPE, plContext), + PKIX_OBJECTNOTAIAMGR); + + aiaMgr = (PKIX_PL_AIAMgr *)object; + + /* pointer to cert cache */ + /* pointer to crl cache */ + aiaMgr->method = 0; + aiaMgr->aiaIndex = 0; + aiaMgr->numAias = 0; + PKIX_DECREF(aiaMgr->aia); + PKIX_DECREF(aiaMgr->location); + PKIX_DECREF(aiaMgr->results); +#ifndef NSS_PKIX_NO_LDAP + PKIX_DECREF(aiaMgr->client.ldapClient); +#endif + +cleanup: + + PKIX_RETURN(AIAMGR); +} + +/* + * FUNCTION: pkix_pl_AIAMgr_RegisterSelf + * DESCRIPTION: + * Registers PKIX_AIAMGR_TYPE and its related functions with systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_AIAMgr_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_AIAMGR_TYPE]; + + PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_RegisterSelf"); + + entry->description = "AIAMgr"; + entry->typeObjectSize = sizeof(PKIX_PL_AIAMgr); + entry->destructor = pkix_pl_AIAMgr_Destroy; + + PKIX_RETURN(AIAMGR); +} + +#ifndef NSS_PKIX_NO_LDAP +/* + * FUNCTION: pkix_pl_AiaMgr_FindLDAPClient + * DESCRIPTION: + * + * This function checks the collection of LDAPClient connections held by the + * AIAMgr pointed to by "aiaMgr" for one matching the domain name given by + * "domainName". The string may include a port number: e.g., "betty.nist.gov" + * or "nss.red.iplanet.com:1389". If a match is found, that LDAPClient is + * stored at "pClient". Otherwise, an LDAPClient is created and added to the + * collection, and then stored at "pClient". + * + * PARAMETERS: + * "aiaMgr" + * The AIAMgr whose LDAPClient connected are to be managed. Must be + * non-NULL. + * "domainName" + * Address of a string pointing to a server name. Must be non-NULL. + * An empty string (which means no <host> is given in the LDAP URL) is + * not supported. + * "pClient" + * Address at which the returned LDAPClient is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an AIAMgr Error if the function fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_AiaMgr_FindLDAPClient( + PKIX_PL_AIAMgr *aiaMgr, + char *domainName, + PKIX_PL_LdapClient **pClient, + void *plContext) +{ + PKIX_PL_String *domainString = NULL; + PKIX_PL_LdapDefaultClient *client = NULL; + + PKIX_ENTER(AIAMGR, "pkix_pl_AiaMgr_FindLDAPClient"); + PKIX_NULLCHECK_THREE(aiaMgr, domainName, pClient); + + /* + * An LDAP URL may not have a <host> part, for example, + * ldap:///o=University%20of%20Michigan,c=US + * PKIX_PL_LdapDefaultClient doesn't know how to discover the default + * LDAP server, so we don't support this kind of LDAP URL. + */ + if (*domainName == '\0') { + /* Simulate a PKIX_PL_LdapDefaultClient_CreateByName failure. */ + PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED); + } + + /* create PKIX_PL_String from domain name */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, domainName, 0, &domainString, plContext), + PKIX_STRINGCREATEFAILED); + + /* Is this domainName already in cache? */ + PKIX_CHECK(PKIX_PL_HashTable_Lookup + (aiaConnectionCache, + (PKIX_PL_Object *)domainString, + (PKIX_PL_Object **)&client, + plContext), + PKIX_HASHTABLELOOKUPFAILED); + + if (client == NULL) { + + /* No, create a connection (and cache it) */ + PKIX_CHECK(PKIX_PL_LdapDefaultClient_CreateByName + (domainName, + /* Do not use NBIO until we verify, that + * it is working. For now use 1 min timeout. */ + PR_SecondsToInterval( + ((PKIX_PL_NssContext*)plContext)->timeoutSeconds), + NULL, + &client, + plContext), + PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED); + + PKIX_CHECK(PKIX_PL_HashTable_Add + (aiaConnectionCache, + (PKIX_PL_Object *)domainString, + (PKIX_PL_Object *)client, + plContext), + PKIX_HASHTABLEADDFAILED); + + } + + *pClient = (PKIX_PL_LdapClient *)client; + +cleanup: + + PKIX_DECREF(domainString); + + PKIX_RETURN(AIAMGR); +} +#endif /* !NSS_PKIX_NO_LDAP */ + +PKIX_Error * +pkix_pl_AIAMgr_GetHTTPCerts( + PKIX_PL_AIAMgr *aiaMgr, + PKIX_PL_InfoAccess *ia, + void **pNBIOContext, + PKIX_List **pCerts, + void *plContext) +{ + PKIX_PL_GeneralName *location = NULL; + PKIX_PL_String *locationString = NULL; + PKIX_UInt32 len = 0; + PRUint16 port = 0; + const SEC_HttpClientFcn *httpClient = NULL; + const SEC_HttpClientFcnV1 *hcv1 = NULL; + SECStatus rv = SECFailure; + SEC_HTTP_SERVER_SESSION serverSession = NULL; + SEC_HTTP_REQUEST_SESSION requestSession = NULL; + char *path = NULL; + char *hostname = NULL; + char *locationAscii = NULL; + void *nbio = NULL; + PRUint16 responseCode = 0; + const char *responseContentType = NULL; + const char *responseData = NULL; + + PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts"); + PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts); + + nbio = *pNBIOContext; + *pNBIOContext = NULL; + *pCerts = NULL; + + if (nbio == NULL) { /* a new request */ + + PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation + (ia, &location, plContext), + PKIX_INFOACCESSGETLOCATIONFAILED); + + /* find or create httpClient = default client */ + httpClient = SEC_GetRegisteredHttpClient(); + aiaMgr->client.hdata.httpClient = httpClient; + if (!httpClient) + PKIX_ERROR(PKIX_OUTOFMEMORY); + + if (httpClient->version == 1) { + + PKIX_UInt32 timeout = + ((PKIX_PL_NssContext*)plContext)->timeoutSeconds; + + hcv1 = &(httpClient->fcnTable.ftable1); + + /* create server session */ + PKIX_TOSTRING(location, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (locationString, + PKIX_ESCASCII, + (void **)&locationAscii, + &len, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + rv = CERT_ParseURL(locationAscii, &hostname, &port, + &path); + if ((rv != SECSuccess) || + (hostname == NULL) || + (path == NULL)) { + PKIX_ERROR(PKIX_URLPARSINGFAILED); + } + + rv = (*hcv1->createSessionFcn)(hostname, port, + &serverSession); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED); + } + + aiaMgr->client.hdata.serverSession = serverSession; + + /* create request session */ + rv = (*hcv1->createFcn)(serverSession, "http", path, + "GET", PR_SecondsToInterval(timeout), + &requestSession); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + aiaMgr->client.hdata.requestSession = requestSession; + } else { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + } + + httpClient = aiaMgr->client.hdata.httpClient; + + if (httpClient->version == 1) { + PRUint32 responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + hcv1 = &(httpClient->fcnTable.ftable1); + requestSession = aiaMgr->client.hdata.requestSession; + + /* trySendAndReceive */ + rv = (*hcv1->trySendAndReceiveFcn)(requestSession, + (PRPollDesc **)&nbio, + &responseCode, + (const char **)&responseContentType, + NULL, /* &responseHeaders */ + (const char **)&responseData, + &responseDataLen); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + if (nbio != 0) { + *pNBIOContext = nbio; + goto cleanup; + } + + PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse + (responseCode, + responseContentType, + responseData, + responseDataLen, + pCerts, + plContext), + PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); + + /* Session and request cleanup in case of success */ + if (aiaMgr->client.hdata.requestSession != NULL) { + (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); + aiaMgr->client.hdata.requestSession = NULL; + } + if (aiaMgr->client.hdata.serverSession != NULL) { + (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); + aiaMgr->client.hdata.serverSession = NULL; + } + aiaMgr->client.hdata.httpClient = 0; /* callback fn */ + + } else { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + +cleanup: + /* Session and request cleanup in case of error. Passing through without cleanup + * if interrupted by blocked IO. */ + if (PKIX_ERROR_RECEIVED) { + if (aiaMgr->client.hdata.requestSession != NULL) { + (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); + aiaMgr->client.hdata.requestSession = NULL; + } + if (aiaMgr->client.hdata.serverSession != NULL) { + (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); + aiaMgr->client.hdata.serverSession = NULL; + } + aiaMgr->client.hdata.httpClient = 0; /* callback fn */ + } + + PKIX_DECREF(location); + PKIX_DECREF(locationString); + + if (locationAscii) { + PORT_Free(locationAscii); + } + if (hostname) { + PORT_Free(hostname); + } + if (path) { + PORT_Free(path); + } + + PKIX_RETURN(AIAMGR); +} + +#ifndef NSS_PKIX_NO_LDAP +PKIX_Error * +pkix_pl_AIAMgr_GetLDAPCerts( + PKIX_PL_AIAMgr *aiaMgr, + PKIX_PL_InfoAccess *ia, + void **pNBIOContext, + PKIX_List **pCerts, + void *plContext) +{ + PKIX_List *result = NULL; + PKIX_PL_GeneralName *location = NULL; + PKIX_PL_LdapClient *client = NULL; + LDAPRequestParams request; + PLArenaPool *arena = NULL; + char *domainName = NULL; + void *nbio = NULL; + + PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts"); + PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts); + + nbio = *pNBIOContext; + *pNBIOContext = NULL; + *pCerts = NULL; + + if (nbio == NULL) { /* a new request */ + + /* Initiate an LDAP request */ + + request.scope = WHOLE_SUBTREE; + request.derefAliases = NEVER_DEREF; + request.sizeLimit = 0; + request.timeLimit = 0; + + PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation + (ia, &location, plContext), + PKIX_INFOACCESSGETLOCATIONFAILED); + + /* + * Get a short-lived arena. We'll be done with + * this space once the request is encoded. + */ + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY); + } + + PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation + (location, arena, &request, &domainName, plContext), + PKIX_INFOACCESSPARSELOCATIONFAILED); + + PKIX_DECREF(location); + + /* Find or create a connection to LDAP server */ + PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient + (aiaMgr, domainName, &client, plContext), + PKIX_AIAMGRFINDLDAPCLIENTFAILED); + + aiaMgr->client.ldapClient = client; + + PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest + (aiaMgr->client.ldapClient, + &request, + &nbio, + &result, + plContext), + PKIX_LDAPCLIENTINITIATEREQUESTFAILED); + + PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE)); + + } else { + + PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest + (aiaMgr->client.ldapClient, &nbio, &result, plContext), + PKIX_LDAPCLIENTRESUMEREQUESTFAILED); + + } + + if (nbio != NULL) { /* WOULDBLOCK */ + *pNBIOContext = nbio; + *pCerts = NULL; + goto cleanup; + } + + PKIX_DECREF(aiaMgr->client.ldapClient); + + if (result == NULL) { + *pCerts = NULL; + } else { + PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList + (result, pCerts, plContext), + PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED); + } + + *pNBIOContext = nbio; + +cleanup: + + if (arena && (PKIX_ERROR_RECEIVED)) { + PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE)); + } + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(aiaMgr->client.ldapClient); + } + + PKIX_DECREF(location); + + PKIX_RETURN(AIAMGR); +} +#endif /* !NSS_PKIX_NO_LDAP */ + +/* + * FUNCTION: PKIX_PL_AIAMgr_Create + * DESCRIPTION: + * + * This function creates an AIAMgr, storing the result at "pAIAMgr". + * + * PARAMETERS: + * "pAIAMGR" + * Address at which the returned AIAMgr is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an AIAMgr Error if the function fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +PKIX_PL_AIAMgr_Create( + PKIX_PL_AIAMgr **pAIAMgr, + void *plContext) +{ + PKIX_PL_AIAMgr *aiaMgr = NULL; + + PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_Create"); + PKIX_NULLCHECK_ONE(pAIAMgr); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_AIAMGR_TYPE, + sizeof(PKIX_PL_AIAMgr), + (PKIX_PL_Object **)&aiaMgr, + plContext), + PKIX_COULDNOTCREATEAIAMGROBJECT); + /* pointer to cert cache */ + /* pointer to crl cache */ + aiaMgr->method = 0; + aiaMgr->aiaIndex = 0; + aiaMgr->numAias = 0; + aiaMgr->aia = NULL; + aiaMgr->location = NULL; + aiaMgr->results = NULL; + aiaMgr->client.hdata.httpClient = NULL; + aiaMgr->client.hdata.serverSession = NULL; + aiaMgr->client.hdata.requestSession = NULL; + + *pAIAMgr = aiaMgr; + +cleanup: + + PKIX_RETURN(AIAMGR); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_AIAMgr_GetAIACerts( + PKIX_PL_AIAMgr *aiaMgr, + PKIX_PL_Cert *prevCert, + void **pNBIOContext, + PKIX_List **pCerts, + void *plContext) +{ + PKIX_UInt32 numAias = 0; + PKIX_UInt32 aiaIndex = 0; + PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN; + PKIX_List *certs = NULL; + PKIX_PL_InfoAccess *ia = NULL; + void *nbio = NULL; + + PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts"); + PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts); + + nbio = *pNBIOContext; + *pCerts = NULL; + *pNBIOContext = NULL; + + if (nbio == NULL) { /* a new request */ + + /* Does this Cert have an AIA extension? */ + PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess + (prevCert, &aiaMgr->aia, plContext), + PKIX_CERTGETAUTHORITYINFOACCESSFAILED); + + if (aiaMgr->aia != NULL) { + PKIX_CHECK(PKIX_List_GetLength + (aiaMgr->aia, &numAias, plContext), + PKIX_LISTGETLENGTHFAILED); + } + + /* And if so, does it have any entries? */ + if ((aiaMgr->aia == NULL) || (numAias == 0)) { + *pCerts = NULL; + goto cleanup; + } + + aiaMgr->aiaIndex = 0; + aiaMgr->numAias = numAias; + aiaMgr->results = NULL; + + } + + for (aiaIndex = aiaMgr->aiaIndex; + aiaIndex < aiaMgr->numAias; + aiaIndex ++) { + PKIX_UInt32 method = 0; + + PKIX_CHECK(PKIX_List_GetItem + (aiaMgr->aia, + aiaIndex, + (PKIX_PL_Object **)&ia, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod + (ia, &method, plContext), + PKIX_INFOACCESSGETMETHODFAILED); + + if (method != PKIX_INFOACCESS_CA_ISSUERS && + method != PKIX_INFOACCESS_CA_REPOSITORY) { + PKIX_DECREF(ia); + continue; + } + + PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType + (ia, &iaType, plContext), + PKIX_INFOACCESSGETLOCATIONTYPEFAILED); + + if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) { + PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts + (aiaMgr, ia, &nbio, &certs, plContext), + PKIX_AIAMGRGETHTTPCERTSFAILED); +#ifndef NSS_PKIX_NO_LDAP + } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) { + PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts + (aiaMgr, ia, &nbio, &certs, plContext), + PKIX_AIAMGRGETLDAPCERTSFAILED); +#endif + } else { + /* We only support http and ldap requests. */ + PKIX_DECREF(ia); + continue; + } + + if (nbio != NULL) { /* WOULDBLOCK */ + aiaMgr->aiaIndex = aiaIndex; + *pNBIOContext = nbio; + *pCerts = NULL; + goto cleanup; + } + + /* + * We can't just use and modify the List we received. + * Because it's cached, it's set immutable. + */ + if (aiaMgr->results == NULL) { + PKIX_CHECK(PKIX_List_Create + (&(aiaMgr->results), plContext), + PKIX_LISTCREATEFAILED); + } + PKIX_CHECK(pkix_List_AppendList + (aiaMgr->results, certs, plContext), + PKIX_APPENDLISTFAILED); + PKIX_DECREF(certs); + + PKIX_DECREF(ia); + } + + PKIX_DECREF(aiaMgr->aia); + + *pNBIOContext = NULL; + *pCerts = aiaMgr->results; + aiaMgr->results = NULL; + +cleanup: + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(aiaMgr->aia); + PKIX_DECREF(aiaMgr->results); +#ifndef NSS_PKIX_NO_LDAP + PKIX_DECREF(aiaMgr->client.ldapClient); +#endif + } + + PKIX_DECREF(certs); + PKIX_DECREF(ia); + + PKIX_RETURN(AIAMGR); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h new file mode 100644 index 0000000000..356c1ecdf2 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_aiamgr.h + * + * AIAMgr Object Definitions + * + */ + +#ifndef _PKIX_PL_AIAMGR_H +#define _PKIX_PL_AIAMGR_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_AIAMgrStruct { + /* pointer to cert cache */ + /* pointer to crl cache */ + PKIX_UInt32 method; + PKIX_UInt32 aiaIndex; + PKIX_UInt32 numAias; + PKIX_List *aia; + PKIX_PL_GeneralName *location; + PKIX_List *results; + union { +#ifndef NSS_PKIX_NO_LDAP + PKIX_PL_LdapClient *ldapClient; +#endif + struct { + const SEC_HttpClientFcn *httpClient; + SEC_HTTP_SERVER_SESSION serverSession; + SEC_HTTP_REQUEST_SESSION requestSession; + char *path; + } hdata; + } client; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_AIAMgr_RegisterSelf(void *plContext); + +#ifndef NSS_PKIX_NO_LDAP +PKIX_Error *PKIX_PL_LdapClient_InitiateRequest( + PKIX_PL_LdapClient *client, + LDAPRequestParams *requestParams, + void **pPollDesc, + PKIX_List **pResponse, + void *plContext); + +PKIX_Error *PKIX_PL_LdapClient_ResumeRequest( + PKIX_PL_LdapClient *client, + void **pPollDesc, + PKIX_List **pResponse, + void *plContext); +#endif /* !NSS_PKIX_NO_LDAP */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_AIAMGR_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c new file mode 100644 index 0000000000..4cc5607cf6 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c @@ -0,0 +1,1292 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_colcertstore.c + * + * CollectionCertStore Function Definitions + * + */ + +#include "pkix_pl_colcertstore.h" + +/* + * This Object is going to be taken out from libpkix SOON. The following + * function is copied from nss/cmd library, but not supported by NSS as + * public API. We use it since ColCertStore are read in Cert/Crl from + * files and need this support. + */ + +static SECStatus +SECU_FileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + /* XXX workaround for 3.1, not all utils zero dst before sending */ + dst->data = 0; + if (!SECITEM_AllocItem(NULL, dst, info.size)) + goto loser; + + numBytes = PR_Read(src, dst->data, info.size); + if (numBytes != info.size) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + + return SECSuccess; +loser: + SECITEM_FreeItem(dst, PR_FALSE); + return SECFailure; +} + +static SECStatus +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii) +{ + SECStatus rv; + if (ascii) { + /* First convert ascii to binary */ + SECItem filedata; + + /* Read in ascii data */ + rv = SECU_FileToItem(&filedata, inFile); + if (rv != SECSuccess) { + return rv; + } + if (!filedata.data) { + fprintf(stderr, "unable to read data from input file\n"); + return SECFailure; + } + /* need one additional byte for zero terminator */ + rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len + 1); + if (rv != SECSuccess) { + PORT_Free(filedata.data); + return rv; + } + char *asc = (char *)filedata.data; + asc[filedata.len - 1] = '\0'; + + char *body; + /* check for headers and trailers and remove them */ + if ((body = strstr(asc, "-----BEGIN")) != NULL) { + char *trailer = NULL; + asc = body; + body = PORT_Strchr(body, '\n'); + if (!body) + body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */ + if (body) + trailer = strstr(++body, "-----END"); + if (trailer != NULL) { + *trailer = '\0'; + } else { + fprintf(stderr, "input has header but no trailer\n"); + PORT_Free(filedata.data); + return SECFailure; + } + } else { + body = asc; + } + + /* Convert to binary */ + rv = ATOB_ConvertAsciiToItem(der, body); + if (rv) { + return SECFailure; + } + + PORT_Free(filedata.data); + } else { + /* Read in binary der */ + rv = SECU_FileToItem(der, inFile); + if (rv) { + return SECFailure; + } + } + return SECSuccess; +} + +/* + * FUNCTION: PKIX_PL_CollectionCertStoreContext_Create + * DESCRIPTION: + * + * Creates a new CollectionCertStoreContext using the String pointed to + * by "storeDir" and stores it at "pColCertStoreContext". + * + * PARAMETERS: + * "storeDir" + * The absolute path where *.crl and *.crt files are located. + * "pColCertStoreContext" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CollectionCertStoreContext Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_Create( + PKIX_PL_String *storeDir, + PKIX_PL_CollectionCertStoreContext **pColCertStoreContext, + void *plContext) +{ + PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_Create"); + PKIX_NULLCHECK_TWO(storeDir, pColCertStoreContext); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_COLLECTIONCERTSTORECONTEXT_TYPE, + sizeof (PKIX_PL_CollectionCertStoreContext), + (PKIX_PL_Object **)&colCertStoreContext, + plContext), + PKIX_COULDNOTCREATECOLLECTIONCERTSTORECONTEXTOBJECT); + + PKIX_INCREF(storeDir); + colCertStoreContext->storeDir = storeDir; + + colCertStoreContext->crlList = NULL; + colCertStoreContext->certList = NULL; + + *pColCertStoreContext = colCertStoreContext; + colCertStoreContext = NULL; + +cleanup: + + PKIX_DECREF(colCertStoreContext); + + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_COLLECTIONCERTSTORECONTEXT_TYPE, plContext), + PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT); + + colCertStoreContext = (PKIX_PL_CollectionCertStoreContext *)object; + + PKIX_DECREF(colCertStoreContext->storeDir); + PKIX_DECREF(colCertStoreContext->crlList); + PKIX_DECREF(colCertStoreContext->certList); + +cleanup: + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CollectionCertStoreContext *collectionCSContext = NULL; + PKIX_UInt32 tempHash = 0; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, + PKIX_COLLECTIONCERTSTORECONTEXT_TYPE, + plContext), + PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT); + + collectionCSContext = (PKIX_PL_CollectionCertStoreContext *)object; + + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *) collectionCSContext->storeDir, + &tempHash, + plContext), + PKIX_STRINGHASHCODEFAILED); + + *pHashcode = tempHash << 7; + + /* should not hash on crlList and certList, values are dynamic */ + +cleanup: + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_PL_CollectionCertStoreContext *firstCCSContext = NULL; + PKIX_PL_CollectionCertStoreContext *secondCCSContext = NULL; + PKIX_Boolean cmpResult = 0; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + PKIX_CHECK(pkix_CheckTypes + (firstObject, + secondObject, + PKIX_COLLECTIONCERTSTORECONTEXT_TYPE, + plContext), + PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT); + + firstCCSContext = (PKIX_PL_CollectionCertStoreContext *)firstObject; + secondCCSContext = (PKIX_PL_CollectionCertStoreContext *)secondObject; + + if (firstCCSContext->storeDir == secondCCSContext->storeDir) { + + cmpResult = PKIX_TRUE; + + } else { + + PKIX_CHECK(PKIX_PL_Object_Equals + ((PKIX_PL_Object *) firstCCSContext->storeDir, + (PKIX_PL_Object *) secondCCSContext->storeDir, + &cmpResult, + plContext), + PKIX_STRINGEQUALSFAILED); + } + + *pResult = cmpResult; + + /* should not check equal on crlList and certList, data are dynamic */ + +cleanup: + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStore_CheckTrust + * DESCRIPTION: + * This function checks the trust status of this "cert" that was retrieved + * from the CertStore "store" and returns its trust status at "pTrusted". + * + * PARAMETERS: + * "store" + * Address of the CertStore. Must be non-NULL. + * "cert" + * Address of the Cert. Must be non-NULL. + * "pTrusted" + * Address of PKIX_Boolean where the "cert" trust status is returned. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStore_CheckTrust( + PKIX_CertStore *store, + PKIX_PL_Cert *cert, + PKIX_Boolean *pTrusted, + void *plContext) +{ + PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_CheckTrust"); + PKIX_NULLCHECK_THREE(store, cert, pTrusted); + + *pTrusted = PKIX_TRUE; + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_CreateCert + * DESCRIPTION: + * + * Creates Cert using data file path name pointed to by "certFileName" and + * stores it at "pCert". If the Cert can not be decoded, NULL is stored + * at "pCert". + * + * PARAMETERS + * "certFileName" - Address of Cert data file path name. Must be non-NULL. + * "pCert" - Address where object pointer will be stored. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CollectionCertStoreContext Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_CreateCert( + const char *certFileName, + PKIX_PL_Cert **pCert, + void *plContext) +{ + PKIX_PL_ByteArray *byteArray = NULL; + PKIX_PL_Cert *cert = NULL; + PRFileDesc *inFile = NULL; + SECItem certDER; + void *buf = NULL; + PKIX_UInt32 len; + SECStatus rv; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_CreateCert"); + PKIX_NULLCHECK_TWO(certFileName, pCert); + + *pCert = NULL; + certDER.data = NULL; + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_Open.\n"); + inFile = PR_Open(certFileName, PR_RDONLY, 0); + + if (!inFile){ + PKIX_ERROR(PKIX_UNABLETOOPENCERTFILE); + } else { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling SECU_ReadDerFromFile.\n"); + rv = SECU_ReadDERFromFile(&certDER, inFile, PR_FALSE); + if (!rv){ + buf = (void *)certDER.data; + len = certDER.len; + + PKIX_CHECK(PKIX_PL_ByteArray_Create + (buf, len, &byteArray, plContext), + PKIX_BYTEARRAYCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Cert_Create + (byteArray, &cert, plContext), + PKIX_CERTCREATEFAILED); + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling SECITEM_FreeItem.\n"); + SECITEM_FreeItem(&certDER, PR_FALSE); + + } else { + PKIX_ERROR(PKIX_UNABLETOREADDERFROMCERTFILE); + } + } + + *pCert = cert; + +cleanup: + if (inFile){ + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_CloseDir.\n"); + PR_Close(inFile); + } + + if (PKIX_ERROR_RECEIVED){ + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&certDER, PR_FALSE); + + PKIX_DECREF(cert); + } + PKIX_DECREF(byteArray); + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_CreateCRL + * DESCRIPTION: + * + * Creates CRL using data file path name pointed to by "crlFileName" and + * stores it at "pCrl". If the CRL can not be decoded, NULL is stored + * at "pCrl". + * + * PARAMETERS + * "crlFileName" - Address of CRL data file path name. Must be non-NULL. + * "pCrl" - Address where object pointer will be stored. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CollectionCertStoreContext Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_CreateCRL( + const char *crlFileName, + PKIX_PL_CRL **pCrl, + void *plContext) +{ + PKIX_PL_ByteArray *byteArray = NULL; + PKIX_PL_CRL *crl = NULL; + PRFileDesc *inFile = NULL; + SECItem crlDER; + void *buf = NULL; + PKIX_UInt32 len; + SECStatus rv; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_CreateCRL"); + PKIX_NULLCHECK_TWO(crlFileName, pCrl); + + *pCrl = NULL; + crlDER.data = NULL; + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_Open.\n"); + inFile = PR_Open(crlFileName, PR_RDONLY, 0); + + if (!inFile){ + PKIX_ERROR(PKIX_UNABLETOOPENCRLFILE); + } else { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling SECU_ReadDerFromFile.\n"); + rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE); + if (!rv){ + buf = (void *)crlDER.data; + len = crlDER.len; + + PKIX_CHECK(PKIX_PL_ByteArray_Create + (buf, len, &byteArray, plContext), + PKIX_BYTEARRAYCREATEFAILED); + + PKIX_CHECK(PKIX_PL_CRL_Create + (byteArray, &crl, plContext), + PKIX_CRLCREATEFAILED); + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling SECITEM_FreeItem.\n"); + SECITEM_FreeItem(&crlDER, PR_FALSE); + + } else { + PKIX_ERROR(PKIX_UNABLETOREADDERFROMCRLFILE); + } + } + + *pCrl = crl; + +cleanup: + if (inFile){ + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_CloseDir.\n"); + PR_Close(inFile); + } + + if (PKIX_ERROR_RECEIVED){ + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&crlDER, PR_FALSE); + + PKIX_DECREF(crl); + if (crlDER.data != NULL) { + SECITEM_FreeItem(&crlDER, PR_FALSE); + } + } + + PKIX_DECREF(byteArray); + + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_PopulateCert + * DESCRIPTION: + * + * Create list of Certs from *.crt files at directory specified in dirName, + * Not recursive to sub-directory. Also assume the directory contents are + * not changed dynamically. + * + * PARAMETERS + * "colCertStoreContext" - Address of CollectionCertStoreContext + * where the dirName is specified and where the return + * Certs are stored as a list. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * + * THREAD SAFETY: + * Not Thread Safe - A lock at top level is required. + * + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CollectionCertStoreContext Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_PopulateCert( + PKIX_PL_CollectionCertStoreContext *colCertStoreContext, + void *plContext) +{ + PKIX_List *certList = NULL; + PKIX_PL_Cert *certItem = NULL; + char *dirName = NULL; + char *pathName = NULL; + PKIX_UInt32 dirNameLen = 0; + PRErrorCode prError = 0; + PRDir *dir = NULL; + PRDirEntry *dirEntry = NULL; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_PopulateCert"); + PKIX_NULLCHECK_ONE(colCertStoreContext); + + /* convert directory to ascii */ + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (colCertStoreContext->storeDir, + PKIX_ESCASCII, + (void **)&dirName, + &dirNameLen, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + /* create cert list, if no cert file, should return an empty list */ + + PKIX_CHECK(PKIX_List_Create(&certList, plContext), + PKIX_LISTCREATEFAILED); + + /* open directory and read in .crt files */ + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_OpenDir.\n"); + dir = PR_OpenDir(dirName); + + if (!dir) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG_ARG + ("\t\t Directory Name:%s\n", dirName); + PKIX_ERROR(PKIX_CANNOTOPENCOLLECTIONCERTSTORECONTEXTDIRECTORY); + } + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_ReadDir.\n"); + dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH); + + if (!dirEntry) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Empty directory.\n"); + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_GetError.\n"); + prError = PR_GetError(); + } + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_SetError.\n"); + PR_SetError(0, 0); + + while (dirEntry != NULL && prError == 0) { + if (PL_strrstr(dirEntry->name, ".crt") == + dirEntry->name + PL_strlen(dirEntry->name) - 4) { + + PKIX_CHECK_ONLY_FATAL + (PKIX_PL_Malloc + (dirNameLen + PL_strlen(dirEntry->name) + 2, + (void **)&pathName, + plContext), + PKIX_MALLOCFAILED); + + if ((!PKIX_ERROR_RECEIVED) && (pathName != NULL)){ + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PL_strcpy for dirName.\n"); + PL_strcpy(pathName, dirName); + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PL_strcat for dirName.\n"); + PL_strcat(pathName, "/"); + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PL_strcat for /.\n"); + PL_strcat(pathName, dirEntry->name); + + PKIX_CHECK_ONLY_FATAL + (pkix_pl_CollectionCertStoreContext_CreateCert + (pathName, &certItem, plContext), + PKIX_COLLECTIONCERTSTORECONTEXTCREATECERTFAILED); + + if (!PKIX_ERROR_RECEIVED){ + PKIX_CHECK_ONLY_FATAL + (PKIX_List_AppendItem + (certList, + (PKIX_PL_Object *)certItem, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + } + + PKIX_DECREF(certItem); + PKIX_FREE(pathName); + } + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_SetError.\n"); + PR_SetError(0, 0); + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_ReadDir.\n"); + dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH); + + if (!dirEntry) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_GetError.\n"); + prError = PR_GetError(); + } + } + + if ((prError != 0) && (prError != PR_NO_MORE_FILES_ERROR)) { + PKIX_ERROR(PKIX_COLLECTIONCERTSTOREPOPULATECERTFAILED); + } + + PKIX_CHECK(PKIX_List_SetImmutable(certList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + PKIX_INCREF(certList); + colCertStoreContext->certList = certList; + +cleanup: + if (dir) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_CloseDir.\n"); + PR_CloseDir(dir); + } + + PKIX_FREE(pathName); + PKIX_FREE(dirName); + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(certList); + } + + PKIX_DECREF(certItem); + PKIX_DECREF(certList); + + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_PopulateCRL + * DESCRIPTION: + * + * Create list of CRLs from *.crl files at directory specified in dirName, + * Not recursive to sub-dirctory. Also assume the directory contents are + * not changed dynamically. + * + * PARAMETERS + * "colCertStoreContext" - Address of CollectionCertStoreContext + * where the dirName is specified and where the return + * CRLs are stored as a list. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * + * THREAD SAFETY: + * Not Thread Safe - A lock at top level is required. + * + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CollectionCertStoreContext Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_PopulateCRL( + PKIX_PL_CollectionCertStoreContext *colCertStoreContext, + void *plContext) +{ + PKIX_List *crlList = NULL; + PKIX_PL_CRL *crlItem = NULL; + char *dirName = NULL; + char *pathName = NULL; + PKIX_UInt32 dirNameLen = 0; + PRErrorCode prError = 0; + PRDir *dir = NULL; + PRDirEntry *dirEntry = NULL; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_PopulateCRL"); + PKIX_NULLCHECK_ONE(colCertStoreContext); + + /* convert directory to ascii */ + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (colCertStoreContext->storeDir, + PKIX_ESCASCII, + (void **)&dirName, + &dirNameLen, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + /* create CRL list, if no CRL file, should return an empty list */ + + PKIX_CHECK(PKIX_List_Create(&crlList, plContext), + PKIX_LISTCREATEFAILED); + + /* open directory and read in .crl files */ + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_OpenDir.\n"); + dir = PR_OpenDir(dirName); + + if (!dir) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG_ARG + ("\t\t Directory Name:%s\n", dirName); + PKIX_ERROR(PKIX_CANNOTOPENCOLLECTIONCERTSTORECONTEXTDIRECTORY); + } + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_ReadDir.\n"); + dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH); + + if (!dirEntry) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Empty directory.\n"); + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_GetError.\n"); + prError = PR_GetError(); + } + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_SetError.\n"); + PR_SetError(0, 0); + + while (dirEntry != NULL && prError == 0) { + if (PL_strrstr(dirEntry->name, ".crl") == + dirEntry->name + PL_strlen(dirEntry->name) - 4) { + + PKIX_CHECK_ONLY_FATAL + (PKIX_PL_Malloc + (dirNameLen + PL_strlen(dirEntry->name) + 2, + (void **)&pathName, + plContext), + PKIX_MALLOCFAILED); + + if ((!PKIX_ERROR_RECEIVED) && (pathName != NULL)){ + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PL_strcpy for dirName.\n"); + PL_strcpy(pathName, dirName); + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PL_strcat for dirName.\n"); + PL_strcat(pathName, "/"); + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PL_strcat for /.\n"); + PL_strcat(pathName, dirEntry->name); + + PKIX_CHECK_ONLY_FATAL + (pkix_pl_CollectionCertStoreContext_CreateCRL + (pathName, &crlItem, plContext), + PKIX_COLLECTIONCERTSTORECONTEXTCREATECRLFAILED); + + if (!PKIX_ERROR_RECEIVED){ + PKIX_CHECK_ONLY_FATAL + (PKIX_List_AppendItem + (crlList, + (PKIX_PL_Object *)crlItem, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + } + + PKIX_DECREF(crlItem); + PKIX_FREE(pathName); + } + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_SetError.\n"); + PR_SetError(0, 0); + + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_ReadDir.\n"); + dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH); + + if (!dirEntry) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_GetError.\n"); + prError = PR_GetError(); + } + } + + if ((prError != 0) && (prError != PR_NO_MORE_FILES_ERROR)) { + PKIX_ERROR(PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCRLFAILED); + } + + PKIX_CHECK(PKIX_List_SetImmutable(crlList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + PKIX_INCREF(crlList); + colCertStoreContext->crlList = crlList; + +cleanup: + if (dir) { + PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG + ("\t\t Calling PR_CloseDir.\n"); + PR_CloseDir(dir); + } + + PKIX_FREE(pathName); + PKIX_FREE(dirName); + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(crlList); + } + + PKIX_DECREF(crlItem); + PKIX_DECREF(crlList); + + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCert + * DESCRIPTION: + * + * Finds the Certs that match the criterion of the CertSelector pointed + * to by "selector" using the List of Certs pointed to by "certList" and + * stores the matching Certs at "pSelectedCertList". + * + * Not recursive to sub-directory. + * + * PARAMETERS + * "certList" - Address of List of Certs to be searched. Must be non-NULL. + * "colCertStoreContext" - Address of CollectionCertStoreContext + * where the cached Certs are stored. + * "selector" - CertSelector for chosing Cert based on Params set + * "pSelectedCertList" - Certs that qualified by selector. + * "plContext" - Platform-specific context pointer. + * + * THREAD SAFETY: + * Not Thread Safe - A lock at top level is required. + * + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CollectionCertStoreContext Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_GetSelectedCert( + PKIX_List *certList, + PKIX_CertSelector *selector, + PKIX_List **pSelectedCertList, + void *plContext) +{ + PKIX_List *selectCertList = NULL; + PKIX_PL_Cert *certItem = NULL; + PKIX_CertSelector_MatchCallback certSelectorMatch = NULL; + PKIX_UInt32 numCerts = 0; + PKIX_UInt32 i = 0; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_GetSelectedCert"); + PKIX_NULLCHECK_THREE(certList, selector, pSelectedCertList); + + PKIX_CHECK(PKIX_CertSelector_GetMatchCallback + (selector, &certSelectorMatch, plContext), + PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); + + PKIX_CHECK(PKIX_List_GetLength(certList, &numCerts, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (certSelectorMatch) { + + PKIX_CHECK(PKIX_List_Create(&selectCertList, plContext), + PKIX_LISTCREATEFAILED); + + for (i = 0; i < numCerts; i++) { + PKIX_CHECK_ONLY_FATAL + (PKIX_List_GetItem + (certList, + i, + (PKIX_PL_Object **) &certItem, + plContext), + PKIX_LISTGETITEMFAILED); + + if (!PKIX_ERROR_RECEIVED){ + PKIX_CHECK_ONLY_FATAL + (certSelectorMatch + (selector, certItem, plContext), + PKIX_CERTSELECTORMATCHFAILED); + + if (!PKIX_ERROR_RECEIVED){ + PKIX_CHECK_ONLY_FATAL + (PKIX_List_AppendItem + (selectCertList, + (PKIX_PL_Object *)certItem, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + } + + PKIX_DECREF(certItem); + } + + } else { + + PKIX_INCREF(certList); + + selectCertList = certList; + } + + *pSelectedCertList = selectCertList; + +cleanup: + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCRL + * DESCRIPTION: + * + * Finds the CRLs that match the criterion of the CRLSelector pointed + * to by "selector" using the List of CRLs pointed to by "crlList" and + * stores the matching CRLs at "pSelectedCrlList". + * + * Not recursive to sub-directory. + * + * PARAMETERS + * "crlList" - Address of List of CRLs to be searched. Must be non-NULL + * "selector" - CRLSelector for chosing CRL based on Params set + * "pSelectedCrlList" - CRLs that qualified by selector. + * "plContext" - Platform-specific context pointer. + * + * THREAD SAFETY: + * Not Thread Safe - A lock at top level is required. + * + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CollectionCertStoreContext Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_CollectionCertStoreContext_GetSelectedCRL( + PKIX_List *crlList, + PKIX_CRLSelector *selector, + PKIX_List **pSelectedCrlList, + void *plContext) +{ + PKIX_List *selectCrlList = NULL; + PKIX_PL_CRL *crlItem = NULL; + PKIX_CRLSelector_MatchCallback crlSelectorMatch = NULL; + PKIX_UInt32 numCrls = 0; + PKIX_UInt32 i = 0; + PKIX_Boolean match = PKIX_FALSE; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_GetSelectedCRL"); + PKIX_NULLCHECK_THREE(crlList, selector, pSelectedCrlList); + + PKIX_CHECK(PKIX_CRLSelector_GetMatchCallback + (selector, &crlSelectorMatch, plContext), + PKIX_CRLSELECTORGETMATCHCALLBACKFAILED); + + PKIX_CHECK(PKIX_List_GetLength(crlList, &numCrls, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (crlSelectorMatch) { + + PKIX_CHECK(PKIX_List_Create(&selectCrlList, plContext), + PKIX_LISTCREATEFAILED); + + for (i = 0; i < numCrls; i++) { + PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem + (crlList, + i, + (PKIX_PL_Object **) &crlItem, + plContext), + PKIX_LISTGETITEMFAILED); + + if (!PKIX_ERROR_RECEIVED){ + PKIX_CHECK_ONLY_FATAL + (crlSelectorMatch + (selector, crlItem, &match, plContext), + PKIX_CRLSELECTORMATCHFAILED); + + if (!(PKIX_ERROR_RECEIVED) && match) { + PKIX_CHECK_ONLY_FATAL + (PKIX_List_AppendItem + (selectCrlList, + (PKIX_PL_Object *)crlItem, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + } + + PKIX_DECREF(crlItem); + } + } else { + + PKIX_INCREF(crlList); + + selectCrlList = crlList; + } + + /* Don't throw away the list if one CRL was bad! */ + pkixTempErrorReceived = PKIX_FALSE; + + *pSelectedCrlList = selectCrlList; + +cleanup: + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStore_GetCert + * DESCRIPTION: + * + * Retrieve Certs in a list of PKIX_PL_Cert object. + * + * PARAMETERS: + * "colCertStoreContext" + * The object CertStore is the object passed in by checker call. + * "crlSelector" + * CRLSelector specifies criteria for chosing CRL's + * "pNBIOContext" + * Address where platform-dependent information is returned for CertStores + * that use non-blocking I/O. Must be non-NULL. + * "pCertList" + * Address where object pointer will be returned. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_CollectionCertStore_GetCert( + PKIX_CertStore *certStore, + PKIX_CertSelector *selector, + PKIX_VerifyNode *verifyNode, + void **pNBIOContext, + PKIX_List **pCerts, + void *plContext) +{ + PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL; + PKIX_List *selectedCerts = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_GetCert"); + PKIX_NULLCHECK_FOUR(certStore, selector, pNBIOContext, pCerts); + + *pNBIOContext = NULL; /* We don't use non-blocking I/O */ + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (certStore, + (PKIX_PL_Object **) &colCertStoreContext, + plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + if (colCertStoreContext->certList == NULL) { + + PKIX_OBJECT_LOCK(colCertStoreContext); + + /* + * Certs in the directory are cached based on the + * assumption that the directory contents won't be + * changed dynamically. + */ + if (colCertStoreContext->certList == NULL){ + PKIX_CHECK(pkix_pl_CollectionCertStoreContext_PopulateCert + (colCertStoreContext, plContext), + PKIX_COLLECTIONCERTSTORECONTEXTPOPULATECERTFAILED); + } + + PKIX_OBJECT_UNLOCK(colCertStoreContext); + } + + PKIX_CHECK(pkix_pl_CollectionCertStoreContext_GetSelectedCert + (colCertStoreContext->certList, + selector, + &selectedCerts, + plContext), + PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCERTFAILED); + + *pCerts = selectedCerts; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_DECREF(colCertStoreContext); + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStore_GetCRL + * DESCRIPTION: + * + * Retrieve CRL's in a list of PKIX_PL_CRL object. + * + * PARAMETERS: + * "colCertStoreContext" + * The object CertStore is passed in by checker call. + * "crlSelector" + * CRLSelector specifies criteria for chosing CRL's + * "pNBIOContext" + * Address where platform-dependent information is returned for CertStores + * that use non-blocking I/O. Must be non-NULL. + * "pCrlList" + * Address where object pointer will be returned. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_CollectionCertStore_GetCRL( + PKIX_CertStore *certStore, + PKIX_CRLSelector *selector, + void **pNBIOContext, + PKIX_List **pCrlList, + void *plContext) +{ + PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL; + PKIX_List *selectCrl = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_GetCRL"); + PKIX_NULLCHECK_FOUR(certStore, selector, pNBIOContext, pCrlList); + + *pNBIOContext = NULL; /* We don't use non-blocking I/O */ + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (certStore, + (PKIX_PL_Object **) &colCertStoreContext, + plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + if (colCertStoreContext->crlList == NULL) { + + PKIX_OBJECT_LOCK(colCertStoreContext); + + /* + * CRLs in the directory are cached based on the + * assumption that the directory contents won't be + * changed dynamically. + */ + if (colCertStoreContext->crlList == NULL){ + PKIX_CHECK(pkix_pl_CollectionCertStoreContext_PopulateCRL + (colCertStoreContext, plContext), + PKIX_COLLECTIONCERTSTORECONTEXTPOPULATECRLFAILED); + } + + PKIX_OBJECT_UNLOCK(colCertStoreContext); + + } + + PKIX_CHECK(pkix_pl_CollectionCertStoreContext_GetSelectedCRL + (colCertStoreContext->crlList, + selector, + &selectCrl, + plContext), + PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCRLFAILED); + + *pCrlList = selectCrl; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_DECREF(colCertStoreContext); + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_CollectionCertStoreContext_RegisterSelf + * DESCRIPTION: + * + * Registers PKIX_PL_COLLECTIONCERTSTORECONTEXT_TYPE and its related + * functions with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_CollectionCertStoreContext_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(COLLECTIONCERTSTORECONTEXT, + "pkix_pl_CollectionCertStoreContext_RegisterSelf"); + + entry.description = "CollectionCertStoreContext"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CollectionCertStoreContext); + entry.destructor = pkix_pl_CollectionCertStoreContext_Destroy; + entry.equalsFunction = pkix_pl_CollectionCertStoreContext_Equals; + entry.hashcodeFunction = pkix_pl_CollectionCertStoreContext_Hashcode; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_COLLECTIONCERTSTORECONTEXT_TYPE] = entry; + + PKIX_RETURN(COLLECTIONCERTSTORECONTEXT); +} + +/* --Public-CollectionCertStoreContext-Functions--------------------------- */ + +/* + * FUNCTION: PKIX_PL_CollectionCertStore_Create + * (see comments in pkix_samples_modules.h) + */ +PKIX_Error * +PKIX_PL_CollectionCertStore_Create( + PKIX_PL_String *storeDir, + PKIX_CertStore **pCertStore, + void *plContext) +{ + PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL; + PKIX_CertStore *certStore = NULL; + + PKIX_ENTER(CERTSTORE, "PKIX_PL_CollectionCertStore_Create"); + PKIX_NULLCHECK_TWO(storeDir, pCertStore); + + PKIX_CHECK(pkix_pl_CollectionCertStoreContext_Create + (storeDir, &colCertStoreContext, plContext), + PKIX_COULDNOTCREATECOLLECTIONCERTSTORECONTEXTOBJECT); + + PKIX_CHECK(PKIX_CertStore_Create + (pkix_pl_CollectionCertStore_GetCert, + pkix_pl_CollectionCertStore_GetCRL, + NULL, /* GetCertContinue */ + NULL, /* GetCRLContinue */ + pkix_pl_CollectionCertStore_CheckTrust, + NULL, /* can not store crls */ + NULL, /* can not do revocation check */ + (PKIX_PL_Object *)colCertStoreContext, + PKIX_TRUE, /* cache flag */ + PKIX_TRUE, /* local - no network I/O */ + &certStore, + plContext), + PKIX_CERTSTORECREATEFAILED); + + PKIX_DECREF(colCertStoreContext); + + *pCertStore = certStore; + +cleanup: + PKIX_RETURN(CERTSTORE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h new file mode 100644 index 0000000000..f41e6fa5e8 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_colcertstore.h + * + * CollectionCertstore Object Type Definition + * + */ + +#ifndef _PKIX_PL_COLCERTSTORE_H +#define _PKIX_PL_COLCERTSTORE_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_CollectionCertStoreContext { + PKIX_PL_String *storeDir; + PKIX_List *crlList; + PKIX_List *certList; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_CollectionCertStoreContext_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_COLCERTSTORE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c new file mode 100644 index 0000000000..471f92004a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c @@ -0,0 +1,1147 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_httpcertstore.c + * + * HTTPCertStore Function Definitions + * + */ + +/* We can't decode the length of a message without at least this many bytes */ + +#include "pkix_pl_httpcertstore.h" +extern PKIX_PL_HashTable *httpSocketCache; +SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate) +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) +SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate) +SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate) + +SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate) +SEC_ASN1_CHOOSER_DECLARE(SECOID_AlgorithmIDTemplate) +/* SEC_ASN1_CHOOSER_DECLARE(SEC_SetOfAnyTemplate) +SEC_ASN1_CHOOSER_DECLARE(CERT_SetOfSignedCrlTemplate) + +const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTIssuerAndSN) }, + { SEC_ASN1_SAVE, + offsetof(CERTIssuerAndSN,derIssuer) }, + { SEC_ASN1_INLINE, + offsetof(CERTIssuerAndSN,issuer), + CERT_NameTemplate }, + { SEC_ASN1_INTEGER, + offsetof(CERTIssuerAndSN,serialNumber) }, + { 0 } +}; + +const SEC_ASN1Template SECOID_AlgorithmIDTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(SECAlgorithmID) }, + { SEC_ASN1_OBJECT_ID, + offsetof(SECAlgorithmID,algorithm) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, + offsetof(SECAlgorithmID,parameters) }, + { 0 } +}; */ + +/* --Private-HttpCertStoreContext-Object Functions----------------------- */ + +/* + * FUNCTION: pkix_pl_HttpCertStoreContext_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_HttpCertStoreContext_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + const SEC_HttpClientFcnV1 *hcv1 = NULL; + PKIX_PL_HttpCertStoreContext *context = NULL; + + PKIX_ENTER + (HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStoreContext_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_HTTPCERTSTORECONTEXT_TYPE, plContext), + PKIX_OBJECTNOTANHTTPCERTSTORECONTEXT); + + context = (PKIX_PL_HttpCertStoreContext *)object; + hcv1 = (const SEC_HttpClientFcnV1 *)(context->client); + if (context->requestSession != NULL) { + (*hcv1->freeFcn)(context->requestSession); + context->requestSession = NULL; + } + if (context->serverSession != NULL) { + (*hcv1->freeSessionFcn)(context->serverSession); + context->serverSession = NULL; + } + if (context->path != NULL) { + PORT_Free(context->path); + context->path = NULL; + } + +cleanup: + + PKIX_RETURN(HTTPCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_HttpCertStoreContext_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_PL_HTTPCERTSTORECONTEXT_TYPE and its related + * functions with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_HttpCertStoreContext_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_HTTPCERTSTORECONTEXT_TYPE]; + + PKIX_ENTER(HTTPCERTSTORECONTEXT, + "pkix_pl_HttpCertStoreContext_RegisterSelf"); + + entry->description = "HttpCertStoreContext"; + entry->typeObjectSize = sizeof(PKIX_PL_HttpCertStoreContext); + entry->destructor = pkix_pl_HttpCertStoreContext_Destroy; + + PKIX_RETURN(HTTPCERTSTORECONTEXT); +} + + +/* --Private-Http-CertStore-Database-Functions----------------------- */ + +typedef struct callbackContextStruct { + PKIX_List *pkixCertList; + PKIX_Error *error; + void *plContext; +} callbackContext; + + +/* + * FUNCTION: certCallback + * DESCRIPTION: + * + * This function processes the null-terminated array of SECItems produced by + * extracting the contents of a signedData message received in response to an + * HTTP cert query. Its address is supplied as a callback function to + * CERT_DecodeCertPackage; it is not expected to be called directly. + * + * Note that it does not conform to the libpkix API standard of returning + * a PKIX_Error*. It returns a SECStatus. + * + * PARAMETERS: + * "arg" + * The address of the callbackContext provided as a void* argument to + * CERT_DecodeCertPackage. Must be non-NULL. + * "secitemCerts" + * The address of the null-terminated array of SECItems. Must be non-NULL. + * "numcerts" + * The number of SECItems found in the signedData. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns SECSuccess if the function succeeds. + * Returns SECFailure if the function fails. + */ +static SECStatus +certCallback(void *arg, SECItem **secitemCerts, int numcerts) +{ + callbackContext *cbContext; + PKIX_List *pkixCertList = NULL; + PKIX_Error *error = NULL; + void *plContext = NULL; + int itemNum = 0; + + if ((arg == NULL) || (secitemCerts == NULL)) { + return (SECFailure); + } + + cbContext = (callbackContext *)arg; + plContext = cbContext->plContext; + pkixCertList = cbContext->pkixCertList; + + for (; itemNum < numcerts; itemNum++ ) { + error = pkix_pl_Cert_CreateToList(secitemCerts[itemNum], + pkixCertList, plContext); + if (error != NULL) { + if (error->errClass == PKIX_FATAL_ERROR) { + cbContext->error = error; + return SECFailure; + } + /* reuse "error" since we could not destruct the old * + * value */ + error = PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, + plContext); + if (error) { + /* Treat decref failure as a fatal error. + * In this case will leak error, but can not do + * anything about it. */ + error->errClass = PKIX_FATAL_ERROR; + cbContext->error = error; + return SECFailure; + } + } + } + + return SECSuccess; +} + + +typedef SECStatus (*pkix_DecodeCertsFunc)(char *certbuf, int certlen, + CERTImportCertificateFunc f, void *arg); + + +struct pkix_DecodeFuncStr { + pkix_DecodeCertsFunc func; /* function pointer to the + * CERT_DecodeCertPackage function */ + PRLibrary *smimeLib; /* Pointer to the smime shared lib*/ + PRCallOnceType once; +}; + +static struct pkix_DecodeFuncStr pkix_decodeFunc; +static const PRCallOnceType pkix_pristine; + +#define SMIME_LIB_NAME SHLIB_PREFIX"smime3."SHLIB_SUFFIX + +/* + * load the smime library and look up the SEC_ReadPKCS7Certs function. + * we do this so we don't have a circular depenency on the smime library, + * and also so we don't have to load the smime library in applications that + * don't use it. + */ +static PRStatus PR_CALLBACK pkix_getDecodeFunction(void) +{ + pkix_decodeFunc.smimeLib = + PR_LoadLibrary(SHLIB_PREFIX"smime3."SHLIB_SUFFIX); + if (pkix_decodeFunc.smimeLib == NULL) { + return PR_FAILURE; + } + + pkix_decodeFunc.func = (pkix_DecodeCertsFunc) PR_FindFunctionSymbol( + pkix_decodeFunc.smimeLib, "CERT_DecodeCertPackage"); + if (!pkix_decodeFunc.func) { + return PR_FAILURE; + } + return PR_SUCCESS; + +} + +/* + * clears our global state on shutdown. + */ +void +pkix_pl_HttpCertStore_Shutdown(void *plContext) +{ + if (pkix_decodeFunc.smimeLib) { + PR_UnloadLibrary(pkix_decodeFunc.smimeLib); + pkix_decodeFunc.smimeLib = NULL; + } + /* the function pointer just need to be cleared, not freed */ + pkix_decodeFunc.func = NULL; + pkix_decodeFunc.once = pkix_pristine; +} + +/* + * This function is based on CERT_DecodeCertPackage from lib/pkcs7/certread.c + * read an old style ascii or binary certificate chain + */ +PKIX_Error * +pkix_pl_HttpCertStore_DecodeCertPackage + (const char *certbuf, + int certlen, + CERTImportCertificateFunc f, + void *arg, + void *plContext) +{ + + PRStatus status; + SECStatus rv; + + PKIX_ENTER + (HTTPCERTSTORECONTEXT, + "pkix_pl_HttpCertStore_DecodeCertPackage"); + PKIX_NULLCHECK_TWO(certbuf, f); + + status = PR_CallOnce(&pkix_decodeFunc.once, pkix_getDecodeFunction); + + if (status != PR_SUCCESS) { + PKIX_ERROR(PKIX_CANTLOADLIBSMIME); + } + + /* paranoia, shouldn't happen if status == PR_SUCCESS); */ + if (!pkix_decodeFunc.func) { + PKIX_ERROR(PKIX_CANTLOADLIBSMIME); + } + + rv = (*pkix_decodeFunc.func)((char*)certbuf, certlen, f, arg); + + if (rv != SECSuccess) { + PKIX_ERROR (PKIX_SECREADPKCS7CERTSFAILED); + } + + +cleanup: + + PKIX_RETURN(HTTPCERTSTORECONTEXT); +} + + +/* + * FUNCTION: pkix_pl_HttpCertStore_ProcessCertResponse + * DESCRIPTION: + * + * This function verifies that the response code pointed to by "responseCode" + * and the content type pointed to by "responseContentType" are as expected, + * and then decodes the data pointed to by "responseData", of length + * "responseDataLen", into a List of Certs, possibly empty, which is returned + * at "pCertList". + * + * PARAMETERS: + * "responseCode" + * The value of the HTTP response code. + * "responseContentType" + * The address of the Content-type string. Must be non-NULL. + * "responseData" + * The address of the message data. Must be non-NULL. + * "responseDataLen" + * The length of the message data. + * "pCertList" + * The address of the List that is created. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpCertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_HttpCertStore_ProcessCertResponse( + PRUint16 responseCode, + const char *responseContentType, + const char *responseData, + PRUint32 responseDataLen, + PKIX_List **pCertList, + void *plContext) +{ + callbackContext cbContext; + + PKIX_ENTER(HTTPCERTSTORECONTEXT, + "pkix_pl_HttpCertStore_ProcessCertResponse"); + + cbContext.error = NULL; + cbContext.plContext = plContext; + cbContext.pkixCertList = NULL; + + PKIX_NULLCHECK_ONE(pCertList); + + if (responseCode != 200) { + PKIX_ERROR(PKIX_BADHTTPRESPONSE); + } + + /* check that response type is application/pkcs7-mime */ + if (responseContentType == NULL) { + PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE); + } + + if (responseData == NULL) { + PKIX_ERROR(PKIX_NORESPONSEDATAINHTTPRESPONSE); + } + + PKIX_CHECK( + PKIX_List_Create(&cbContext.pkixCertList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK_ONLY_FATAL( + pkix_pl_HttpCertStore_DecodeCertPackage(responseData, + responseDataLen, + certCallback, + &cbContext, + plContext), + PKIX_HTTPCERTSTOREDECODECERTPACKAGEFAILED); + if (cbContext.error) { + /* Aborting on a fatal error(See certCallback fn) */ + pkixErrorResult = cbContext.error; + goto cleanup; + } + + *pCertList = cbContext.pkixCertList; + cbContext.pkixCertList = NULL; + +cleanup: + + PKIX_DECREF(cbContext.pkixCertList); + + PKIX_RETURN(HTTPCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_HttpCertStore_ProcessCrlResponse + * DESCRIPTION: + * + * This function verifies that the response code pointed to by "responseCode" + * and the content type pointed to by "responseContentType" are as expected, + * and then decodes the data pointed to by "responseData", of length + * "responseDataLen", into a List of Crls, possibly empty, which is returned + * at "pCrlList". + * + * PARAMETERS: + * "responseCode" + * The value of the HTTP response code. + * "responseContentType" + * The address of the Content-type string. Must be non-NULL. + * "responseData" + * The address of the message data. Must be non-NULL. + * "responseDataLen" + * The length of the message data. + * "pCrlList" + * The address of the List that is created. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpCertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_HttpCertStore_ProcessCrlResponse( + PRUint16 responseCode, + const char *responseContentType, + const char *responseData, + PRUint32 responseDataLen, + PKIX_List **pCrlList, + void *plContext) +{ + SECItem encodedResponse; + PRInt16 compareVal = 0; + PKIX_List *crls = NULL; + SECItem *derCrlCopy = NULL; + CERTSignedCrl *nssCrl = NULL; + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(HTTPCERTSTORECONTEXT, + "pkix_pl_HttpCertStore_ProcessCrlResponse"); + PKIX_NULLCHECK_ONE(pCrlList); + + if (responseCode != 200) { + PKIX_ERROR(PKIX_BADHTTPRESPONSE); + } + + /* check that response type is application/pkix-crl */ + if (responseContentType == NULL) { + PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE); + } + + compareVal = PORT_Strcasecmp(responseContentType, + "application/pkix-crl"); + if (compareVal != 0) { + PKIX_ERROR(PKIX_CONTENTTYPENOTPKIXCRL); + } + encodedResponse.type = siBuffer; + encodedResponse.data = (void*)responseData; + encodedResponse.len = responseDataLen; + + derCrlCopy = SECITEM_DupItem(&encodedResponse); + if (!derCrlCopy) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + /* crl will be based on derCrlCopy, but will not own the der. */ + nssCrl = + CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE, + CRL_DECODE_DONT_COPY_DER | + CRL_DECODE_SKIP_ENTRIES); + if (!nssCrl) { + PKIX_ERROR(PKIX_FAILEDTODECODECRL); + } + /* pkix crls own the der. */ + PKIX_CHECK( + pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy, NULL, + &crl, plContext), + PKIX_CRLCREATEWITHSIGNEDCRLFAILED); + /* Left control over memory pointed by derCrlCopy and + * nssCrl to pkix crl. */ + derCrlCopy = NULL; + nssCrl = NULL; + PKIX_CHECK(PKIX_List_Create(&crls, plContext), + PKIX_LISTCREATEFAILED); + PKIX_CHECK(PKIX_List_AppendItem + (crls, (PKIX_PL_Object *) crl, plContext), + PKIX_LISTAPPENDITEMFAILED); + *pCrlList = crls; + crls = NULL; +cleanup: + if (derCrlCopy) { + SECITEM_FreeItem(derCrlCopy, PR_TRUE); + } + if (nssCrl) { + SEC_DestroyCrl(nssCrl); + } + PKIX_DECREF(crl); + PKIX_DECREF(crls); + + PKIX_RETURN(HTTPCERTSTORECONTEXT); +} + +/* + * FUNCTION: pkix_pl_HttpCertStore_CreateRequestSession + * DESCRIPTION: + * + * This function takes elements from the HttpCertStoreContext pointed to by + * "context" (path, client, and serverSession) and creates a RequestSession. + * See the HTTPClient API described in ocspt.h for further details. + * + * PARAMETERS: + * "context" + * The address of the HttpCertStoreContext. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpCertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_HttpCertStore_CreateRequestSession( + PKIX_PL_HttpCertStoreContext *context, + void *plContext) +{ + const SEC_HttpClientFcnV1 *hcv1 = NULL; + SECStatus rv = SECFailure; + + PKIX_ENTER + (HTTPCERTSTORECONTEXT, + "pkix_pl_HttpCertStore_CreateRequestSession"); + PKIX_NULLCHECK_TWO(context, context->serverSession); + + if (context->client->version != 1) { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + + hcv1 = &(context->client->fcnTable.ftable1); + if (context->requestSession != NULL) { + (*hcv1->freeFcn)(context->requestSession); + context->requestSession = 0; + } + + rv = (*hcv1->createFcn)(context->serverSession, "http", + context->path, "GET", + PR_SecondsToInterval( + ((PKIX_PL_NssContext*)plContext)->timeoutSeconds), + &(context->requestSession)); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } +cleanup: + + PKIX_RETURN(HTTPCERTSTORECONTEXT); + +} + +/* + * FUNCTION: pkix_pl_HttpCertStore_GetCert + * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h) + */ +PKIX_Error * +pkix_pl_HttpCertStore_GetCert( + PKIX_CertStore *store, + PKIX_CertSelector *selector, + PKIX_VerifyNode *verifyNode, + void **pNBIOContext, + PKIX_List **pCertList, + void *plContext) +{ + const SEC_HttpClientFcnV1 *hcv1 = NULL; + PKIX_PL_HttpCertStoreContext *context = NULL; + void *nbioContext = NULL; + SECStatus rv = SECFailure; + PRUint16 responseCode = 0; + const char *responseContentType = NULL; + const char *responseData = NULL; + PRUint32 responseDataLen = 0; + PKIX_List *certList = NULL; + + PKIX_ENTER(HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStore_GetCert"); + PKIX_NULLCHECK_THREE(store, selector, pCertList); + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (store, (PKIX_PL_Object **)&context, plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + if (context->client->version != 1) { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + + hcv1 = &(context->client->fcnTable.ftable1); + + PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession + (context, plContext), + PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED); + + responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, + (PRPollDesc **)&nbioContext, + &responseCode, + (const char **)&responseContentType, + NULL, /* &responseHeaders */ + (const char **)&responseData, + &responseDataLen); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + if (nbioContext != 0) { + *pNBIOContext = nbioContext; + goto cleanup; + } + + PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse + (responseCode, + responseContentType, + responseData, + responseDataLen, + &certList, + plContext), + PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); + + *pCertList = certList; + +cleanup: + PKIX_DECREF(context); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_HttpCertStore_GetCertContinue + * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h) + */ +PKIX_Error * +pkix_pl_HttpCertStore_GetCertContinue( + PKIX_CertStore *store, + PKIX_CertSelector *selector, + PKIX_VerifyNode *verifyNode, + void **pNBIOContext, + PKIX_List **pCertList, + void *plContext) +{ + const SEC_HttpClientFcnV1 *hcv1 = NULL; + PKIX_PL_HttpCertStoreContext *context = NULL; + void *nbioContext = NULL; + SECStatus rv = SECFailure; + PRUint16 responseCode = 0; + const char *responseContentType = NULL; + const char *responseData = NULL; + PRUint32 responseDataLen = 0; + PKIX_List *certList = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCertContinue"); + PKIX_NULLCHECK_THREE(store, selector, pCertList); + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (store, (PKIX_PL_Object **)&context, plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + if (context->client->version != 1) { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + + hcv1 = &(context->client->fcnTable.ftable1); + PKIX_NULLCHECK_ONE(context->requestSession); + + responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, + (PRPollDesc **)&nbioContext, + &responseCode, + (const char **)&responseContentType, + NULL, /* &responseHeaders */ + (const char **)&responseData, + &responseDataLen); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + if (nbioContext != 0) { + *pNBIOContext = nbioContext; + goto cleanup; + } + + PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse + (responseCode, + responseContentType, + responseData, + responseDataLen, + &certList, + plContext), + PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); + + *pCertList = certList; + +cleanup: + PKIX_DECREF(context); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_HttpCertStore_GetCRL + * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) + */ +PKIX_Error * +pkix_pl_HttpCertStore_GetCRL( + PKIX_CertStore *store, + PKIX_CRLSelector *selector, + void **pNBIOContext, + PKIX_List **pCrlList, + void *plContext) +{ + + const SEC_HttpClientFcnV1 *hcv1 = NULL; + PKIX_PL_HttpCertStoreContext *context = NULL; + void *nbioContext = NULL; + SECStatus rv = SECFailure; + PRUint16 responseCode = 0; + const char *responseContentType = NULL; + const char *responseData = NULL; + PRUint32 responseDataLen = 0; + PKIX_List *crlList = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRL"); + PKIX_NULLCHECK_THREE(store, selector, pCrlList); + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (store, (PKIX_PL_Object **)&context, plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + if (context->client->version != 1) { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + + hcv1 = &(context->client->fcnTable.ftable1); + PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession + (context, plContext), + PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED); + + responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, + (PRPollDesc **)&nbioContext, + &responseCode, + (const char **)&responseContentType, + NULL, /* &responseHeaders */ + (const char **)&responseData, + &responseDataLen); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + if (nbioContext != 0) { + *pNBIOContext = nbioContext; + goto cleanup; + } + + PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse + (responseCode, + responseContentType, + responseData, + responseDataLen, + &crlList, + plContext), + PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED); + + *pCrlList = crlList; + +cleanup: + PKIX_DECREF(context); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_HttpCertStore_GetCRLContinue + * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) + */ +PKIX_Error * +pkix_pl_HttpCertStore_GetCRLContinue( + PKIX_CertStore *store, + PKIX_CRLSelector *selector, + void **pNBIOContext, + PKIX_List **pCrlList, + void *plContext) +{ + const SEC_HttpClientFcnV1 *hcv1 = NULL; + PKIX_PL_HttpCertStoreContext *context = NULL; + void *nbioContext = NULL; + SECStatus rv = SECFailure; + PRUint16 responseCode = 0; + const char *responseContentType = NULL; + const char *responseData = NULL; + PRUint32 responseDataLen = 0; + PKIX_List *crlList = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRLContinue"); + PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList); + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (store, (PKIX_PL_Object **)&context, plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + if (context->client->version != 1) { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + hcv1 = &(context->client->fcnTable.ftable1); + + PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession + (context, plContext), + PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED); + + responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession, + (PRPollDesc **)&nbioContext, + &responseCode, + (const char **)&responseContentType, + NULL, /* &responseHeaders */ + (const char **)&responseData, + &responseDataLen); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPSERVERERROR); + } + + if (nbioContext != 0) { + *pNBIOContext = nbioContext; + goto cleanup; + } + + PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse + (responseCode, + responseContentType, + responseData, + responseDataLen, + &crlList, + plContext), + PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED); + + *pCrlList = crlList; + +cleanup: + PKIX_DECREF(context); + + PKIX_RETURN(CERTSTORE); +} + +/* --Public-HttpCertStore-Functions----------------------------------- */ + +/* + * FUNCTION: pkix_pl_HttpCertStore_CreateWithAsciiName + * DESCRIPTION: + * + * This function uses the HttpClient pointed to by "client" and the string + * (hostname:portnum/path, with portnum optional) pointed to by "locationAscii" + * to create an HttpCertStore connected to the desired location, storing the + * created CertStore at "pCertStore". + * + * PARAMETERS: + * "client" + * The address of the HttpClient. Must be non-NULL. + * "locationAscii" + * The address of the character string indicating the hostname, port, and + * path to be queried for Certs or Crls. Must be non-NULL. + * "pCertStore" + * The address in which the object is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpCertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_HttpCertStore_CreateWithAsciiName( + PKIX_PL_HttpClient *client, + char *locationAscii, + PKIX_CertStore **pCertStore, + void *plContext) +{ + const SEC_HttpClientFcn *clientFcn = NULL; + const SEC_HttpClientFcnV1 *hcv1 = NULL; + PKIX_PL_HttpCertStoreContext *httpCertStore = NULL; + PKIX_CertStore *certStore = NULL; + char *hostname = NULL; + char *path = NULL; + PRUint16 port = 0; + SECStatus rv = SECFailure; + + PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_CreateWithAsciiName"); + PKIX_NULLCHECK_TWO(locationAscii, pCertStore); + + if (client == NULL) { + clientFcn = SEC_GetRegisteredHttpClient(); + if (clientFcn == NULL) { + PKIX_ERROR(PKIX_NOREGISTEREDHTTPCLIENT); + } + } else { + clientFcn = (const SEC_HttpClientFcn *)client; + } + + if (clientFcn->version != 1) { + PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); + } + + /* create a PKIX_PL_HttpCertStore object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_HTTPCERTSTORECONTEXT_TYPE, + sizeof (PKIX_PL_HttpCertStoreContext), + (PKIX_PL_Object **)&httpCertStore, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* Initialize fields */ + httpCertStore->client = clientFcn; /* not a PKIX object! */ + + /* parse location -> hostname, port, path */ + rv = CERT_ParseURL(locationAscii, &hostname, &port, &path); + if (rv == SECFailure || hostname == NULL || path == NULL) { + PKIX_ERROR(PKIX_URLPARSINGFAILED); + } + + httpCertStore->path = path; + path = NULL; + + hcv1 = &(clientFcn->fcnTable.ftable1); + rv = (*hcv1->createSessionFcn)(hostname, port, + &(httpCertStore->serverSession)); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED); + } + + httpCertStore->requestSession = NULL; + + PKIX_CHECK(PKIX_CertStore_Create + (pkix_pl_HttpCertStore_GetCert, + pkix_pl_HttpCertStore_GetCRL, + pkix_pl_HttpCertStore_GetCertContinue, + pkix_pl_HttpCertStore_GetCRLContinue, + NULL, /* don't support trust */ + NULL, /* can not store crls */ + NULL, /* can not do revocation check */ + (PKIX_PL_Object *)httpCertStore, + PKIX_TRUE, /* cache flag */ + PKIX_FALSE, /* not local */ + &certStore, + plContext), + PKIX_CERTSTORECREATEFAILED); + + *pCertStore = certStore; + certStore = NULL; + +cleanup: + PKIX_DECREF(httpCertStore); + if (hostname) { + PORT_Free(hostname); + } + if (path) { + PORT_Free(path); + } + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: PKIX_PL_HttpCertStore_Create + * (see comments in pkix_samples_modules.h) + */ +PKIX_Error * +PKIX_PL_HttpCertStore_Create( + PKIX_PL_HttpClient *client, + PKIX_PL_GeneralName *location, + PKIX_CertStore **pCertStore, + void *plContext) +{ + PKIX_PL_String *locationString = NULL; + char *locationAscii = NULL; + PKIX_UInt32 len = 0; + + PKIX_ENTER(CERTSTORE, "PKIX_PL_HttpCertStore_Create"); + PKIX_NULLCHECK_TWO(location, pCertStore); + + PKIX_TOSTRING(location, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (locationString, + PKIX_ESCASCII, + (void **)&locationAscii, + &len, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_CHECK(pkix_pl_HttpCertStore_CreateWithAsciiName + (client, locationAscii, pCertStore, plContext), + PKIX_HTTPCERTSTORECREATEWITHASCIINAMEFAILED); + +cleanup: + + PKIX_DECREF(locationString); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_HttpCertStore_FindSocketConnection + * DESCRIPTION: + * + PRIntervalTime timeout, + char *hostname, + PRUint16 portnum, + PRErrorCode *pStatus, + PKIX_PL_Socket **pSocket, + + * This function checks for an existing socket, creating a new one if unable + * to find an existing one, for the host pointed to by "hostname" and the port + * pointed to by "portnum". If a new socket is created the PRIntervalTime in + * "timeout" will be used for the timeout value and a creation status is + * returned at "pStatus". The address of the socket is stored at "pSocket". + * + * PARAMETERS: + * "timeout" + * The PRIntervalTime of the timeout value. + * "hostname" + * The address of the string containing the hostname. Must be non-NULL. + * "portnum" + * The port number for the desired socket. + * "pStatus" + * The address at which the status is stored. Must be non-NULL. + * "pSocket" + * The address at which the socket is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpCertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_HttpCertStore_FindSocketConnection( + PRIntervalTime timeout, + char *hostname, + PRUint16 portnum, + PRErrorCode *pStatus, + PKIX_PL_Socket **pSocket, + void *plContext) +{ + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *hostString = NULL; + PKIX_PL_String *domainString = NULL; + PKIX_PL_Socket *socket = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_HttpCertStore_FindSocketConnection"); + PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket); + + *pStatus = 0; + + /* create PKIX_PL_String from hostname and port */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "%s:%d", 0, &formatString, plContext), + PKIX_STRINGCREATEFAILED); + +#if 0 +hostname = "variation.red.iplanet.com"; +portnum = 2001; +#endif + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, hostname, 0, &hostString, plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&domainString, plContext, formatString, hostString, portnum), + PKIX_STRINGCREATEFAILED); + +#ifdef PKIX_SOCKETCACHE + /* Is this domainName already in cache? */ + PKIX_CHECK(PKIX_PL_HashTable_Lookup + (httpSocketCache, + (PKIX_PL_Object *)domainString, + (PKIX_PL_Object **)&socket, + plContext), + PKIX_HASHTABLELOOKUPFAILED); +#endif + if (socket == NULL) { + + /* No, create a connection (and cache it) */ + PKIX_CHECK(pkix_pl_Socket_CreateByHostAndPort + (PKIX_FALSE, /* create a client, not a server */ + timeout, + hostname, + portnum, + pStatus, + &socket, + plContext), + PKIX_SOCKETCREATEBYHOSTANDPORTFAILED); + +#ifdef PKIX_SOCKETCACHE + PKIX_CHECK(PKIX_PL_HashTable_Add + (httpSocketCache, + (PKIX_PL_Object *)domainString, + (PKIX_PL_Object *)socket, + plContext), + PKIX_HASHTABLEADDFAILED); +#endif + } + + *pSocket = socket; + socket = NULL; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(hostString); + PKIX_DECREF(domainString); + PKIX_DECREF(socket); + + PKIX_RETURN(CERTSTORE); +} + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h new file mode 100644 index 0000000000..a03ea94d86 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_httpcertstore.h + * + * HTTPCertstore Object Type Definition + * + */ + +#ifndef _PKIX_PL_HTTPCERTSTORE_H +#define _PKIX_PL_HTTPCERTSTORE_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_HttpCertStoreContextStruct { + const SEC_HttpClientFcn *client; + SEC_HTTP_SERVER_SESSION serverSession; + SEC_HTTP_REQUEST_SESSION requestSession; + char *path; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_HttpCertStoreContext_RegisterSelf(void *plContext); + +void pkix_pl_HttpCertStore_Shutdown(void *plContext); + +PKIX_Error * +pkix_pl_HttpCertStore_CreateWithAsciiName( + PKIX_PL_HttpClient *client, + char *locationAscii, + PKIX_CertStore **pCertStore, + void *plContext); + +PKIX_Error * +pkix_HttpCertStore_FindSocketConnection( + PRIntervalTime timeout, + char *hostname, + PRUint16 portnum, + PRErrorCode *pStatus, + PKIX_PL_Socket **pSocket, + void *plContext); + +PKIX_Error * +pkix_pl_HttpCertStore_ProcessCertResponse( + PRUint16 responseCode, + const char *responseContentType, + const char *responseData, + PRUint32 responseDataLen, + PKIX_List **pCertList, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_HTTPCERTSTORE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c new file mode 100644 index 0000000000..f73b95f686 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c @@ -0,0 +1,1654 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_httpdefaultclient.c + * + * HTTPDefaultClient Function Definitions + * + */ + +#include "pkix_pl_httpdefaultclient.h" + +static void *plContext = NULL; + +/* + * The interface specification for an http client requires that it register + * a function table of type SEC_HttpClientFcn, which is defined as a union + * of tables, of which only version 1 is defined at present. + * + * Note: these functions violate the PKIX calling conventions, in that they + * return SECStatus rather than PKIX_Error*, and that they do not provide a + * plContext argument. They are implemented here as calls to PKIX functions, + * but the plContext value is circularly defined - a true kludge. Its value + * is saved at the time of the call to pkix_pl_HttpDefaultClient_Create for + * subsequent use, but since that initial call comes from the + * pkix_pl_HttpDefaultClient_CreateSessionFcn, it's not really getting saved. + */ +static SEC_HttpClientFcnV1 vtable = { + pkix_pl_HttpDefaultClient_CreateSessionFcn, + pkix_pl_HttpDefaultClient_KeepAliveSessionFcn, + pkix_pl_HttpDefaultClient_FreeSessionFcn, + pkix_pl_HttpDefaultClient_RequestCreateFcn, + pkix_pl_HttpDefaultClient_SetPostDataFcn, + pkix_pl_HttpDefaultClient_AddHeaderFcn, + pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn, + pkix_pl_HttpDefaultClient_CancelFcn, + pkix_pl_HttpDefaultClient_FreeFcn +}; + +static SEC_HttpClientFcn httpClient; + +static const char *eohMarker = "\r\n\r\n"; +static const PKIX_UInt32 eohMarkLen = 4; /* strlen(eohMarker) */ +static const char *crlf = "\r\n"; +static const PKIX_UInt32 crlfLen = 2; /* strlen(crlf) */ +static const char *httpprotocol = "HTTP/"; +static const PKIX_UInt32 httpprotocolLen = 5; /* strlen(httpprotocol) */ + + +#define HTTP_UNKNOWN_CONTENT_LENGTH -1 + +/* --Private-HttpDefaultClient-Functions------------------------- */ + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_HdrCheckComplete + * DESCRIPTION: + * + * This function determines whether the headers in the current receive buffer + * in the HttpDefaultClient pointed to by "client" are complete. If so, the + * input data is checked for status code, content-type and content-length are + * extracted, and the client is set up to read the body of the response. + * Otherwise, the client is set up to continue reading header data. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "bytesRead" + * The UInt32 number of bytes received in the latest read. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_HdrCheckComplete( + PKIX_PL_HttpDefaultClient *client, + PKIX_UInt32 bytesRead, + PKIX_Boolean *pKeepGoing, + void *plCtx) +{ + PKIX_UInt32 alreadyScanned = 0; + PKIX_UInt32 comp = 0; + PKIX_UInt32 headerLength = 0; + PKIX_Int32 contentLength = HTTP_UNKNOWN_CONTENT_LENGTH; + char *eoh = NULL; + char *statusLineEnd = NULL; + char *space = NULL; + char *nextHeader = NULL; + const char *httpcode = NULL; + char *thisHeaderEnd = NULL; + char *value = NULL; + char *colon = NULL; + char *copy = NULL; + char *body = NULL; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_HdrCheckComplete"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + *pKeepGoing = PKIX_FALSE; + + /* Does buffer contain end-of-header marker? */ + + /* Copy number of scanned bytes into a variable. */ + alreadyScanned = client->filledupBytes; + /* + * If this is the initial buffer, we have to scan from the beginning. + * If we scanned, failed to find eohMarker, and read some more, we + * only have to scan from where we left off. + */ + if (alreadyScanned > eohMarkLen) { + /* Back up and restart scanning over a few bytes that were + * scanned before */ + PKIX_UInt32 searchStartPos = alreadyScanned - eohMarkLen; + eoh = PL_strnstr(&(client->rcvBuf[searchStartPos]), eohMarker, + bytesRead + searchStartPos); + } else { + /* A search from the beginning of the buffer. */ + eoh = PL_strnstr(client->rcvBuf, eohMarker, bytesRead); + } + + client->filledupBytes += bytesRead; + + if (eoh == NULL) { /* did we see end-of-header? */ + /* No. Continue to read header data */ + client->connectStatus = HTTP_RECV_HDR; + *pKeepGoing = PKIX_TRUE; + goto cleanup; + } + + /* Yes. Calculate how many bytes in header (not counting eohMarker) */ + headerLength = (eoh - client->rcvBuf); + + /* allocate space to copy header (and for the NULL terminator) */ + PKIX_CHECK(PKIX_PL_Malloc(headerLength + 1, (void **)©, plCtx), + PKIX_MALLOCFAILED); + + /* copy header data before we corrupt it (by storing NULLs) */ + PORT_Memcpy(copy, client->rcvBuf, headerLength); + /* Store the NULL terminator */ + copy[headerLength] = '\0'; + client->rcvHeaders = copy; + + /* Did caller want a pointer to header? */ + if (client->rcv_http_headers != NULL) { + /* store pointer for caller */ + *(client->rcv_http_headers) = copy; + } + + /* Check that message status is okay. */ + statusLineEnd = PL_strnstr(client->rcvBuf, crlf, client->capacity); + if (statusLineEnd == NULL) { + client->connectStatus = HTTP_ERROR; + PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); + goto cleanup; + } + + *statusLineEnd = '\0'; + + space = strchr((const char *)client->rcvBuf, ' '); + if (space == NULL) { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + + comp = PORT_Strncasecmp((const char *)client->rcvBuf, httpprotocol, + httpprotocolLen); + if (comp != 0) { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + + httpcode = space + 1; + space = strchr(httpcode, ' '); + if (space == NULL) { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + *space = '\0'; + + client->responseCode = atoi(httpcode); + if (client->responseCode != 200) { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + + /* Find the content-type and content-length */ + nextHeader = statusLineEnd + crlfLen; + *eoh = '\0'; + do { + thisHeaderEnd = NULL; + value = NULL; + + colon = strchr(nextHeader, ':'); + if (colon == NULL) { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + *colon = '\0'; + value = colon + 1; + if (*value != ' ') { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + value++; + thisHeaderEnd = strstr(value, crlf); + if (thisHeaderEnd != NULL) { + *thisHeaderEnd = '\0'; + } + comp = PORT_Strcasecmp(nextHeader, "content-type"); + if (comp == 0) { + client->rcvContentType = PORT_Strdup(value); + } else { + comp = PORT_Strcasecmp(nextHeader, "content-length"); + if (comp == 0) { + contentLength = atoi(value); + } + } + if (thisHeaderEnd != NULL) { + nextHeader = thisHeaderEnd + crlfLen; + } else { + nextHeader = NULL; + } + } while ((nextHeader != NULL) && (nextHeader < (eoh + crlfLen))); + + /* Did caller provide a pointer to return content-type? */ + if (client->rcv_http_content_type != NULL) { + *(client->rcv_http_content_type) = client->rcvContentType; + } + + if (client->rcvContentType == NULL) { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + + /* How many bytes remain in current buffer, beyond the header? */ + headerLength += eohMarkLen; + client->filledupBytes -= headerLength; + + /* + * The headers have passed validation. Now figure out whether the + * message is within the caller's size limit (if one was specified). + */ + switch (contentLength) { + case 0: + client->rcv_http_data_len = 0; + client->connectStatus = HTTP_COMPLETE; + *pKeepGoing = PKIX_FALSE; + break; + + case HTTP_UNKNOWN_CONTENT_LENGTH: + /* Unknown contentLength indicator.Will be set by + * pkix_pl_HttpDefaultClient_RecvBody whey connection get closed */ + client->rcv_http_data_len = HTTP_UNKNOWN_CONTENT_LENGTH; + contentLength = /* Try to reserve 4K+ buffer */ + client->filledupBytes + HTTP_DATA_BUFSIZE; + if (client->maxResponseLen > 0 && + contentLength > (PKIX_Int32)client->maxResponseLen) { + if (client->filledupBytes < client->maxResponseLen) { + contentLength = client->maxResponseLen; + } else { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + } + /* set available number of bytes in the buffer */ + client->capacity = contentLength; + client->connectStatus = HTTP_RECV_BODY; + *pKeepGoing = PKIX_TRUE; + break; + + default: + client->rcv_http_data_len = contentLength; + if (client->maxResponseLen > 0 && + (PKIX_Int32)client->maxResponseLen < contentLength) { + client->connectStatus = HTTP_ERROR; + goto cleanup; + } + + /* + * Do we have all of the message body, or do we need to read some more? + */ + if ((PKIX_Int32)client->filledupBytes < contentLength) { + client->connectStatus = HTTP_RECV_BODY; + *pKeepGoing = PKIX_TRUE; + } else { + client->connectStatus = HTTP_COMPLETE; + *pKeepGoing = PKIX_FALSE; + } + } + + if (contentLength > 0) { + /* allocate a buffer of size contentLength for the content */ + PKIX_CHECK(PKIX_PL_Malloc(contentLength, (void **)&body, plCtx), + PKIX_MALLOCFAILED); + + /* copy any remaining bytes in current buffer into new buffer */ + if (client->filledupBytes > 0) { + PORT_Memcpy(body, &(client->rcvBuf[headerLength]), + client->filledupBytes); + } + } + + PKIX_CHECK(PKIX_PL_Free(client->rcvBuf, plCtx), + PKIX_FREEFAILED); + client->rcvBuf = body; + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: PKIX_PL_HttpDefaultClient_Create + * DESCRIPTION: + * + * This function creates a new HttpDefaultClient, and stores the result at + * "pClient". + * + * The HttpClient API does not include a plContext argument in its + * function calls. Its value at the time of this Create call must be the + * same as when the client is invoked. + * + * PARAMETERS: + * "host" + * The name of the server with which we hope to exchange messages. Must + * be non-NULL. + * "portnum" + * The port number to be used for our connection to the server. + * "pClient" + * The address at which the created HttpDefaultClient is to be stored. + * Must be non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_Create( + const char *host, + PRUint16 portnum, + PKIX_PL_HttpDefaultClient **pClient, + void *plCtx) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "PKIX_PL_HttpDefaultClient_Create"); + PKIX_NULLCHECK_TWO(pClient, host); + + /* allocate an HttpDefaultClient */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_HTTPDEFAULTCLIENT_TYPE, + sizeof (PKIX_PL_HttpDefaultClient), + (PKIX_PL_Object **)&client, + plCtx), + PKIX_COULDNOTCREATEHTTPDEFAULTCLIENTOBJECT); + + /* Client timeout is overwritten in HttpDefaultClient_RequestCreate + * function. Default value will be ignored. */ + client->timeout = 0; + client->connectStatus = HTTP_NOT_CONNECTED; + client->portnum = portnum; + client->bytesToWrite = 0; + client->send_http_data_len = 0; + client->rcv_http_data_len = 0; + client->capacity = 0; + client->filledupBytes = 0; + client->responseCode = 0; + client->maxResponseLen = 0; + client->GETLen = 0; + client->POSTLen = 0; + client->pRcv_http_data_len = NULL; + client->callbackList = NULL; + client->GETBuf = NULL; + client->POSTBuf = NULL; + client->rcvBuf = NULL; + /* "host" is a parsing result by CERT_GetURL function that adds + * "end of line" to the value. OK to dup the string. */ + client->host = PORT_Strdup(host); + if (!client->host) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + client->path = NULL; + client->rcvContentType = NULL; + client->rcvHeaders = NULL; + client->send_http_method = HTTP_POST_METHOD; + client->send_http_content_type = NULL; + client->send_http_data = NULL; + client->rcv_http_response_code = NULL; + client->rcv_http_content_type = NULL; + client->rcv_http_headers = NULL; + client->rcv_http_data = NULL; + client->socket = NULL; + + /* + * The HttpClient API does not include a plCtx argument in its + * function calls. Save it here. + */ + client->plContext = plCtx; + + *pClient = client; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(client); + } + + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_Destroy( + PKIX_PL_Object *object, + void *plCtx) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_HTTPDEFAULTCLIENT_TYPE, plCtx), + PKIX_OBJECTNOTANHTTPDEFAULTCLIENT); + + client = (PKIX_PL_HttpDefaultClient *)object; + + if (client->rcvHeaders) { + PKIX_PL_Free(client->rcvHeaders, plCtx); + client->rcvHeaders = NULL; + } + if (client->rcvContentType) { + PORT_Free(client->rcvContentType); + client->rcvContentType = NULL; + } + if (client->GETBuf != NULL) { + PR_smprintf_free(client->GETBuf); + client->GETBuf = NULL; + } + if (client->POSTBuf != NULL) { + PKIX_PL_Free(client->POSTBuf, plCtx); + client->POSTBuf = NULL; + } + if (client->rcvBuf != NULL) { + PKIX_PL_Free(client->rcvBuf, plCtx); + client->rcvBuf = NULL; + } + if (client->host) { + PORT_Free(client->host); + client->host = NULL; + } + if (client->path) { + PORT_Free(client->path); + client->path = NULL; + } + PKIX_DECREF(client->socket); + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_PL_HTTPDEFAULTCLIENT_TYPE and its related + * functions with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_HttpDefaultClient_RegisterSelf(void *plCtx) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = + &systemClasses[PKIX_HTTPDEFAULTCLIENT_TYPE]; + + PKIX_ENTER(HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_RegisterSelf"); + + entry->description = "HttpDefaultClient"; + entry->typeObjectSize = sizeof(PKIX_PL_HttpDefaultClient); + entry->destructor = pkix_pl_HttpDefaultClient_Destroy; + + httpClient.version = 1; + httpClient.fcnTable.ftable1 = vtable; + (void)SEC_RegisterDefaultHttpClient(&httpClient); + + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* --Private-HttpDefaultClient-I/O-Functions---------------------------- */ +/* + * FUNCTION: pkix_pl_HttpDefaultClient_ConnectContinue + * DESCRIPTION: + * + * This function determines whether a socket Connect initiated earlier for the + * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag + * indicating whether processing can continue without further input. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_ConnectContinue( + PKIX_PL_HttpDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plCtx) +{ + PRErrorCode status; + PKIX_Boolean keepGoing = PKIX_FALSE; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_ConnectContinue"); + PKIX_NULLCHECK_ONE(client); + + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; + + PKIX_CHECK(callbackList->connectcontinueCallback + (client->socket, &status, plCtx), + PKIX_SOCKETCONNECTCONTINUEFAILED); + + if (status == 0) { + client->connectStatus = HTTP_CONNECTED; + keepGoing = PKIX_TRUE; + } else if (status != PR_IN_PROGRESS_ERROR) { + PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION); + } + + *pKeepGoing = keepGoing; + +cleanup: + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_Send + * DESCRIPTION: + * + * This function creates and sends HTTP-protocol headers and, if applicable, + * data, for the HttpDefaultClient "client", and stores in "pKeepGoing" a flag + * indicating whether processing can continue without further input, and at + * "pBytesTransferred" the number of bytes sent. + * + * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use + * and that transmission has not completed. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "pBytesTransferred" + * The address at which the number of bytes sent is stored. Must be + * non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_Send( + PKIX_PL_HttpDefaultClient *client, + PKIX_Boolean *pKeepGoing, + PKIX_UInt32 *pBytesTransferred, + void *plCtx) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_Int32 lenToWrite = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + char *dataToWrite = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Send"); + PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); + + *pKeepGoing = PKIX_FALSE; + + /* Do we have anything waiting to go? */ + if ((client->GETBuf) || (client->POSTBuf)) { + + if (client->GETBuf) { + dataToWrite = client->GETBuf; + lenToWrite = client->GETLen; + } else { + dataToWrite = client->POSTBuf; + lenToWrite = client->POSTLen; + } + + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; + + PKIX_CHECK(callbackList->sendCallback + (client->socket, + dataToWrite, + lenToWrite, + &bytesWritten, + plCtx), + PKIX_SOCKETSENDFAILED); + + client->rcvBuf = NULL; + client->capacity = 0; + client->filledupBytes = 0; + + /* + * If the send completed we can proceed to try for the + * response. If the send did not complete we will have + * to poll for completion later. + */ + if (bytesWritten >= 0) { + client->connectStatus = HTTP_RECV_HDR; + *pKeepGoing = PKIX_TRUE; + } else { + client->connectStatus = HTTP_SEND_PENDING; + *pKeepGoing = PKIX_FALSE; + } + + } + + *pBytesTransferred = bytesWritten; + +cleanup: + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_SendContinue + * DESCRIPTION: + * + * This function determines whether the sending of the HTTP message for the + * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a + * flag indicating whether processing can continue without further input, and + * at "pBytesTransferred" the number of bytes sent. + * + * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use + * and that transmission has not completed. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "pBytesTransferred" + * The address at which the number of bytes sent is stored. Must be + * non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_SendContinue( + PKIX_PL_HttpDefaultClient *client, + PKIX_Boolean *pKeepGoing, + PKIX_UInt32 *pBytesTransferred, + void *plCtx) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_SendContinue"); + PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); + + *pKeepGoing = PKIX_FALSE; + + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; + + PKIX_CHECK(callbackList->pollCallback + (client->socket, &bytesWritten, NULL, plCtx), + PKIX_SOCKETPOLLFAILED); + + /* + * If the send completed we can proceed to try for the + * response. If the send did not complete we will have + * continue to poll. + */ + if (bytesWritten >= 0) { + client->connectStatus = HTTP_RECV_HDR; + *pKeepGoing = PKIX_TRUE; + } + + *pBytesTransferred = bytesWritten; + +cleanup: + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdr + * DESCRIPTION: + * + * This function receives HTTP headers for the HttpDefaultClient "client", and + * stores in "pKeepGoing" a flag indicating whether processing can continue + * without further input. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_RecvHdr( + PKIX_PL_HttpDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plCtx) +{ + PKIX_UInt32 bytesToRead = 0; + PKIX_Int32 bytesRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvHdr"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + /* + * rcvbuf, capacity, and filledupBytes were + * initialized when we wrote the headers. We begin by reading + * HTTP_HEADER_BUFSIZE bytes, repeatedly increasing the buffersize and + * reading again if necessary, until we have read the end-of-header + * marker, "\r\n\r\n", or have reached our maximum. + */ + client->capacity += HTTP_HEADER_BUFSIZE; + PKIX_CHECK(PKIX_PL_Realloc + (client->rcvBuf, + client->capacity, + (void **)&(client->rcvBuf), + plCtx), + PKIX_REALLOCFAILED); + + bytesToRead = client->capacity - client->filledupBytes; + + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; + + PKIX_CHECK(callbackList->recvCallback + (client->socket, + (void *)&(client->rcvBuf[client->filledupBytes]), + bytesToRead, + &bytesRead, + plCtx), + PKIX_SOCKETRECVFAILED); + + if (bytesRead > 0) { + /* client->filledupBytes will be adjusted by + * pkix_pl_HttpDefaultClient_HdrCheckComplete */ + PKIX_CHECK( + pkix_pl_HttpDefaultClient_HdrCheckComplete(client, bytesRead, + pKeepGoing, + plCtx), + PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED); + } else { + client->connectStatus = HTTP_RECV_HDR_PENDING; + *pKeepGoing = PKIX_FALSE; + } + +cleanup: + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdrContinue + * DESCRIPTION: + * + * This function determines whether the receiving of the HTTP headers for the + * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag + * indicating whether processing can continue without further input. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_RecvHdrContinue( + PKIX_PL_HttpDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plCtx) +{ + PKIX_Int32 bytesRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_RecvHdrContinue"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; + + PKIX_CHECK(callbackList->pollCallback + (client->socket, NULL, &bytesRead, plCtx), + PKIX_SOCKETPOLLFAILED); + + if (bytesRead > 0) { + client->filledupBytes += bytesRead; + + PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete + (client, bytesRead, pKeepGoing, plCtx), + PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED); + + } else { + + *pKeepGoing = PKIX_FALSE; + + } + +cleanup: + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_RecvBody + * DESCRIPTION: + * + * This function processes the contents of the first buffer of a received + * HTTP-protocol message for the HttpDefaultClient "client", and stores in + * "pKeepGoing" a flag indicating whether processing can continue without + * further input. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_RecvBody( + PKIX_PL_HttpDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plCtx) +{ + PKIX_Int32 bytesRead = 0; + PKIX_Int32 bytesToRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvBody"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList; + + if (client->rcv_http_data_len != HTTP_UNKNOWN_CONTENT_LENGTH) { + bytesToRead = client->rcv_http_data_len - + client->filledupBytes; + } else { + /* Reading till the EOF. Context length is not known.*/ + /* Check the buffer capacity: increase and + * reallocate if it is low. */ + int freeBuffSize = client->capacity - client->filledupBytes; + if (freeBuffSize < HTTP_MIN_AVAILABLE_BUFFER_SIZE) { + /* New length will be consist of available(downloaded) bytes, + * plus remaining capacity, plus new expansion. */ + int currBuffSize = client->capacity; + /* Try to increase the buffer by 4K */ + unsigned int newLength = currBuffSize + HTTP_DATA_BUFSIZE; + if (client->maxResponseLen > 0 && + newLength > client->maxResponseLen) { + newLength = client->maxResponseLen; + } + /* Check if we can grow the buffer and report an error if + * new size is not larger than the current size of the buffer.*/ + if (newLength <= client->filledupBytes) { + client->rcv_http_data_len = client->filledupBytes; + client->connectStatus = HTTP_ERROR; + *pKeepGoing = PKIX_FALSE; + goto cleanup; + } + if (client->capacity < newLength) { + client->capacity = newLength; + PKIX_CHECK( + PKIX_PL_Realloc(client->rcvBuf, newLength, + (void**)&client->rcvBuf, plCtx), + PKIX_REALLOCFAILED); + freeBuffSize = client->capacity - + client->filledupBytes; + } + } + bytesToRead = freeBuffSize; + } + + /* Use poll callback if waiting on non-blocking IO */ + if (client->connectStatus == HTTP_RECV_BODY_PENDING) { + PKIX_CHECK(callbackList->pollCallback + (client->socket, NULL, &bytesRead, plCtx), + PKIX_SOCKETPOLLFAILED); + } else { + PKIX_CHECK(callbackList->recvCallback + (client->socket, + (void *)&(client->rcvBuf[client->filledupBytes]), + bytesToRead, + &bytesRead, + plCtx), + PKIX_SOCKETRECVFAILED); + } + + /* If bytesRead < 0, an error will be thrown by recvCallback, so + * need to handle >= 0 cases. */ + + /* bytesRead == 0 - IO was blocked. */ + if (bytesRead == 0) { + client->connectStatus = HTTP_RECV_BODY_PENDING; + *pKeepGoing = PKIX_TRUE; + goto cleanup; + } + + /* We got something. Did we get it all? */ + client->filledupBytes += bytesRead; + + /* continue if not enough bytes read or if complete size of + * transfer is unknown */ + if (bytesToRead > bytesRead || + client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) { + *pKeepGoing = PKIX_TRUE; + goto cleanup; + } + client->connectStatus = HTTP_COMPLETE; + *pKeepGoing = PKIX_FALSE; + +cleanup: + if (pkixErrorResult && pkixErrorResult->errCode == + PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED) { + if (client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) { + client->rcv_http_data_len = client->filledupBytes; + client->connectStatus = HTTP_COMPLETE; + *pKeepGoing = PKIX_FALSE; + PKIX_DECREF(pkixErrorResult); + } else { + client->connectStatus = HTTP_ERROR; + } + } + + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_HttpDefaultClient_Dispatch + * DESCRIPTION: + * + * This function is the state machine dispatcher for the HttpDefaultClient + * pointed to by "client". Results are returned by changes to various fields + * in the context. + * + * PARAMETERS: + * "client" + * The address of the HttpDefaultClient object. Must be non-NULL. + * "plCtx" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HttpDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_HttpDefaultClient_Dispatch( + PKIX_PL_HttpDefaultClient *client, + void *plCtx) +{ + PKIX_UInt32 bytesTransferred = 0; + PKIX_Boolean keepGoing = PKIX_TRUE; + + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Dispatch"); + PKIX_NULLCHECK_ONE(client); + + while (keepGoing) { + switch (client->connectStatus) { + case HTTP_CONNECT_PENDING: + PKIX_CHECK(pkix_pl_HttpDefaultClient_ConnectContinue + (client, &keepGoing, plCtx), + PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED); + break; + case HTTP_CONNECTED: + PKIX_CHECK(pkix_pl_HttpDefaultClient_Send + (client, &keepGoing, &bytesTransferred, plCtx), + PKIX_HTTPDEFAULTCLIENTSENDFAILED); + break; + case HTTP_SEND_PENDING: + PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue + (client, &keepGoing, &bytesTransferred, plCtx), + PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED); + break; + case HTTP_RECV_HDR: + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr + (client, &keepGoing, plCtx), + PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED); + break; + case HTTP_RECV_HDR_PENDING: + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue + (client, &keepGoing, plCtx), + PKIX_HTTPDEFAULTCLIENTRECVHDRCONTINUEFAILED); + break; + case HTTP_RECV_BODY: + case HTTP_RECV_BODY_PENDING: + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvBody + (client, &keepGoing, plCtx), + PKIX_HTTPDEFAULTCLIENTRECVBODYFAILED); + break; + case HTTP_ERROR: + case HTTP_COMPLETE: + keepGoing = PKIX_FALSE; + break; + case HTTP_NOT_CONNECTED: + default: + PKIX_ERROR(PKIX_HTTPDEFAULTCLIENTINILLEGALSTATE); + } + } + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); +} + +/* + * --HttpClient vtable functions + * See comments in ocspt.h for the function (wrappers) that return SECStatus. + * The functions that return PKIX_Error* are the libpkix implementations. + */ + +PKIX_Error * +pkix_pl_HttpDefaultClient_CreateSession( + const char *host, + PRUint16 portnum, + SEC_HTTP_SERVER_SESSION *pSession, + void *plCtx) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_CreateSession"); + PKIX_NULLCHECK_TWO(host, pSession); + + PKIX_CHECK(pkix_pl_HttpDefaultClient_Create + (host, portnum, &client, plCtx), + PKIX_HTTPDEFAULTCLIENTCREATEFAILED); + + *pSession = (SEC_HTTP_SERVER_SESSION)client; + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); + +} + +PKIX_Error * +pkix_pl_HttpDefaultClient_KeepAliveSession( + SEC_HTTP_SERVER_SESSION session, + PRPollDesc **pPollDesc, + void *plCtx) +{ + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_KeepAliveSession"); + PKIX_NULLCHECK_TWO(session, pPollDesc); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)session, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plCtx), + PKIX_SESSIONNOTANHTTPDEFAULTCLIENT); + + /* XXX Not implemented */ + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); + +} + +PKIX_Error * +pkix_pl_HttpDefaultClient_RequestCreate( + SEC_HTTP_SERVER_SESSION session, + const char *http_protocol_variant, /* usually "http" */ + const char *path_and_query_string, + const char *http_request_method, + const PRIntervalTime timeout, + SEC_HTTP_REQUEST_SESSION *pRequest, + void *plCtx) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + PKIX_PL_Socket *socket = NULL; + PKIX_PL_Socket_Callback *callbackList = NULL; + PRFileDesc *fileDesc = NULL; + PRErrorCode status = 0; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RequestCreate"); + PKIX_NULLCHECK_TWO(session, pRequest); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)session, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plCtx), + PKIX_SESSIONNOTANHTTPDEFAULTCLIENT); + + client = (PKIX_PL_HttpDefaultClient *)session; + + /* We only know how to do http */ + if (PORT_Strncasecmp(http_protocol_variant, "http", 4) != 0) { + PKIX_ERROR(PKIX_UNRECOGNIZEDPROTOCOLREQUESTED); + } + + if (PORT_Strncasecmp(http_request_method, "POST", 4) == 0) { + client->send_http_method = HTTP_POST_METHOD; + } else if (PORT_Strncasecmp(http_request_method, "GET", 3) == 0) { + client->send_http_method = HTTP_GET_METHOD; + } else { + /* We only know how to do POST and GET */ + PKIX_ERROR(PKIX_UNRECOGNIZEDREQUESTMETHOD); + } + + if (path_and_query_string) { + /* "path_and_query_string" is a parsing result by CERT_GetURL + * function that adds "end of line" to the value. OK to dup + * the string. */ + client->path = PORT_Strdup(path_and_query_string); + if (!client->path) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + } + + client->timeout = timeout; + +#if 0 + PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection + (timeout, + "variation.red.iplanet.com", /* (char *)client->host, */ + 2001, /* client->portnum, */ + &status, + &socket, + plCtx), + PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED); +#else + PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection + (timeout, + (char *)client->host, + client->portnum, + &status, + &socket, + plCtx), + PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED); +#endif + + client->socket = socket; + + PKIX_CHECK(pkix_pl_Socket_GetCallbackList + (socket, &callbackList, plCtx), + PKIX_SOCKETGETCALLBACKLISTFAILED); + + client->callbackList = (void *)callbackList; + + PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc + (socket, &fileDesc, plCtx), + PKIX_SOCKETGETPRFILEDESCFAILED); + + client->pollDesc.fd = fileDesc; + client->pollDesc.in_flags = 0; + client->pollDesc.out_flags = 0; + + client->send_http_data = NULL; + client->send_http_data_len = 0; + client->send_http_content_type = NULL; + + client->connectStatus = + ((status == 0) ? HTTP_CONNECTED : HTTP_CONNECT_PENDING); + + /* Request object is the same object as Session object */ + PKIX_INCREF(client); + *pRequest = client; + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); + +} + +PKIX_Error * +pkix_pl_HttpDefaultClient_SetPostData( + SEC_HTTP_REQUEST_SESSION request, + const char *http_data, + const PRUint32 http_data_len, + const char *http_content_type, + void *plCtx) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_SetPostData"); + PKIX_NULLCHECK_ONE(request); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)request, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plCtx), + PKIX_REQUESTNOTANHTTPDEFAULTCLIENT); + + client = (PKIX_PL_HttpDefaultClient *)request; + + client->send_http_data = http_data; + client->send_http_data_len = http_data_len; + client->send_http_content_type = http_content_type; + + /* Caller is allowed to give NULL or empty string for content_type */ + if ((client->send_http_content_type == NULL) || + (*(client->send_http_content_type) == '\0')) { + client->send_http_content_type = "application/ocsp-request"; + } + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); + +} + +PKIX_Error * +pkix_pl_HttpDefaultClient_TrySendAndReceive( + SEC_HTTP_REQUEST_SESSION request, + PRUint16 *http_response_code, + const char **http_response_content_type, + const char **http_response_headers, + const char **http_response_data, + PRUint32 *http_response_data_len, + PRPollDesc **pPollDesc, + SECStatus *pSECReturn, + void *plCtx) +{ + PKIX_PL_HttpDefaultClient *client = NULL; + PKIX_UInt32 postLen = 0; + PRPollDesc *pollDesc = NULL; + char *sendbuf = NULL; + char portstr[16]; + + PKIX_ENTER + (HTTPDEFAULTCLIENT, + "pkix_pl_HttpDefaultClient_TrySendAndReceive"); + + PKIX_NULLCHECK_ONE(request); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)request, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plCtx), + PKIX_REQUESTNOTANHTTPDEFAULTCLIENT); + + client = (PKIX_PL_HttpDefaultClient *)request; + + if (!pPollDesc && client->timeout == 0) { + PKIX_ERROR_FATAL(PKIX_NULLARGUMENT); + } + + if (pPollDesc) { + pollDesc = *pPollDesc; + } + + /* if not continuing from an earlier WOULDBLOCK return... */ + if (pollDesc == NULL) { + + if (!((client->connectStatus == HTTP_CONNECTED) || + (client->connectStatus == HTTP_CONNECT_PENDING))) { + PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE); + } + + /* Did caller provide a value for response length? */ + if (http_response_data_len != NULL) { + client->pRcv_http_data_len = http_response_data_len; + client->maxResponseLen = *http_response_data_len; + } + + client->rcv_http_response_code = http_response_code; + client->rcv_http_content_type = http_response_content_type; + client->rcv_http_headers = http_response_headers; + client->rcv_http_data = http_response_data; + + /* prepare the message */ + portstr[0] = '\0'; + if (client->portnum != 80) { + PR_snprintf(portstr, sizeof(portstr), ":%d", + client->portnum); + } + + if (client->send_http_method == HTTP_POST_METHOD) { + sendbuf = PR_smprintf + ("POST %s HTTP/1.0\r\nHost: %s%s\r\n" + "Content-Type: %s\r\nContent-Length: %u\r\n\r\n", + client->path, + client->host, + portstr, + client->send_http_content_type, + client->send_http_data_len); + postLen = PORT_Strlen(sendbuf); + + client->POSTLen = postLen + client->send_http_data_len; + + /* allocate postBuffer big enough for header + data */ + PKIX_CHECK(PKIX_PL_Malloc + (client->POSTLen, + (void **)&(client->POSTBuf), + plCtx), + PKIX_MALLOCFAILED); + + /* copy header into postBuffer */ + PORT_Memcpy(client->POSTBuf, sendbuf, postLen); + + /* append data after header */ + PORT_Memcpy(&client->POSTBuf[postLen], + client->send_http_data, + client->send_http_data_len); + + /* PR_smprintf_free original header buffer */ + PR_smprintf_free(sendbuf); + sendbuf = NULL; + + } else if (client->send_http_method == HTTP_GET_METHOD) { + client->GETBuf = PR_smprintf + ("GET %s HTTP/1.0\r\nHost: %s%s\r\n\r\n", + client->path, + client->host, + portstr); + client->GETLen = PORT_Strlen(client->GETBuf); + } + + } + + /* continue according to state */ + PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plCtx), + PKIX_HTTPDEFAULTCLIENTDISPATCHFAILED); + + switch (client->connectStatus) { + case HTTP_CONNECT_PENDING: + case HTTP_SEND_PENDING: + case HTTP_RECV_HDR_PENDING: + case HTTP_RECV_BODY_PENDING: + pollDesc = &(client->pollDesc); + *pSECReturn = SECWouldBlock; + break; + case HTTP_ERROR: + /* Did caller provide a pointer for length? */ + if (client->pRcv_http_data_len != NULL) { + /* Was error "response too big?" */ + if (client->rcv_http_data_len != + HTTP_UNKNOWN_CONTENT_LENGTH && + client->maxResponseLen >= + client->rcv_http_data_len) { + /* Yes, report needed space */ + *(client->pRcv_http_data_len) = + client->rcv_http_data_len; + } else { + /* No, report problem other than size */ + *(client->pRcv_http_data_len) = 0; + } + } + + pollDesc = NULL; + *pSECReturn = SECFailure; + break; + case HTTP_COMPLETE: + *(client->rcv_http_response_code) = + client->responseCode; + if (client->pRcv_http_data_len != NULL) { + *http_response_data_len = + client->rcv_http_data_len; + } + if (client->rcv_http_data != NULL) { + *(client->rcv_http_data) = client->rcvBuf; + } + pollDesc = NULL; + *pSECReturn = SECSuccess; + break; + case HTTP_NOT_CONNECTED: + case HTTP_CONNECTED: + case HTTP_RECV_HDR: + case HTTP_RECV_BODY: + default: + pollDesc = NULL; + *pSECReturn = SECFailure; + PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE); + break; + } + + if (pPollDesc) { + *pPollDesc = pollDesc; + } + +cleanup: + if (sendbuf) { + PR_smprintf_free(sendbuf); + } + + PKIX_RETURN(HTTPDEFAULTCLIENT); + +} + +PKIX_Error * +pkix_pl_HttpDefaultClient_Cancel( + SEC_HTTP_REQUEST_SESSION request, + void *plCtx) +{ + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel"); + PKIX_NULLCHECK_ONE(request); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)request, + PKIX_HTTPDEFAULTCLIENT_TYPE, + plCtx), + PKIX_REQUESTNOTANHTTPDEFAULTCLIENT); + + /* XXX Not implemented */ + +cleanup: + + PKIX_RETURN(HTTPDEFAULTCLIENT); + +} + +SECStatus +pkix_pl_HttpDefaultClient_CreateSessionFcn( + const char *host, + PRUint16 portnum, + SEC_HTTP_SERVER_SESSION *pSession) +{ + PKIX_Error *err = pkix_pl_HttpDefaultClient_CreateSession + (host, portnum, pSession, plContext); + + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +pkix_pl_HttpDefaultClient_KeepAliveSessionFcn( + SEC_HTTP_SERVER_SESSION session, + PRPollDesc **pPollDesc) +{ + PKIX_Error *err = pkix_pl_HttpDefaultClient_KeepAliveSession + (session, pPollDesc, plContext); + + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +pkix_pl_HttpDefaultClient_FreeSessionFcn( + SEC_HTTP_SERVER_SESSION session) +{ + PKIX_Error *err = + PKIX_PL_Object_DecRef((PKIX_PL_Object *)(session), plContext); + + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +pkix_pl_HttpDefaultClient_RequestCreateFcn( + SEC_HTTP_SERVER_SESSION session, + const char *http_protocol_variant, /* usually "http" */ + const char *path_and_query_string, + const char *http_request_method, + const PRIntervalTime timeout, + SEC_HTTP_REQUEST_SESSION *pRequest) +{ + PKIX_Error *err = pkix_pl_HttpDefaultClient_RequestCreate + (session, + http_protocol_variant, + path_and_query_string, + http_request_method, + timeout, + pRequest, + plContext); + + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +pkix_pl_HttpDefaultClient_SetPostDataFcn( + SEC_HTTP_REQUEST_SESSION request, + const char *http_data, + const PRUint32 http_data_len, + const char *http_content_type) +{ + PKIX_Error *err = + pkix_pl_HttpDefaultClient_SetPostData(request, http_data, + http_data_len, + http_content_type, + plContext); + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +pkix_pl_HttpDefaultClient_AddHeaderFcn( + SEC_HTTP_REQUEST_SESSION request, + const char *http_header_name, + const char *http_header_value) +{ + /* Not supported */ + return SECFailure; +} + +SECStatus +pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn( + SEC_HTTP_REQUEST_SESSION request, + PRPollDesc **pPollDesc, + PRUint16 *http_response_code, + const char **http_response_content_type, + const char **http_response_headers, + const char **http_response_data, + PRUint32 *http_response_data_len) +{ + SECStatus rv = SECFailure; + + PKIX_Error *err = pkix_pl_HttpDefaultClient_TrySendAndReceive + (request, + http_response_code, + http_response_content_type, + http_response_headers, + http_response_data, + http_response_data_len, + pPollDesc, + &rv, + plContext); + + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return rv; + } + return SECSuccess; +} + +SECStatus +pkix_pl_HttpDefaultClient_CancelFcn( + SEC_HTTP_REQUEST_SESSION request) +{ + PKIX_Error *err = pkix_pl_HttpDefaultClient_Cancel(request, plContext); + + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +pkix_pl_HttpDefaultClient_FreeFcn( + SEC_HTTP_REQUEST_SESSION request) +{ + PKIX_Error *err = + PKIX_PL_Object_DecRef((PKIX_PL_Object *)(request), plContext); + + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext); + return SECFailure; + } + return SECSuccess; +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h new file mode 100644 index 0000000000..91916a0ab4 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h @@ -0,0 +1,139 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_httpdefaultclient.h + * + * HTTPDefaultClient Object Type Definition + * + */ + +#ifndef _PKIX_PL_HTTPDEFAULTCLIENT_H +#define _PKIX_PL_HTTPDEFAULTCLIENT_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HTTP_DATA_BUFSIZE 4096 +#define HTTP_HEADER_BUFSIZE 1024 +#define HTTP_MIN_AVAILABLE_BUFFER_SIZE 512 + +typedef enum { + HTTP_NOT_CONNECTED, + HTTP_CONNECT_PENDING, + HTTP_CONNECTED, + HTTP_SEND_PENDING, + HTTP_RECV_HDR, + HTTP_RECV_HDR_PENDING, + HTTP_RECV_BODY, + HTTP_RECV_BODY_PENDING, + HTTP_COMPLETE, + HTTP_ERROR +} HttpConnectStatus; + +typedef enum { + HTTP_POST_METHOD, + HTTP_GET_METHOD +} HttpMethod; + +struct PKIX_PL_HttpDefaultClientStruct { + HttpConnectStatus connectStatus; + PRUint16 portnum; + PRIntervalTime timeout; + PKIX_UInt32 bytesToWrite; + PKIX_UInt32 send_http_data_len; + PKIX_UInt32 rcv_http_data_len; + PKIX_UInt32 capacity; + PKIX_UInt32 filledupBytes; + PKIX_UInt32 responseCode; + PKIX_UInt32 maxResponseLen; + PKIX_UInt32 GETLen; + PKIX_UInt32 POSTLen; + PRUint32 *pRcv_http_data_len; + PRPollDesc pollDesc; + void *callbackList; /* cast this to (PKIX_PL_Socket_Callback *) */ + char *GETBuf; + char *POSTBuf; + char *rcvBuf; + char *host; + char *path; + char *rcvContentType; + void *rcvHeaders; + HttpMethod send_http_method; + const char *send_http_content_type; + const char *send_http_data; + PRUint16 *rcv_http_response_code; + const char **rcv_http_content_type; + const char **rcv_http_headers; + const char **rcv_http_data; + PKIX_PL_Socket *socket; + void *plContext; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_HttpDefaultClient_RegisterSelf(void *plContext); + +SECStatus +pkix_pl_HttpDefaultClient_CreateSessionFcn( + const char *host, + PRUint16 portnum, + SEC_HTTP_SERVER_SESSION *pSession); + +SECStatus +pkix_pl_HttpDefaultClient_KeepAliveSessionFcn( + SEC_HTTP_SERVER_SESSION session, + PRPollDesc **pPollDesc); + +SECStatus +pkix_pl_HttpDefaultClient_FreeSessionFcn( + SEC_HTTP_SERVER_SESSION session); + +SECStatus +pkix_pl_HttpDefaultClient_RequestCreateFcn( + SEC_HTTP_SERVER_SESSION session, + const char *http_protocol_variant, /* usually "http" */ + const char *path_and_query_string, + const char *http_request_method, + const PRIntervalTime timeout, + SEC_HTTP_REQUEST_SESSION *pRequest); + +SECStatus +pkix_pl_HttpDefaultClient_SetPostDataFcn( + SEC_HTTP_REQUEST_SESSION request, + const char *http_data, + const PRUint32 http_data_len, + const char *http_content_type); + +SECStatus +pkix_pl_HttpDefaultClient_AddHeaderFcn( + SEC_HTTP_REQUEST_SESSION request, + const char *http_header_name, + const char *http_header_value); + +SECStatus +pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn( + SEC_HTTP_REQUEST_SESSION request, + PRPollDesc **pPollDesc, + PRUint16 *http_response_code, + const char **http_response_content_type, + const char **http_response_headers, + const char **http_response_data, + PRUint32 *http_response_data_len); + +SECStatus +pkix_pl_HttpDefaultClient_CancelFcn( + SEC_HTTP_REQUEST_SESSION request); + +SECStatus +pkix_pl_HttpDefaultClient_FreeFcn( + SEC_HTTP_REQUEST_SESSION request); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_HTTPDEFAULTCLIENT_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c new file mode 100644 index 0000000000..dd32334ab3 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c @@ -0,0 +1,1113 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldapcertstore.c + * + * LDAPCertStore Function Definitions + * + */ + +/* We can't decode the length of a message without at least this many bytes */ +#define MINIMUM_MSG_LENGTH 5 + +#include "pkix_pl_ldapcertstore.h" + +/* --Private-Ldap-CertStore-Database-Functions----------------------- */ + +/* + * FUNCTION: pkix_pl_LdapCertStore_DecodeCrossCertPair + * DESCRIPTION: + * + * This function decodes a DER-encoded CrossCertPair pointed to by + * "responseList" and extracts and decodes the Certificates in that pair, + * adding the resulting Certs, if the decoding was successful, to the List + * (possibly empty) pointed to by "certList". If none of the objects + * can be decoded into a Cert, the List is returned unchanged. + * + * PARAMETERS: + * "derCCPItem" + * The address of the SECItem containing the DER representation of the + * CrossCertPair. Must be non-NULL. + * "certList" + * The address of the List to which the decoded Certs are added. May be + * empty, but must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapCertStore_DecodeCrossCertPair( + SECItem *derCCPItem, + PKIX_List *certList, + void *plContext) +{ + LDAPCertPair certPair = {{ siBuffer, NULL, 0 }, { siBuffer, NULL, 0 }}; + SECStatus rv = SECFailure; + + PLArenaPool *tempArena = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_DecodeCrossCertPair"); + PKIX_NULLCHECK_TWO(derCCPItem, certList); + + tempArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!tempArena) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + rv = SEC_ASN1DecodeItem(tempArena, &certPair, PKIX_PL_LDAPCrossCertPairTemplate, + derCCPItem); + if (rv != SECSuccess) { + goto cleanup; + } + + if (certPair.forward.data != NULL) { + + PKIX_CHECK( + pkix_pl_Cert_CreateToList(&certPair.forward, certList, + plContext), + PKIX_CERTCREATETOLISTFAILED); + } + + if (certPair.reverse.data != NULL) { + + PKIX_CHECK( + pkix_pl_Cert_CreateToList(&certPair.reverse, certList, + plContext), + PKIX_CERTCREATETOLISTFAILED); + } + +cleanup: + if (tempArena) { + PORT_FreeArena(tempArena, PR_FALSE); + } + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_LdapCertStore_BuildCertList + * DESCRIPTION: + * + * This function takes a List of LdapResponse objects pointed to by + * "responseList" and extracts and decodes the Certificates in those responses, + * storing the List of those Certificates at "pCerts". If none of the objects + * can be decoded into a Cert, the returned List is empty. + * + * PARAMETERS: + * "responseList" + * The address of the List of LdapResponses. Must be non-NULL. + * "pCerts" + * The address at which the result is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapCertStore_BuildCertList( + PKIX_List *responseList, + PKIX_List **pCerts, + void *plContext) +{ + PKIX_UInt32 numResponses = 0; + PKIX_UInt32 respIx = 0; + LdapAttrMask attrBits = 0; + PKIX_PL_LdapResponse *response = NULL; + PKIX_List *certList = NULL; + LDAPMessage *message = NULL; + LDAPSearchResponseEntry *sre = NULL; + LDAPSearchResponseAttr **sreAttrArray = NULL; + LDAPSearchResponseAttr *sreAttr = NULL; + SECItem *attrType = NULL; + SECItem **attrVal = NULL; + SECItem *derCertItem = NULL; + + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCertList"); + PKIX_NULLCHECK_TWO(responseList, pCerts); + + PKIX_CHECK(PKIX_List_Create(&certList, plContext), + PKIX_LISTCREATEFAILED); + + /* extract certs from response */ + PKIX_CHECK(PKIX_List_GetLength + (responseList, &numResponses, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (respIx = 0; respIx < numResponses; respIx++) { + PKIX_CHECK(PKIX_List_GetItem + (responseList, + respIx, + (PKIX_PL_Object **)&response, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_pl_LdapResponse_GetMessage + (response, &message, plContext), + PKIX_LDAPRESPONSEGETMESSAGEFAILED); + + sre = &(message->protocolOp.op.searchResponseEntryMsg); + sreAttrArray = sre->attributes; + + /* Get next element of null-terminated array */ + sreAttr = *sreAttrArray++; + while (sreAttr != NULL) { + attrType = &(sreAttr->attrType); + PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit + (attrType, &attrBits, plContext), + PKIX_LDAPREQUESTATTRTYPETOBITFAILED); + /* Is this attrVal a Certificate? */ + if (((LDAPATTR_CACERT | LDAPATTR_USERCERT) & + attrBits) == attrBits) { + attrVal = sreAttr->val; + derCertItem = *attrVal++; + while (derCertItem != 0) { + /* create a PKIX_PL_Cert from derCert */ + PKIX_CHECK(pkix_pl_Cert_CreateToList + (derCertItem, certList, plContext), + PKIX_CERTCREATETOLISTFAILED); + derCertItem = *attrVal++; + } + } else if ((LDAPATTR_CROSSPAIRCERT & attrBits) == attrBits){ + /* Is this attrVal a CrossPairCertificate? */ + attrVal = sreAttr->val; + derCertItem = *attrVal++; + while (derCertItem != 0) { + /* create PKIX_PL_Certs from derCert */ + PKIX_CHECK(pkix_pl_LdapCertStore_DecodeCrossCertPair + (derCertItem, certList, plContext), + PKIX_LDAPCERTSTOREDECODECROSSCERTPAIRFAILED); + derCertItem = *attrVal++; + } + } + sreAttr = *sreAttrArray++; + } + PKIX_DECREF(response); + } + + *pCerts = certList; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(certList); + } + + PKIX_DECREF(response); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_LdapCertStore_BuildCrlList + * DESCRIPTION: + * + * This function takes a List of LdapResponse objects pointed to by + * "responseList" and extracts and decodes the CRLs in those responses, storing + * the List of those CRLs at "pCrls". If none of the objects can be decoded + * into a CRL, the returned List is empty. + * + * PARAMETERS: + * "responseList" + * The address of the List of LdapResponses. Must be non-NULL. + * "pCrls" + * The address at which the result is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapCertStore_BuildCrlList( + PKIX_List *responseList, + PKIX_List **pCrls, + void *plContext) +{ + PKIX_UInt32 numResponses = 0; + PKIX_UInt32 respIx = 0; + LdapAttrMask attrBits = 0; + CERTSignedCrl *nssCrl = NULL; + PKIX_PL_LdapResponse *response = NULL; + PKIX_List *crlList = NULL; + PKIX_PL_CRL *crl = NULL; + LDAPMessage *message = NULL; + LDAPSearchResponseEntry *sre = NULL; + LDAPSearchResponseAttr **sreAttrArray = NULL; + LDAPSearchResponseAttr *sreAttr = NULL; + SECItem *attrType = NULL; + SECItem **attrVal = NULL; + SECItem *derCrlCopy = NULL; + SECItem *derCrlItem = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCrlList"); + PKIX_NULLCHECK_TWO(responseList, pCrls); + + PKIX_CHECK(PKIX_List_Create(&crlList, plContext), + PKIX_LISTCREATEFAILED); + + /* extract crls from response */ + PKIX_CHECK(PKIX_List_GetLength + (responseList, &numResponses, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (respIx = 0; respIx < numResponses; respIx++) { + PKIX_CHECK(PKIX_List_GetItem + (responseList, + respIx, + (PKIX_PL_Object **)&response, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_pl_LdapResponse_GetMessage + (response, &message, plContext), + PKIX_LDAPRESPONSEGETMESSAGEFAILED); + + sre = &(message->protocolOp.op.searchResponseEntryMsg); + sreAttrArray = sre->attributes; + + /* Get next element of null-terminated array */ + sreAttr = *sreAttrArray++; + while (sreAttr != NULL) { + attrType = &(sreAttr->attrType); + PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit + (attrType, &attrBits, plContext), + PKIX_LDAPREQUESTATTRTYPETOBITFAILED); + /* Is this attrVal a Revocation List? */ + if (((LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST) & + attrBits) == attrBits) { + attrVal = sreAttr->val; + derCrlItem = *attrVal++; + while (derCrlItem != 0) { + /* create a PKIX_PL_Crl from derCrl */ + derCrlCopy = SECITEM_DupItem(derCrlItem); + if (!derCrlCopy) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + /* crl will be based on derCrlCopy, but wont + * own the der. */ + nssCrl = + CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, + SEC_CRL_TYPE, + CRL_DECODE_DONT_COPY_DER | + CRL_DECODE_SKIP_ENTRIES); + if (!nssCrl) { + SECITEM_FreeItem(derCrlCopy, PKIX_TRUE); + continue; + } + /* pkix crl own the der. */ + PKIX_CHECK( + pkix_pl_CRL_CreateWithSignedCRL(nssCrl, + derCrlCopy, NULL, &crl, plContext), + PKIX_CRLCREATEWITHSIGNEDCRLFAILED); + /* Left control over memory pointed by derCrlCopy and + * nssCrl to pkix crl. */ + derCrlCopy = NULL; + nssCrl = NULL; + PKIX_CHECK(PKIX_List_AppendItem + (crlList, (PKIX_PL_Object *) crl, plContext), + PKIX_LISTAPPENDITEMFAILED); + PKIX_DECREF(crl); + derCrlItem = *attrVal++; + } + /* Clean up after PKIX_CHECK_ONLY_FATAL */ + pkixTempErrorReceived = PKIX_FALSE; + } + sreAttr = *sreAttrArray++; + } + PKIX_DECREF(response); + } + + *pCrls = crlList; + crlList = NULL; +cleanup: + if (derCrlCopy) { + SECITEM_FreeItem(derCrlCopy, PKIX_TRUE); + } + if (nssCrl) { + SEC_DestroyCrl(nssCrl); + } + PKIX_DECREF(crl); + PKIX_DECREF(crlList); + PKIX_DECREF(response); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_LdapCertStore_DestroyAVAList + * DESCRIPTION: + * + * This function frees the space allocated for the components of the + * equalFilters that make up the andFilter pointed to by "filter". + * + * PARAMETERS: + * "requestParams" + * The address of the andFilter whose components are to be freed. Must be + * non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapCertStore_DestroyAVAList( + LDAPNameComponent **nameComponents, + void *plContext) +{ + LDAPNameComponent **currentNC = NULL; + unsigned char *component = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_DestroyAVAList"); + PKIX_NULLCHECK_ONE(nameComponents); + + /* Set currentNC to point to first AVA pointer */ + currentNC = nameComponents; + + while ((*currentNC) != NULL) { + component = (*currentNC)->attrValue; + if (component != NULL) { + PORT_Free(component); + } + currentNC++; + } + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_LdapCertStore_MakeNameAVAList + * DESCRIPTION: + * + * This function allocates space from the arena pointed to by "arena" to + * construct a filter that will match components of the X500Name pointed to + * by "name", and stores the resulting filter at "pFilter". + * + * "name" is checked for commonName and organizationName components (cn=, + * and o=). The component strings are extracted using the family of + * CERT_Get* functions, and each must be freed with PORT_Free. + * + * It is not clear which components should be in a request, so, for now, + * we stop adding components after we have found one. + * + * PARAMETERS: + * "arena" + * The address of the PLArenaPool used in creating the filter. Must be + * non-NULL. + * "name" + * The address of the X500Name whose components define the desired + * matches. Must be non-NULL. + * "pList" + * The address at which the result is stored. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapCertStore_MakeNameAVAList( + PLArenaPool *arena, + PKIX_PL_X500Name *subjectName, + LDAPNameComponent ***pList, + void *plContext) +{ + LDAPNameComponent **setOfNameComponents; + LDAPNameComponent *currentNameComponent = NULL; + PKIX_UInt32 componentsPresent = 0; + void *v = NULL; + unsigned char *component = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_MakeNameAVAList"); + PKIX_NULLCHECK_THREE(arena, subjectName, pList); + + /* Increase this if additional components may be extracted */ +#define MAX_NUM_COMPONENTS 3 + + /* Space for (MAX_NUM_COMPONENTS + 1) pointers to LDAPNameComponents */ + PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc, + (arena, (MAX_NUM_COMPONENTS + 1)*sizeof(LDAPNameComponent *))); + setOfNameComponents = (LDAPNameComponent **)v; + + /* Space for MAX_NUM_COMPONENTS LDAPNameComponents */ + PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray, + (arena, LDAPNameComponent, MAX_NUM_COMPONENTS)); + + currentNameComponent = (LDAPNameComponent *)v; + + /* Try for commonName */ + PKIX_CHECK(pkix_pl_X500Name_GetCommonName + (subjectName, &component, plContext), + PKIX_X500NAMEGETCOMMONNAMEFAILED); + if (component) { + setOfNameComponents[componentsPresent] = currentNameComponent; + currentNameComponent->attrType = (unsigned char *)"cn"; + currentNameComponent->attrValue = component; + componentsPresent++; + currentNameComponent++; + } + + /* + * The LDAP specification says we can send multiple name components + * in an "AND" filter, but the LDAP Servers don't seem to be able to + * handle such requests. So we'll quit after the cn component. + */ +#if 0 + /* Try for orgName */ + PKIX_CHECK(pkix_pl_X500Name_GetOrgName + (subjectName, &component, plContext), + PKIX_X500NAMEGETORGNAMEFAILED); + if (component) { + setOfNameComponents[componentsPresent] = currentNameComponent; + currentNameComponent->attrType = (unsigned char *)"o"; + currentNameComponent->attrValue = component; + componentsPresent++; + currentNameComponent++; + } + + /* Try for countryName */ + PKIX_CHECK(pkix_pl_X500Name_GetCountryName + (subjectName, &component, plContext), + PKIX_X500NAMEGETCOUNTRYNAMEFAILED); + if (component) { + setOfNameComponents[componentsPresent] = currentNameComponent; + currentNameComponent->attrType = (unsigned char *)"c"; + currentNameComponent->attrValue = component; + componentsPresent++; + currentNameComponent++; + } +#endif + + setOfNameComponents[componentsPresent] = NULL; + + *pList = setOfNameComponents; + +cleanup: + + PKIX_RETURN(CERTSTORE); + +} + +#if 0 +/* + * FUNCTION: pkix_pl_LdapCertstore_ConvertCertResponses + * DESCRIPTION: + * + * This function processes the List of LDAPResponses pointed to by "responses" + * into a List of resulting Certs, storing the result at "pCerts". If there + * are no responses converted successfully, a NULL may be stored. + * + * PARAMETERS: + * "responses" + * The LDAPResponses whose contents are to be converted. Must be non-NULL. + * "pCerts" + * Address at which the returned List is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapCertStore_ConvertCertResponses( + PKIX_List *responses, + PKIX_List **pCerts, + void *plContext) +{ + PKIX_List *unfiltered = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_ConvertCertResponses"); + PKIX_NULLCHECK_TWO(responses, pCerts); + + /* + * We have a List of LdapResponse objects that have to be + * turned into Certs. + */ + PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList + (responses, &unfiltered, plContext), + PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED); + + *pCerts = unfiltered; + +cleanup: + + PKIX_RETURN(CERTSTORE); +} +#endif + +/* + * FUNCTION: pkix_pl_LdapCertStore_GetCert + * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h) + */ +PKIX_Error * +pkix_pl_LdapCertStore_GetCert( + PKIX_CertStore *store, + PKIX_CertSelector *selector, + PKIX_VerifyNode *verifyNode, + void **pNBIOContext, + PKIX_List **pCertList, + void *plContext) +{ + PLArenaPool *requestArena = NULL; + LDAPRequestParams requestParams; + void *pollDesc = NULL; + PKIX_Int32 minPathLen = 0; + PKIX_Boolean cacheFlag = PKIX_FALSE; + PKIX_ComCertSelParams *params = NULL; + PKIX_PL_LdapCertStoreContext *lcs = NULL; + PKIX_List *responses = NULL; + PKIX_List *unfilteredCerts = NULL; + PKIX_List *filteredCerts = NULL; + PKIX_PL_X500Name *subjectName = 0; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCert"); + PKIX_NULLCHECK_THREE(store, selector, pCertList); + + requestParams.baseObject = "c=US"; + requestParams.scope = WHOLE_SUBTREE; + requestParams.derefAliases = NEVER_DEREF; + requestParams.sizeLimit = 0; + requestParams.timeLimit = 0; + + /* Prepare elements for request filter */ + + /* + * Get a short-lived arena. We'll be done with this space once + * the request is encoded. + */ + requestArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!requestArena) { + PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY); + } + + PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams + (selector, ¶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; + PLArenaPool *requestArena = NULL; + PKIX_UInt32 numNames = 0; + PKIX_UInt32 thisName = 0; + PKIX_PL_CRL *candidate = NULL; + PKIX_List *responses = NULL; + PKIX_List *issuerNames = NULL; + PKIX_List *filteredCRLs = NULL; + PKIX_List *unfilteredCRLs = NULL; + PKIX_PL_X500Name *issuer = NULL; + PKIX_PL_LdapCertStoreContext *lcs = NULL; + PKIX_ComCRLSelParams *params = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRL"); + PKIX_NULLCHECK_THREE(store, selector, pCrlList); + + requestParams.baseObject = "c=US"; + requestParams.scope = WHOLE_SUBTREE; + requestParams.derefAliases = NEVER_DEREF; + requestParams.sizeLimit = 0; + requestParams.timeLimit = 0; + requestParams.attributes = LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST; + /* Prepare elements for request filter */ + + /* XXX Place CRLDP code here. Handle the case when */ + /* RFC 5280. Paragraph: 4.2.1.13: */ + /* If the distributionPoint field contains a directoryName, the entry */ + /* for that directoryName contains the current CRL for the associated */ + /* reasons and the CRL is issued by the associated cRLIssuer. The CRL */ + /* may be stored in either the certificateRevocationList or */ + /* authorityRevocationList attribute. The CRL is to be obtained by the */ + /* application from whatever directory server is locally configured. */ + /* The protocol the application uses to access the directory (e.g., DAP */ + /* or LDAP) is a local matter. */ + + + + /* + * Get a short-lived arena. We'll be done with this space once + * the request is encoded. + */ + PKIX_PL_NSSCALLRV + (CERTSTORE, requestArena, PORT_NewArena, (DER_DEFAULT_CHUNKSIZE)); + + if (!requestArena) { + PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY); + } + + PKIX_CHECK(PKIX_CRLSelector_GetCommonCRLSelectorParams + (selector, ¶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) { + /* + * LDAP Servers don't seem to be able to handle + * requests with more than more than one name. + * So only use first name. + */ + PKIX_CHECK(PKIX_List_GetItem + (issuerNames, + thisName, + (PKIX_PL_Object **)&issuer, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK + (pkix_pl_LdapCertStore_MakeNameAVAList + (requestArena, + issuer, + &(requestParams.nc), + plContext), + PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED); + + PKIX_DECREF(issuer); + + if (*requestParams.nc == NULL) { + /* + * The issuer may not include any + * components that we know how to + * encode. We do not return an error, + * because the caller did not + * necessarily do anything wrong, but + * we return an empty List. + */ + PKIX_PL_NSSCALL + (CERTSTORE, PORT_FreeArena, + (requestArena, PR_FALSE)); + + PKIX_CHECK(PKIX_List_Create + (&filteredCRLs, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_SetImmutable + (filteredCRLs, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + *pNBIOContext = NULL; + *pCrlList = filteredCRLs; + goto cleanup; + } + } else { + PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY); + } + } else { + PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY); + } + + /* All request fields are done */ + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (store, (PKIX_PL_Object **)&lcs, plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest + ((PKIX_PL_LdapClient *)lcs, + &requestParams, + &pollDesc, + &responses, + plContext), + PKIX_LDAPCLIENTINITIATEREQUESTFAILED); + + PKIX_CHECK(pkix_pl_LdapCertStore_DestroyAVAList + (requestParams.nc, plContext), + PKIX_LDAPCERTSTOREDESTROYAVALISTFAILED); + + if (requestArena) { + PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena, + (requestArena, PR_FALSE)); + } + + if (pollDesc != NULL) { + /* client is waiting for non-blocking I/O to complete */ + *pNBIOContext = (void *)pollDesc; + *pCrlList = NULL; + goto cleanup; + } + /* client has finished! */ + + if (responses) { + + /* + * We have a List of LdapResponse objects that still have to be + * turned into Crls. + */ + PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList + (responses, &unfilteredCRLs, plContext), + PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED); + + PKIX_CHECK(pkix_CRLSelector_Select + (selector, unfilteredCRLs, &filteredCRLs, plContext), + PKIX_CRLSELECTORSELECTFAILED); + + } + + /* Don't throw away the list if one CRL was bad! */ + pkixTempErrorReceived = PKIX_FALSE; + + *pNBIOContext = NULL; + *pCrlList = filteredCRLs; + +cleanup: + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(filteredCRLs); + } + + PKIX_DECREF(params); + PKIX_DECREF(issuerNames); + PKIX_DECREF(issuer); + PKIX_DECREF(candidate); + PKIX_DECREF(responses); + PKIX_DECREF(unfilteredCRLs); + PKIX_DECREF(lcs); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_LdapCertStore_GetCRLContinue + * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) + */ +PKIX_Error * +pkix_pl_LdapCertStore_GetCRLContinue( + PKIX_CertStore *store, + PKIX_CRLSelector *selector, + void **pNBIOContext, + PKIX_List **pCrlList, + void *plContext) +{ + void *nbio = NULL; + PKIX_PL_CRL *candidate = NULL; + PKIX_List *responses = NULL; + PKIX_PL_LdapCertStoreContext *lcs = NULL; + PKIX_List *filteredCRLs = NULL; + PKIX_List *unfilteredCRLs = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRLContinue"); + PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList); + + PKIX_CHECK(PKIX_CertStore_GetCertStoreContext + (store, (PKIX_PL_Object **)&lcs, plContext), + PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); + + PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest + ((PKIX_PL_LdapClient *)lcs, &nbio, &responses, plContext), + PKIX_LDAPCLIENTRESUMEREQUESTFAILED); + + if (nbio != NULL) { + /* client is waiting for non-blocking I/O to complete */ + *pNBIOContext = (void *)nbio; + *pCrlList = NULL; + goto cleanup; + } + /* client has finished! */ + + if (responses) { + + /* + * We have a List of LdapResponse objects that still have to be + * turned into Crls. + */ + PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList + (responses, &unfilteredCRLs, plContext), + PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED); + + PKIX_CHECK(pkix_CRLSelector_Select + (selector, unfilteredCRLs, &filteredCRLs, plContext), + PKIX_CRLSELECTORSELECTFAILED); + + PKIX_CHECK(PKIX_List_SetImmutable(filteredCRLs, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + } + + /* Don't throw away the list if one CRL was bad! */ + pkixTempErrorReceived = PKIX_FALSE; + + *pCrlList = filteredCRLs; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(filteredCRLs); + } + + PKIX_DECREF(candidate); + PKIX_DECREF(responses); + PKIX_DECREF(unfilteredCRLs); + PKIX_DECREF(lcs); + + PKIX_RETURN(CERTSTORE); +} + +/* --Public-LdapCertStore-Functions----------------------------------- */ + +/* + * FUNCTION: PKIX_PL_LdapCertStore_Create + * (see comments in pkix_samples_modules.h) + */ +PKIX_Error * +PKIX_PL_LdapCertStore_Create( + PKIX_PL_LdapClient *client, + PKIX_CertStore **pCertStore, + void *plContext) +{ + PKIX_CertStore *certStore = NULL; + + PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapCertStore_Create"); + PKIX_NULLCHECK_TWO(client, pCertStore); + + PKIX_CHECK(PKIX_CertStore_Create + (pkix_pl_LdapCertStore_GetCert, + pkix_pl_LdapCertStore_GetCRL, + pkix_pl_LdapCertStore_GetCertContinue, + pkix_pl_LdapCertStore_GetCRLContinue, + NULL, /* don't support trust */ + NULL, /* can not store crls */ + NULL, /* can not do revocation check */ + (PKIX_PL_Object *)client, + PKIX_TRUE, /* cache flag */ + PKIX_FALSE, /* not local */ + &certStore, + plContext), + PKIX_CERTSTORECREATEFAILED); + + *pCertStore = certStore; + +cleanup: + + PKIX_RETURN(CERTSTORE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h new file mode 100644 index 0000000000..5bbe5385ca --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldapcertstore.h + * + * LDAPCertstore Object Type Definition + * + */ + +#ifndef _PKIX_PL_LDAPCERTSTORE_H +#define _PKIX_PL_LDAPCERTSTORE_H + +#include "pkix_pl_ldapt.h" +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * At the time of this version, there are unresolved questions about the LDAP + * protocol. Although RFC1777 describes a BIND and UNBIND message, it is not + * clear whether they are appropriate to this application. We have tested only + * using servers that do not expect authentication, and that reject BIND + * messages. It is not clear what values might be appropriate for the bindname + * and authentication fields, which are currently implemented as char strings + * supplied by the caller. (If this changes, the API and possibly the templates + * will have to change.) Therefore the CertStore_Create API contains a BindAPI + * structure, a union, which will have to be revised and extended when this + * area of the protocol is better understood. + * + * It is further assumed that a given LdapCertStore will connect only to a + * single server, and that the creation of the socket will initiate the + * CONNECT. Therefore the LdapCertStore handles only the case of continuing + * the connection, if nonblocking I/O is being used. + */ + +typedef enum { + LDAP_CONNECT_PENDING, + LDAP_CONNECTED, + LDAP_BIND_PENDING, + LDAP_BIND_RESPONSE, + LDAP_BIND_RESPONSE_PENDING, + LDAP_BOUND, + LDAP_SEND_PENDING, + LDAP_RECV, + LDAP_RECV_PENDING, + LDAP_RECV_INITIAL, + LDAP_RECV_NONINITIAL, + LDAP_ABANDON_PENDING +} LDAPConnectStatus; + +#define LDAP_CACHEBUCKETS 128 +#define RCVBUFSIZE 512 + +struct PKIX_PL_LdapCertStoreContext { + PKIX_PL_LdapClient *client; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_LdapCertStoreContext_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_LdapCertStore_BuildCertList( + PKIX_List *responseList, + PKIX_List **pCerts, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_LDAPCERTSTORE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c new file mode 100644 index 0000000000..9b6f8d688d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c @@ -0,0 +1,2494 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldapdefaultclient.c + * + * LDAPDefaultClient Function Definitions + * + */ + +/* We can't decode the length of a message without at least this many bytes */ +#define MINIMUM_MSG_LENGTH 5 + +#include "pkix_pl_ldapdefaultclient.h" + +/* --Private-LdapDefaultClient-Message-Building-Functions---------------- */ + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_MakeBind + * DESCRIPTION: + * + * This function creates and encodes a Bind message, using the arena pointed + * to by "arena", the version number contained in "versionData", the + * LDAPBindAPI pointed to by "bindAPI", and the messageID contained in + * "msgNum", and stores a pointer to the encoded string at "pBindMsg". + * + * See pkix_pl_ldaptemplates.c for the ASN.1 description of a Bind message. + * + * This code is not used if the DefaultClient was created with a NULL pointer + * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be + * expected for anonymous Search requests.) + * + * PARAMETERS: + * "arena" + * The address of the PLArenaPool used in encoding the message. Must be + * non-NULL. + * "versionData" + * The Int32 containing the version number to be encoded in the Bind + * message. + * "bindAPI" + * The address of the LDAPBindAPI to be encoded in the Bind message. Must + * be non-NULL. + * "msgNum" + * The Int32 containing the MessageID to be encoded in the Bind message. + * "pBindMsg" + * The address at which the encoded Bind message will be stored. Must be + * non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_MakeBind( + PLArenaPool *arena, + PKIX_Int32 versionData, + LDAPBindAPI *bindAPI, + PKIX_UInt32 msgNum, + SECItem **pBindMsg, + void *plContext) +{ + LDAPMessage msg; + char version = '\0'; + SECItem *encoded = NULL; + PKIX_UInt32 len = 0; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeBind"); + PKIX_NULLCHECK_TWO(arena, pBindMsg); + + PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset, + (&msg, 0, sizeof (LDAPMessage))); + + version = (char)versionData; + + msg.messageID.type = siUnsignedInteger; + msg.messageID.data = (void*)&msgNum; + msg.messageID.len = sizeof (msgNum); + + msg.protocolOp.selector = LDAP_BIND_TYPE; + + msg.protocolOp.op.bindMsg.version.type = siUnsignedInteger; + msg.protocolOp.op.bindMsg.version.data = (void *)&version; + msg.protocolOp.op.bindMsg.version.len = sizeof (char); + + /* + * XXX At present we only know how to handle anonymous requests (no + * authentication), and we are guessing how to do simple authentication. + * This section will need to be revised and extended when other + * authentication is needed. + */ + if (bindAPI->selector == SIMPLE_AUTH) { + msg.protocolOp.op.bindMsg.bindName.type = siAsciiString; + msg.protocolOp.op.bindMsg.bindName.data = + (void *)bindAPI->chooser.simple.bindName; + len = PL_strlen(bindAPI->chooser.simple.bindName); + msg.protocolOp.op.bindMsg.bindName.len = len; + + msg.protocolOp.op.bindMsg.authentication.type = siAsciiString; + msg.protocolOp.op.bindMsg.authentication.data = + (void *)bindAPI->chooser.simple.authentication; + len = PL_strlen(bindAPI->chooser.simple.authentication); + msg.protocolOp.op.bindMsg.authentication.len = len; + } + + PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem, + (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate)); + if (!encoded) { + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + *pBindMsg = encoded; +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_MakeUnbind + * DESCRIPTION: + * + * This function creates and encodes a Unbind message, using the arena pointed + * to by "arena" and the messageID contained in "msgNum", and stores a pointer + * to the encoded string at "pUnbindMsg". + * + * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Unbind message. + * + * This code is not used if the DefaultClient was created with a NULL pointer + * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be + * expected for anonymous Search requests.) + * + * PARAMETERS: + * "arena" + * The address of the PLArenaPool used in encoding the message. Must be + * non-NULL. + * "msgNum" + * The Int32 containing the MessageID to be encoded in the Unbind message. + * "pUnbindMsg" + * The address at which the encoded Unbind message will be stored. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_MakeUnbind( + PLArenaPool *arena, + PKIX_UInt32 msgNum, + SECItem **pUnbindMsg, + void *plContext) +{ + LDAPMessage msg; + SECItem *encoded = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeUnbind"); + PKIX_NULLCHECK_TWO(arena, pUnbindMsg); + + PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset, + (&msg, 0, sizeof (LDAPMessage))); + + msg.messageID.type = siUnsignedInteger; + msg.messageID.data = (void*)&msgNum; + msg.messageID.len = sizeof (msgNum); + + msg.protocolOp.selector = LDAP_UNBIND_TYPE; + + msg.protocolOp.op.unbindMsg.dummy.type = siBuffer; + msg.protocolOp.op.unbindMsg.dummy.data = NULL; + msg.protocolOp.op.unbindMsg.dummy.len = 0; + + PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem, + (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate)); + if (!encoded) { + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + *pUnbindMsg = encoded; +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_MakeAbandon + * DESCRIPTION: + * + * This function creates and encodes a Abandon message, using the arena pointed + * to by "arena" and the messageID contained in "msgNum", and stores a pointer + * to the encoded string at "pAbandonMsg". + * + * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Abandon message. + * + * PARAMETERS: + * "arena" + * The address of the PLArenaPool used in encoding the message. Must be + * non-NULL. + * "msgNum" + * The Int32 containing the MessageID to be encoded in the Abandon message. + * "pAbandonMsg" + * The address at which the encoded Abandon message will be stored. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_MakeAbandon( + PLArenaPool *arena, + PKIX_UInt32 msgNum, + SECItem **pAbandonMsg, + void *plContext) +{ + LDAPMessage msg; + SECItem *encoded = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeAbandon"); + PKIX_NULLCHECK_TWO(arena, pAbandonMsg); + + PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset, + (&msg, 0, sizeof (LDAPMessage))); + + msg.messageID.type = siUnsignedInteger; + msg.messageID.data = (void*)&msgNum; + msg.messageID.len = sizeof (msgNum); + + msg.protocolOp.selector = LDAP_ABANDONREQUEST_TYPE; + + msg.protocolOp.op.abandonRequestMsg.messageID.type = siBuffer; + msg.protocolOp.op.abandonRequestMsg.messageID.data = (void*)&msgNum; + msg.protocolOp.op.abandonRequestMsg.messageID.len = sizeof (msgNum); + + PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem, + (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate)); + if (!encoded) { + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + *pAbandonMsg = encoded; +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_DecodeBindResponse + * DESCRIPTION: + * + * This function decodes the encoded data pointed to by "src", using the arena + * pointed to by "arena", storing the decoded LDAPMessage at "pBindResponse" + * and the decoding status at "pStatus". + * + * PARAMETERS: + * "arena" + * The address of the PLArenaPool to be used in decoding the message. Must + * be non-NULL. + * "src" + * The address of the SECItem containing the DER- (or BER-)encoded string. + * Must be non-NULL. + * "pBindResponse" + * The address at which the LDAPMessage is stored, if the decoding is + * successful (the returned status is SECSuccess). Must be non-NULL. + * "pStatus" + * The address at which the decoding status is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_DecodeBindResponse( + PLArenaPool *arena, + SECItem *src, + LDAPMessage *pBindResponse, + SECStatus *pStatus, + void *plContext) +{ + SECStatus rv = SECFailure; + LDAPMessage response; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_DecodeBindResponse"); + PKIX_NULLCHECK_FOUR(arena, src, pBindResponse, pStatus); + + PKIX_PL_NSSCALL + (LDAPDEFAULTCLIENT, + PORT_Memset, + (&response, 0, sizeof (LDAPMessage))); + + PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, rv, SEC_ASN1DecodeItem, + (arena, &response, PKIX_PL_LDAPMessageTemplate, src)); + + if (rv == SECSuccess) { + *pBindResponse = response; + } + + *pStatus = rv; + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_VerifyBindResponse + * DESCRIPTION: + * + * This function verifies that the contents of the message in the rcvbuf of + * the LdapDefaultClient object pointed to by "client", and whose length is + * provided by "buflen", is a response to a successful Bind. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "buflen" + * The value of the number of bytes in the receive buffer. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_VerifyBindResponse( + PKIX_PL_LdapDefaultClient *client, + PKIX_UInt32 bufLen, + void *plContext) +{ + SECItem decode = {siBuffer, NULL, 0}; + SECStatus rv = SECFailure; + LDAPMessage msg; + LDAPBindResponse *ldapBindResponse = &msg.protocolOp.op.bindResponseMsg; + + ldapBindResponse->resultCode.data = NULL; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_VerifyBindResponse"); + PKIX_NULLCHECK_TWO(client, client->rcvBuf); + + decode.data = (unsigned char *)(client->rcvBuf); + decode.len = bufLen; + + PKIX_CHECK(pkix_pl_LdapDefaultClient_DecodeBindResponse + (client->arena, &decode, &msg, &rv, plContext), + PKIX_LDAPDEFAULTCLIENTDECODEBINDRESPONSEFAILED); + + if (rv == SECSuccess) { + if (*(ldapBindResponse->resultCode.data) == SUCCESS) { + client->connectStatus = BOUND; + } else { + PKIX_ERROR(PKIX_BINDREJECTEDBYSERVER); + } + } else { + PKIX_ERROR(PKIX_CANTDECODEBINDRESPONSEFROMSERVER); + } + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_RecvCheckComplete + * DESCRIPTION: + * + * This function determines whether the current response in the + * LdapDefaultClient pointed to by "client" is complete, in the sense that all + * bytes required to satisfy the message length field in the encoding have been + * received. If so, the pointer to input data is updated to reflect the number + * of bytes consumed, provided by "bytesProcessed". The state machine flag + * pointed to by "pKeepGoing" is updated to indicate whether processing can + * continue without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "bytesProcessed" + * The UInt32 value of the number of bytes consumed from the current + * buffer. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_RecvCheckComplete( + PKIX_PL_LdapDefaultClient *client, + PKIX_UInt32 bytesProcessed, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_Boolean complete = PKIX_FALSE; + SECStatus rv = SECFailure; + LDAPMessageType messageType = 0; + LDAPResultCode resultCode = 0; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_RecvCheckComplete"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + PKIX_CHECK(pkix_pl_LdapResponse_IsComplete + (client->currentResponse, &complete, plContext), + PKIX_LDAPRESPONSEISCOMPLETEFAILED); + + if (complete) { + PKIX_CHECK(pkix_pl_LdapResponse_Decode + (client->arena, client->currentResponse, &rv, plContext), + PKIX_LDAPRESPONSEDECODEFAILED); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_CANTDECODESEARCHRESPONSEFROMSERVER); + } + + PKIX_CHECK(pkix_pl_LdapResponse_GetMessageType + (client->currentResponse, &messageType, plContext), + PKIX_LDAPRESPONSEGETMESSAGETYPEFAILED); + + if (messageType == LDAP_SEARCHRESPONSEENTRY_TYPE) { + + if (client->entriesFound == NULL) { + PKIX_CHECK(PKIX_List_Create + (&(client->entriesFound), plContext), + PKIX_LISTCREATEFAILED); + } + + PKIX_CHECK(PKIX_List_AppendItem + (client->entriesFound, + (PKIX_PL_Object *)client->currentResponse, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(client->currentResponse); + + /* current receive buffer empty? */ + if (client->currentBytesAvailable == 0) { + client->connectStatus = RECV; + *pKeepGoing = PKIX_TRUE; + } else { + client->connectStatus = RECV_INITIAL; + client->currentInPtr = &((char *) + (client->currentInPtr))[bytesProcessed]; + *pKeepGoing = PKIX_TRUE; + } + + } else if (messageType == LDAP_SEARCHRESPONSERESULT_TYPE) { + PKIX_CHECK(pkix_pl_LdapResponse_GetResultCode + (client->currentResponse, + &resultCode, + plContext), + PKIX_LDAPRESPONSEGETRESULTCODEFAILED); + + if ((client->entriesFound == NULL) && + ((resultCode == SUCCESS) || + (resultCode == NOSUCHOBJECT))) { + PKIX_CHECK(PKIX_List_Create + (&(client->entriesFound), plContext), + PKIX_LISTCREATEFAILED); + } else if (resultCode == SUCCESS) { + PKIX_CHECK(PKIX_List_SetImmutable + (client->entriesFound, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + PKIX_CHECK(PKIX_PL_HashTable_Add + (client->cachePtr, + (PKIX_PL_Object *)client->currentRequest, + (PKIX_PL_Object *)client->entriesFound, + plContext), + PKIX_HASHTABLEADDFAILED); + } else { + PKIX_ERROR(PKIX_UNEXPECTEDRESULTCODEINRESPONSE); + } + + client->connectStatus = BOUND; + *pKeepGoing = PKIX_FALSE; + PKIX_DECREF(client->currentResponse); + + } else { + PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE); + } + } else { + client->connectStatus = RECV; + *pKeepGoing = PKIX_TRUE; + } + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* --Private-LdapDefaultClient-Object-Functions------------------------- */ + +static PKIX_Error * +pkix_pl_LdapDefaultClient_InitiateRequest( + PKIX_PL_LdapClient *client, + LDAPRequestParams *requestParams, + void **pPollDesc, + PKIX_List **pResponse, + void *plContext); + +static PKIX_Error * +pkix_pl_LdapDefaultClient_ResumeRequest( + PKIX_PL_LdapClient *client, + void **pPollDesc, + PKIX_List **pResponse, + void *plContext); + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_CreateHelper + * DESCRIPTION: + * + * This function creates a new LdapDefaultClient using the Socket pointed to + * by "socket", the PRIntervalTime pointed to by "timeout", and the + * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient". + * + * A value of zero for "timeout" means the LDAPClient will use non-blocking + * I/O. + * + * PARAMETERS: + * "socket" + * Address of the Socket to be used for the client. Must be non-NULL. + * "bindAPI" + * The address of the LDAPBindAPI containing the Bind information to be + * encoded in the Bind message. + * "pClient" + * The address at which the created LdapDefaultClient is to be stored. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapDefaultClient_CreateHelper( + PKIX_PL_Socket *socket, + LDAPBindAPI *bindAPI, + PKIX_PL_LdapDefaultClient **pClient, + void *plContext) +{ + PKIX_PL_HashTable *ht; + PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL; + PKIX_PL_Socket_Callback *callbackList; + PRFileDesc *fileDesc = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_CreateHelper"); + PKIX_NULLCHECK_TWO(socket, pClient); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_LDAPDEFAULTCLIENT_TYPE, + sizeof (PKIX_PL_LdapDefaultClient), + (PKIX_PL_Object **)&ldapDefaultClient, + plContext), + PKIX_COULDNOTCREATELDAPDEFAULTCLIENTOBJECT); + + ldapDefaultClient->vtable.initiateFcn = + pkix_pl_LdapDefaultClient_InitiateRequest; + ldapDefaultClient->vtable.resumeFcn = + pkix_pl_LdapDefaultClient_ResumeRequest; + + PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc + (socket, &fileDesc, plContext), + PKIX_SOCKETGETPRFILEDESCFAILED); + + ldapDefaultClient->pollDesc.fd = fileDesc; + ldapDefaultClient->pollDesc.in_flags = 0; + ldapDefaultClient->pollDesc.out_flags = 0; + + ldapDefaultClient->bindAPI = bindAPI; + + PKIX_CHECK(PKIX_PL_HashTable_Create + (LDAP_CACHEBUCKETS, 0, &ht, plContext), + PKIX_HASHTABLECREATEFAILED); + + ldapDefaultClient->cachePtr = ht; + + PKIX_CHECK(pkix_pl_Socket_GetCallbackList + (socket, &callbackList, plContext), + PKIX_SOCKETGETCALLBACKLISTFAILED); + + ldapDefaultClient->callbackList = callbackList; + + PKIX_INCREF(socket); + ldapDefaultClient->clientSocket = socket; + + ldapDefaultClient->messageID = 0; + + ldapDefaultClient->bindAPI = bindAPI; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY); + } + ldapDefaultClient->arena = arena; + + ldapDefaultClient->sendBuf = NULL; + ldapDefaultClient->bytesToWrite = 0; + + PKIX_CHECK(PKIX_PL_Malloc + (RCVBUFSIZE, &ldapDefaultClient->rcvBuf, plContext), + PKIX_MALLOCFAILED); + ldapDefaultClient->capacity = RCVBUFSIZE; + + ldapDefaultClient->bindMsg = NULL; + ldapDefaultClient->bindMsgLen = 0; + + ldapDefaultClient->entriesFound = NULL; + ldapDefaultClient->currentRequest = NULL; + ldapDefaultClient->currentResponse = NULL; + + *pClient = ldapDefaultClient; + +cleanup: + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(ldapDefaultClient); + } + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: PKIX_PL_LdapDefaultClient_Create + * DESCRIPTION: + * + * This function creates a new LdapDefaultClient using the PRNetAddr pointed to + * by "sockaddr", the PRIntervalTime pointed to by "timeout", and the + * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient". + * + * A value of zero for "timeout" means the LDAPClient will use non-blocking + * I/O. + * + * PARAMETERS: + * "sockaddr" + * Address of the PRNetAddr to be used for the socket connection. Must be + * non-NULL. + * "timeout" + * The PRIntervalTime to be used in I/O requests for this client. + * "bindAPI" + * The address of the LDAPBindAPI containing the Bind information to be + * encoded in the Bind message. + * "pClient" + * The address at which the created LdapDefaultClient is to be stored. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +PKIX_PL_LdapDefaultClient_Create( + PRNetAddr *sockaddr, + PRIntervalTime timeout, + LDAPBindAPI *bindAPI, + PKIX_PL_LdapDefaultClient **pClient, + void *plContext) +{ + PRErrorCode status = 0; + PKIX_PL_Socket *socket = NULL; + PKIX_PL_LdapDefaultClient *client = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_Create"); + PKIX_NULLCHECK_TWO(sockaddr, pClient); + + PKIX_CHECK(pkix_pl_Socket_Create + (PKIX_FALSE, timeout, sockaddr, &status, &socket, plContext), + PKIX_SOCKETCREATEFAILED); + + PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper + (socket, bindAPI, &client, plContext), + PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED); + + /* Did Socket_Create say the connection was made? */ + if (status == 0) { + if (client->bindAPI != NULL) { + client->connectStatus = CONNECTED; + } else { + client->connectStatus = BOUND; + } + } else { + client->connectStatus = CONNECT_PENDING; + } + + *pClient = client; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(client); + } + + PKIX_DECREF(socket); + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: PKIX_PL_LdapDefaultClient_CreateByName + * DESCRIPTION: + * + * This function creates a new LdapDefaultClient using the hostname pointed to + * by "hostname", the PRIntervalTime pointed to by "timeout", and the + * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient". + * + * A value of zero for "timeout" means the LDAPClient will use non-blocking + * I/O. + * + * PARAMETERS: + * "hostname" + * Address of the hostname to be used for the socket connection. Must be + * non-NULL. + * "timeout" + * The PRIntervalTime to be used in I/O requests for this client. + * "bindAPI" + * The address of the LDAPBindAPI containing the Bind information to be + * encoded in the Bind message. + * "pClient" + * The address at which the created LdapDefaultClient is to be stored. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +PKIX_PL_LdapDefaultClient_CreateByName( + char *hostname, + PRIntervalTime timeout, + LDAPBindAPI *bindAPI, + PKIX_PL_LdapDefaultClient **pClient, + void *plContext) +{ + PRErrorCode status = 0; + PKIX_PL_Socket *socket = NULL; + PKIX_PL_LdapDefaultClient *client = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_CreateByName"); + PKIX_NULLCHECK_TWO(hostname, pClient); + + PKIX_CHECK(pkix_pl_Socket_CreateByName + (PKIX_FALSE, timeout, hostname, &status, &socket, plContext), + PKIX_SOCKETCREATEBYNAMEFAILED); + + PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper + (socket, bindAPI, &client, plContext), + PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED); + + /* Did Socket_Create say the connection was made? */ + if (status == 0) { + if (client->bindAPI != NULL) { + client->connectStatus = CONNECTED; + } else { + client->connectStatus = BOUND; + } + } else { + client->connectStatus = CONNECT_PENDING; + } + + *pClient = client; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(client); + } + + PKIX_DECREF(socket); + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_PL_LdapDefaultClient *client = NULL; + PKIX_PL_Socket_Callback *callbackList = NULL; + SECItem *encoded = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext), + PKIX_OBJECTNOTANLDAPDEFAULTCLIENT); + + client = (PKIX_PL_LdapDefaultClient *)object; + + switch (client->connectStatus) { + case CONNECT_PENDING: + break; + case CONNECTED: + case BIND_PENDING: + case BIND_RESPONSE: + case BIND_RESPONSE_PENDING: + case BOUND: + case SEND_PENDING: + case RECV: + case RECV_PENDING: + case RECV_INITIAL: + case RECV_NONINITIAL: + case ABANDON_PENDING: + if (client->bindAPI != NULL) { + PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeUnbind + (client->arena, + ++(client->messageID), + &encoded, + plContext), + PKIX_LDAPDEFAULTCLIENTMAKEUNBINDFAILED); + + callbackList = + (PKIX_PL_Socket_Callback *)(client->callbackList); + PKIX_CHECK(callbackList->sendCallback + (client->clientSocket, + encoded->data, + encoded->len, + &bytesWritten, + plContext), + PKIX_SOCKETSENDFAILED); + } + break; + default: + PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTINILLEGALSTATE); + } + + PKIX_DECREF(client->cachePtr); + PKIX_DECREF(client->clientSocket); + PKIX_DECREF(client->entriesFound); + PKIX_DECREF(client->currentRequest); + PKIX_DECREF(client->currentResponse); + + PKIX_CHECK(PKIX_PL_Free + (client->rcvBuf, plContext), PKIX_FREEFAILED); + + PKIX_PL_NSSCALL + (LDAPDEFAULTCLIENT, + PORT_FreeArena, + (client->arena, PR_FALSE)); + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL; + PKIX_UInt32 tempHash = 0; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext), + PKIX_OBJECTNOTANLDAPDEFAULTCLIENT); + + ldapDefaultClient = (PKIX_PL_LdapDefaultClient *)object; + + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *)ldapDefaultClient->clientSocket, + &tempHash, + plContext), + PKIX_SOCKETHASHCODEFAILED); + + if (ldapDefaultClient->bindAPI != NULL) { + tempHash = (tempHash << 7) + + ldapDefaultClient->bindAPI->selector; + } + + *pHashcode = tempHash; + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_PL_LdapDefaultClient *firstClientContext = NULL; + PKIX_PL_LdapDefaultClient *secondClientContext = NULL; + PKIX_Int32 compare = 0; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + *pResult = PKIX_FALSE; + + PKIX_CHECK(pkix_CheckTypes + (firstObject, + secondObject, + PKIX_LDAPDEFAULTCLIENT_TYPE, + plContext), + PKIX_OBJECTNOTANLDAPDEFAULTCLIENT); + + firstClientContext = (PKIX_PL_LdapDefaultClient *)firstObject; + secondClientContext = (PKIX_PL_LdapDefaultClient *)secondObject; + + if (firstClientContext == secondClientContext) { + *pResult = PKIX_TRUE; + goto cleanup; + } + + PKIX_CHECK(PKIX_PL_Object_Equals + ((PKIX_PL_Object *)firstClientContext->clientSocket, + (PKIX_PL_Object *)secondClientContext->clientSocket, + &compare, + plContext), + PKIX_SOCKETEQUALSFAILED); + + if (!compare) { + goto cleanup; + } + + if (PKIX_EXACTLY_ONE_NULL + (firstClientContext->bindAPI, secondClientContext->bindAPI)) { + goto cleanup; + } + + if (firstClientContext->bindAPI) { + if (firstClientContext->bindAPI->selector != + secondClientContext->bindAPI->selector) { + goto cleanup; + } + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_PL_LDAPDEFAULTCLIENT_TYPE and its related + * functions with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_LdapDefaultClient_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_RegisterSelf"); + + entry.description = "LdapDefaultClient"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_LdapDefaultClient); + entry.destructor = pkix_pl_LdapDefaultClient_Destroy; + entry.equalsFunction = pkix_pl_LdapDefaultClient_Equals; + entry.hashcodeFunction = pkix_pl_LdapDefaultClient_Hashcode; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_LDAPDEFAULTCLIENT_TYPE] = entry; + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_GetPollDesc + * DESCRIPTION: + * + * This function retrieves the PRPollDesc from the LdapDefaultClient + * pointed to by "context" and stores the address at "pPollDesc". + * + * PARAMETERS: + * "context" + * The LdapDefaultClient whose PRPollDesc is desired. Must be non-NULL. + * "pPollDesc" + * Address where PRPollDesc will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapDefaultClient_GetPollDesc( + PKIX_PL_LdapDefaultClient *context, + PRPollDesc **pPollDesc, + void *plContext) +{ + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_GetPollDesc"); + PKIX_NULLCHECK_TWO(context, pPollDesc); + + *pPollDesc = &(context->pollDesc); + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* --Private-Ldap-CertStore-I/O-Functions---------------------------- */ +/* + * FUNCTION: pkix_pl_LdapDefaultClient_ConnectContinue + * DESCRIPTION: + * + * This function determines whether a socket Connect initiated earlier for the + * CertStore embodied in the LdapDefaultClient "client" has completed, and + * stores in "pKeepGoing" a flag indicating whether processing can continue + * without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_ConnectContinue( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_PL_Socket_Callback *callbackList; + PRErrorCode status; + PKIX_Boolean keepGoing = PKIX_FALSE; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_ConnectContinue"); + PKIX_NULLCHECK_ONE(client); + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->connectcontinueCallback + (client->clientSocket, &status, plContext), + PKIX_SOCKETCONNECTCONTINUEFAILED); + + if (status == 0) { + if (client->bindAPI != NULL) { + client->connectStatus = CONNECTED; + } else { + client->connectStatus = BOUND; + } + keepGoing = PKIX_FALSE; + } else if (status != PR_IN_PROGRESS_ERROR) { + PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION); + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + *pKeepGoing = keepGoing; + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_Bind + * DESCRIPTION: + * + * This function creates and sends the LDAP-protocol Bind message for the + * CertStore embodied in the LdapDefaultClient "client", and stores in + * "pKeepGoing" a flag indicating whether processing can continue without + * further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_Bind( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + SECItem *encoded = NULL; + PKIX_Int32 bytesWritten = 0; + PKIX_PL_Socket_Callback *callbackList; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Bind"); + PKIX_NULLCHECK_ONE(client); + + /* if we have not yet constructed the BIND message, build it now */ + if (!(client->bindMsg)) { + PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeBind + (client->arena, + 3, + client->bindAPI, + client->messageID, + &encoded, + plContext), + PKIX_LDAPDEFAULTCLIENTMAKEBINDFAILED); + client->bindMsg = encoded->data; + client->bindMsgLen = encoded->len; + } + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->sendCallback + (client->clientSocket, + client->bindMsg, + client->bindMsgLen, + &bytesWritten, + plContext), + PKIX_SOCKETSENDFAILED); + + client->lastIO = PR_Now(); + + if (bytesWritten < 0) { + client->connectStatus = BIND_PENDING; + *pKeepGoing = PKIX_FALSE; + } else { + client->connectStatus = BIND_RESPONSE; + *pKeepGoing = PKIX_TRUE; + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_BindContinue + * DESCRIPTION: + * + * This function determines whether the LDAP-protocol Bind message for the + * CertStore embodied in the LdapDefaultClient "client" has completed, and + * stores in "pKeepGoing" a flag indicating whether processing can continue + * without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error *pkix_pl_LdapDefaultClient_BindContinue( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindContinue"); + PKIX_NULLCHECK_ONE(client); + + *pKeepGoing = PKIX_FALSE; + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->pollCallback + (client->clientSocket, &bytesWritten, NULL, plContext), + PKIX_SOCKETPOLLFAILED); + + /* + * If the send completed we can proceed to try for the + * response. If the send did not complete we will have + * continue to poll. + */ + if (bytesWritten >= 0) { + + client->connectStatus = BIND_RESPONSE; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + *pKeepGoing = PKIX_TRUE; + } + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_BindResponse + * DESCRIPTION: + * + * This function attempts to read the LDAP-protocol BindResponse message for + * the CertStore embodied in the LdapDefaultClient "client", and stores in + * "pKeepGoing" a flag indicating whether processing can continue without + * further input. + * + * If a BindResponse is received with a Result code of 0 (success), we + * continue with the connection. If a non-zero Result code is received, + * we throw an Error. Some more sophisticated handling of that condition + * might be in order in the future. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_BindResponse( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_Int32 bytesRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindResponse"); + PKIX_NULLCHECK_TWO(client, client->rcvBuf); + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->recvCallback + (client->clientSocket, + client->rcvBuf, + client->capacity, + &bytesRead, + plContext), + PKIX_SOCKETRECVFAILED); + + client->lastIO = PR_Now(); + + if (bytesRead > 0) { + PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse + (client, bytesRead, plContext), + PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED); + /* + * XXX What should we do if failure? At present if + * VerifyBindResponse throws an Error, we do too. + */ + client->connectStatus = BOUND; + } else { + client->connectStatus = BIND_RESPONSE_PENDING; + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + *pKeepGoing = PKIX_TRUE; + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_BindResponseContinue + * DESCRIPTION: + * + * This function determines whether the LDAP-protocol BindResponse message for + * the CertStore embodied in the LdapDefaultClient "client" has completed, and + * stores in "pKeepGoing" a flag indicating whether processing can continue + * without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_BindResponseContinue( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_Int32 bytesRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_BindResponseContinue"); + PKIX_NULLCHECK_ONE(client); + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->pollCallback + (client->clientSocket, NULL, &bytesRead, plContext), + PKIX_SOCKETPOLLFAILED); + + if (bytesRead > 0) { + PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse + (client, bytesRead, plContext), + PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED); + client->connectStatus = BOUND; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + *pKeepGoing = PKIX_TRUE; + } else { + *pKeepGoing = PKIX_FALSE; + } + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_Send + * DESCRIPTION: + * + * This function creates and sends an LDAP-protocol message for the + * CertStore embodied in the LdapDefaultClient "client", and stores in + * "pKeepGoing" a flag indicating whether processing can continue without + * further input, and at "pBytesTransferred" the number of bytes sent. + * + * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use + * and that transmission has not completed. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "pBytesTransferred" + * The address at which the number of bytes sent is stored. Must be + * non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_Send( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + PKIX_UInt32 *pBytesTransferred, + void *plContext) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Send"); + PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); + + *pKeepGoing = PKIX_FALSE; + + /* Do we have anything waiting to go? */ + if (client->sendBuf) { + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->sendCallback + (client->clientSocket, + client->sendBuf, + client->bytesToWrite, + &bytesWritten, + plContext), + PKIX_SOCKETSENDFAILED); + + client->lastIO = PR_Now(); + + /* + * If the send completed we can proceed to try for the + * response. If the send did not complete we will have + * to poll for completion later. + */ + if (bytesWritten >= 0) { + client->sendBuf = NULL; + client->connectStatus = RECV; + *pKeepGoing = PKIX_TRUE; + + } else { + *pKeepGoing = PKIX_FALSE; + client->connectStatus = SEND_PENDING; + } + + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + *pBytesTransferred = bytesWritten; + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_SendContinue + * DESCRIPTION: + * + * This function determines whether the sending of the LDAP-protocol message + * for the CertStore embodied in the LdapDefaultClient "client" has completed, + * and stores in "pKeepGoing" a flag indicating whether processing can continue + * without further input, and at "pBytesTransferred" the number of bytes sent. + * + * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use + * and that transmission has not completed. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "pBytesTransferred" + * The address at which the number of bytes sent is stored. Must be + * non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_SendContinue( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + PKIX_UInt32 *pBytesTransferred, + void *plContext) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_SendContinue"); + PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); + + *pKeepGoing = PKIX_FALSE; + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->pollCallback + (client->clientSocket, &bytesWritten, NULL, plContext), + PKIX_SOCKETPOLLFAILED); + + /* + * If the send completed we can proceed to try for the + * response. If the send did not complete we will have + * continue to poll. + */ + if (bytesWritten >= 0) { + client->sendBuf = NULL; + client->connectStatus = RECV; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + *pKeepGoing = PKIX_TRUE; + } + + *pBytesTransferred = bytesWritten; + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_Recv + * DESCRIPTION: + * + * This function receives an LDAP-protocol message for the CertStore embodied + * in the LdapDefaultClient "client", and stores in "pKeepGoing" a flag + * indicating whether processing can continue without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_Recv( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_Int32 bytesRead = 0; + PKIX_UInt32 bytesToRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Recv"); + PKIX_NULLCHECK_THREE(client, pKeepGoing, client->rcvBuf); + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + /* + * If we attempt to fill our buffer with every read, we increase + * the risk of an ugly situation: one or two bytes of a new message + * left over at the end of processing one message. With such a + * fragment, we can't decode a byte count and so won't know how much + * space to allocate for the next LdapResponse. We try to avoid that + * case by reading just enough to complete the current message, unless + * there will be at least MINIMUM_MSG_LENGTH bytes left over. + */ + if (client->currentResponse) { + PKIX_CHECK(pkix_pl_LdapResponse_GetCapacity + (client->currentResponse, &bytesToRead, plContext), + PKIX_LDAPRESPONSEGETCAPACITYFAILED); + if ((bytesToRead > client->capacity) || + ((bytesToRead + MINIMUM_MSG_LENGTH) < client->capacity)) { + bytesToRead = client->capacity; + } + } else { + bytesToRead = client->capacity; + } + + client->currentBytesAvailable = 0; + + PKIX_CHECK(callbackList->recvCallback + (client->clientSocket, + (void *)client->rcvBuf, + bytesToRead, + &bytesRead, + plContext), + PKIX_SOCKETRECVFAILED); + + client->currentInPtr = client->rcvBuf; + client->lastIO = PR_Now(); + + if (bytesRead > 0) { + client->currentBytesAvailable = bytesRead; + client->connectStatus = RECV_INITIAL; + *pKeepGoing = PKIX_TRUE; + } else { + client->connectStatus = RECV_PENDING; + *pKeepGoing = PKIX_FALSE; + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_RecvContinue + * DESCRIPTION: + * + * This function determines whether the receiving of the LDAP-protocol message + * for the CertStore embodied in the LdapDefaultClient "client" has completed, + * and stores in "pKeepGoing" a flag indicating whether processing can continue + * without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_RecvContinue( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_Int32 bytesRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvContinue"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->pollCallback + (client->clientSocket, NULL, &bytesRead, plContext), + PKIX_SOCKETPOLLFAILED); + + if (bytesRead > 0) { + client->currentBytesAvailable += bytesRead; + client->connectStatus = RECV_INITIAL; + *pKeepGoing = PKIX_TRUE; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + } else { + *pKeepGoing = PKIX_FALSE; + } + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_AbandonContinue + * DESCRIPTION: + * + * This function determines whether the abandon-message request of the + * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient + * "client" has completed, and stores in "pKeepGoing" a flag indicating whether + * processing can continue without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_AbandonContinue( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_AbandonContinue"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + + PKIX_CHECK(callbackList->pollCallback + (client->clientSocket, &bytesWritten, NULL, plContext), + PKIX_SOCKETPOLLFAILED); + + if (bytesWritten > 0) { + client->connectStatus = BOUND; + *pKeepGoing = PKIX_TRUE; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)client, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + } else { + *pKeepGoing = PKIX_FALSE; + } + +cleanup: + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_RecvInitial + * DESCRIPTION: + * + * This function processes the contents of the first buffer of a received + * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient + * "client", and stores in "pKeepGoing" a flag indicating whether processing can + * continue without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_RecvInitial( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + unsigned char *msgBuf = NULL; + unsigned char *to = NULL; + unsigned char *from = NULL; + PKIX_UInt32 dataIndex = 0; + PKIX_UInt32 messageIdLen = 0; + PKIX_UInt32 messageLength = 0; + PKIX_UInt32 sizeofLength = 0; + PKIX_UInt32 bytesProcessed = 0; + unsigned char messageChar = 0; + LDAPMessageType messageType = 0; + PKIX_Int32 bytesRead = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvInitial"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + /* + * Is there an LDAPResponse in progress? I.e., have we + * already processed the tag and length at the beginning of + * the message? + */ + if (client->currentResponse) { + client->connectStatus = RECV_NONINITIAL; + *pKeepGoing = PKIX_TRUE; + goto cleanup; + } + msgBuf = client->currentInPtr; + + /* Do we have enough of the message to decode the message length? */ + if (client->currentBytesAvailable < MINIMUM_MSG_LENGTH) { + /* + * No! Move these few bytes to the beginning of rcvBuf + * and hang another read. + */ + + to = (unsigned char *)client->rcvBuf; + from = client->currentInPtr; + for (dataIndex = 0; + dataIndex < client->currentBytesAvailable; + dataIndex++) { + *to++ = *from++; + } + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + PKIX_CHECK(callbackList->recvCallback + (client->clientSocket, + (void *)to, + client->capacity - client->currentBytesAvailable, + &bytesRead, + plContext), + PKIX_SOCKETRECVFAILED); + + client->currentInPtr = client->rcvBuf; + client->lastIO = PR_Now(); + + if (bytesRead <= 0) { + client->connectStatus = RECV_PENDING; + *pKeepGoing = PKIX_FALSE; + goto cleanup; + } else { + client->currentBytesAvailable += bytesRead; + } + } + + /* + * We have to determine whether the response is an entry, with + * application-specific tag LDAP_SEARCHRESPONSEENTRY_TYPE, or a + * resultCode, with application tag LDAP_SEARCHRESPONSERESULT_TYPE. + * First, we have to figure out where to look for the tag. + */ + + /* Is the message length short form (one octet) or long form? */ + if ((msgBuf[1] & 0x80) != 0) { + sizeofLength = msgBuf[1] & 0x7F; + for (dataIndex = 0; dataIndex < sizeofLength; dataIndex++) { + messageLength = + (messageLength << 8) + msgBuf[dataIndex + 2]; + } + } else { + messageLength = msgBuf[1]; + } + + /* How many bytes did the messageID require? */ + messageIdLen = msgBuf[dataIndex + 3]; + + messageChar = msgBuf[dataIndex + messageIdLen + 4]; + + /* Are we looking at an Entry message or a ResultCode message? */ + if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | + LDAP_SEARCHRESPONSEENTRY_TYPE) == messageChar) { + + messageType = LDAP_SEARCHRESPONSEENTRY_TYPE; + + } else if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | + LDAP_SEARCHRESPONSERESULT_TYPE) == messageChar) { + + messageType = LDAP_SEARCHRESPONSERESULT_TYPE; + + } else { + + PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE); + + } + + /* + * messageLength is the length from (tag, length, value). + * We have to allocate space for the tag and length bits too. + */ + PKIX_CHECK(pkix_pl_LdapResponse_Create + (messageType, + messageLength + dataIndex + 2, + client->currentBytesAvailable, + msgBuf, + &bytesProcessed, + &(client->currentResponse), + plContext), + PKIX_LDAPRESPONSECREATEFAILED); + + client->currentBytesAvailable -= bytesProcessed; + + PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete + (client, bytesProcessed, pKeepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED); + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_RecvNonInitial + * DESCRIPTION: + * + * This function processes the contents of buffers, after the first, of a + * received LDAP-protocol message for the CertStore embodied in the + * LdapDefaultClient "client", and stores in "pKeepGoing" a flag indicating + * whether processing can continue without further input. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pKeepGoing" + * The address at which the Boolean state machine flag is stored to + * indicate whether processing can continue without further input. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_RecvNonInitial( + PKIX_PL_LdapDefaultClient *client, + PKIX_Boolean *pKeepGoing, + void *plContext) +{ + + PKIX_UInt32 bytesProcessed = 0; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvNonInitial"); + PKIX_NULLCHECK_TWO(client, pKeepGoing); + + PKIX_CHECK(pkix_pl_LdapResponse_Append + (client->currentResponse, + client->currentBytesAvailable, + client->currentInPtr, + &bytesProcessed, + plContext), + PKIX_LDAPRESPONSEAPPENDFAILED); + + client->currentBytesAvailable -= bytesProcessed; + + PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete + (client, bytesProcessed, pKeepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED); + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_Dispatch + * DESCRIPTION: + * + * This function is the state machine dispatcher for the CertStore embodied in + * the LdapDefaultClient pointed to by "client". Results are returned by + * changes to various fields in the context. + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_Dispatch( + PKIX_PL_LdapDefaultClient *client, + void *plContext) +{ + PKIX_UInt32 bytesTransferred = 0; + PKIX_Boolean keepGoing = PKIX_TRUE; + + PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Dispatch"); + PKIX_NULLCHECK_ONE(client); + + while (keepGoing) { + switch (client->connectStatus) { + case CONNECT_PENDING: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_ConnectContinue + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTCONNECTCONTINUEFAILED); + break; + case CONNECTED: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_Bind + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTBINDFAILED); + break; + case BIND_PENDING: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_BindContinue + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTBINDCONTINUEFAILED); + break; + case BIND_RESPONSE: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_BindResponse + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTBINDRESPONSEFAILED); + break; + case BIND_RESPONSE_PENDING: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_BindResponseContinue + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTBINDRESPONSECONTINUEFAILED); + break; + case BOUND: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_Send + (client, &keepGoing, &bytesTransferred, plContext), + PKIX_LDAPDEFAULTCLIENTSENDFAILED); + break; + case SEND_PENDING: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_SendContinue + (client, &keepGoing, &bytesTransferred, plContext), + PKIX_LDAPDEFAULTCLIENTSENDCONTINUEFAILED); + break; + case RECV: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_Recv + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTRECVFAILED); + break; + case RECV_PENDING: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_RecvContinue + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTRECVCONTINUEFAILED); + break; + case RECV_INITIAL: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_RecvInitial + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTRECVINITIALFAILED); + break; + case RECV_NONINITIAL: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_RecvNonInitial + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTRECVNONINITIALFAILED); + break; + case ABANDON_PENDING: + PKIX_CHECK + (pkix_pl_LdapDefaultClient_AbandonContinue + (client, &keepGoing, plContext), + PKIX_LDAPDEFAULTCLIENTABANDONCONTINUEFAILED); + break; + default: + PKIX_ERROR(PKIX_LDAPCERTSTOREINILLEGALSTATE); + } + } + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_MakeAndFilter + * DESCRIPTION: + * + * This function allocates space from the arena pointed to by "arena" to + * construct a filter that will match components of the X500Name pointed to by + * XXX... + * + * PARAMETERS: + * "arena" + * The address of the PLArenaPool used in creating the filter. Must be + * non-NULL. + * "nameComponent" + * The address of a NULL-terminated list of LDAPNameComponents + * Must be non-NULL. + * "pFilter" + * The address at which the result is stored. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_MakeAndFilter( + PLArenaPool *arena, + LDAPNameComponent **nameComponents, + LDAPFilter **pFilter, + void *plContext) +{ + LDAPFilter **setOfFilter; + LDAPFilter *andFilter = NULL; + LDAPFilter *currentFilter = NULL; + PKIX_UInt32 componentsPresent = 0; + void *v = NULL; + unsigned char *component = NULL; + LDAPNameComponent **componentP = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_LdapDefaultClient_MakeAndFilter"); + PKIX_NULLCHECK_THREE(arena, nameComponents, pFilter); + + /* count how many components we were provided */ + for (componentP = nameComponents, componentsPresent = 0; + *(componentP++) != NULL; + componentsPresent++) {} + + /* Space for (componentsPresent + 1) pointers to LDAPFilter */ + PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc, + (arena, (componentsPresent + 1)*sizeof(LDAPFilter *))); + setOfFilter = (LDAPFilter **)v; + + /* Space for AndFilter and <componentsPresent> EqualFilters */ + PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray, + (arena, LDAPFilter, componentsPresent + 1)); + setOfFilter[0] = (LDAPFilter *)v; + + /* Claim the first array element for the ANDFilter */ + andFilter = setOfFilter[0]; + + /* Set ANDFilter to point to the first EqualFilter pointer */ + andFilter->selector = LDAP_ANDFILTER_TYPE; + andFilter->filter.andFilter.filters = setOfFilter; + + currentFilter = andFilter + 1; + + for (componentP = nameComponents, componentsPresent = 0; + *(componentP) != NULL; componentP++) { + setOfFilter[componentsPresent++] = currentFilter; + currentFilter->selector = LDAP_EQUALFILTER_TYPE; + component = (*componentP)->attrType; + currentFilter->filter.equalFilter.attrType.data = component; + currentFilter->filter.equalFilter.attrType.len = + PL_strlen((const char *)component); + component = (*componentP)->attrValue; + currentFilter->filter.equalFilter.attrValue.data = component; + currentFilter->filter.equalFilter.attrValue.len = + PL_strlen((const char *)component); + currentFilter++; + } + + setOfFilter[componentsPresent] = NULL; + + *pFilter = andFilter; + + PKIX_RETURN(CERTSTORE); + +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_InitiateRequest + * DESCRIPTION: + * + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "requestParams" + * The address of an LdapClientParams object. Must be non-NULL. + * "pPollDesc" + * The location where the address of the PRPollDesc is stored, if the + * client returns with I/O pending. + * "pResponse" + * The address where the List of LDAPResponses, or NULL for an + * unfinished request, is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_InitiateRequest( + PKIX_PL_LdapClient *genericClient, + LDAPRequestParams *requestParams, + void **pPollDesc, + PKIX_List **pResponse, + void *plContext) +{ + PKIX_List *searchResponseList = NULL; + SECItem *encoded = NULL; + LDAPFilter *filter = NULL; + PKIX_PL_LdapDefaultClient *client = 0; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, + "pkix_pl_LdapDefaultClient_InitiateRequest"); + PKIX_NULLCHECK_FOUR(genericClient, requestParams, pPollDesc, pResponse); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)genericClient, + PKIX_LDAPDEFAULTCLIENT_TYPE, + plContext), + PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT); + + client = (PKIX_PL_LdapDefaultClient *)genericClient; + + PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAndFilter + (client->arena, requestParams->nc, &filter, plContext), + PKIX_LDAPDEFAULTCLIENTMAKEANDFILTERFAILED); + + PKIX_CHECK(pkix_pl_LdapRequest_Create + (client->arena, + client->messageID++, + requestParams->baseObject, + requestParams->scope, + requestParams->derefAliases, + requestParams->sizeLimit, + requestParams->timeLimit, + PKIX_FALSE, /* attrs only */ + filter, + requestParams->attributes, + &client->currentRequest, + plContext), + PKIX_LDAPREQUESTCREATEFAILED); + + /* check hashtable for matching request */ + PKIX_CHECK(PKIX_PL_HashTable_Lookup + (client->cachePtr, + (PKIX_PL_Object *)(client->currentRequest), + (PKIX_PL_Object **)&searchResponseList, + plContext), + PKIX_HASHTABLELOOKUPFAILED); + + if (searchResponseList != NULL) { + *pPollDesc = NULL; + *pResponse = searchResponseList; + PKIX_DECREF(client->currentRequest); + goto cleanup; + } + + /* It wasn't cached. We'll have to actually send it. */ + + PKIX_CHECK(pkix_pl_LdapRequest_GetEncoded + (client->currentRequest, &encoded, plContext), + PKIX_LDAPREQUESTGETENCODEDFAILED); + + client->sendBuf = encoded->data; + client->bytesToWrite = encoded->len; + + PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext), + PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED); + + /* + * It's not enough that we may be done with a particular read. + * We're still processing the transaction until we've gotten the + * SearchResponseResult message and returned to the BOUND state. + * Otherwise we must still have a read pending, and must hold off + * on returning results. + */ + if ((client->connectStatus == BOUND) && + (client->entriesFound != NULL)) { + *pPollDesc = NULL; + *pResponse = client->entriesFound; + client->entriesFound = NULL; + PKIX_DECREF(client->currentRequest); + } else { + *pPollDesc = &client->pollDesc; + *pResponse = NULL; + } + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); + +} + +/* + * FUNCTION: pkix_pl_LdapDefaultClient_ResumeRequest + * DESCRIPTION: + * + * + * PARAMETERS: + * "client" + * The address of the LdapDefaultClient object. Must be non-NULL. + * "pPollDesc" + * The location where the address of the PRPollDesc is stored, if the + * client returns with I/O pending. + * "pResponse" + * The address where the List of LDAPResponses, or NULL for an + * unfinished request, is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a LdapDefaultClient Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapDefaultClient_ResumeRequest( + PKIX_PL_LdapClient *genericClient, + void **pPollDesc, + PKIX_List **pResponse, + void *plContext) +{ + PKIX_PL_LdapDefaultClient *client = 0; + + PKIX_ENTER + (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_ResumeRequest"); + PKIX_NULLCHECK_THREE(genericClient, pPollDesc, pResponse); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)genericClient, + PKIX_LDAPDEFAULTCLIENT_TYPE, + plContext), + PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT); + + client = (PKIX_PL_LdapDefaultClient *)genericClient; + + PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext), + PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED); + + /* + * It's not enough that we may be done with a particular read. + * We're still processing the transaction until we've gotten the + * SearchResponseResult message and returned to the BOUND state. + * Otherwise we must still have a read pending, and must hold off + * on returning results. + */ + if ((client->connectStatus == BOUND) && + (client->entriesFound != NULL)) { + *pPollDesc = NULL; + *pResponse = client->entriesFound; + client->entriesFound = NULL; + PKIX_DECREF(client->currentRequest); + } else { + *pPollDesc = &client->pollDesc; + *pResponse = NULL; + } + +cleanup: + + PKIX_RETURN(LDAPDEFAULTCLIENT); + +} + +/* --Public-LdapDefaultClient-Functions----------------------------------- */ + +/* + * FUNCTION: PKIX_PL_LdapDefaultClient_AbandonRequest + * DESCRIPTION: + * + * This function creates and sends an LDAP-protocol "Abandon" message to the + * server connected to the LdapDefaultClient pointed to by "client". + * + * PARAMETERS: + * "client" + * The LdapDefaultClient whose connection is to be abandoned. Must be + * non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +PKIX_PL_LdapDefaultClient_AbandonRequest( + PKIX_PL_LdapDefaultClient *client, + void *plContext) +{ + PKIX_Int32 bytesWritten = 0; + PKIX_PL_Socket_Callback *callbackList = NULL; + SECItem *encoded = NULL; + + PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapDefaultClient_AbandonRequest"); + PKIX_NULLCHECK_ONE(client); + + if (client->connectStatus == RECV_PENDING) { + PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAbandon + (client->arena, + (client->messageID) - 1, + &encoded, + plContext), + PKIX_LDAPDEFAULTCLIENTMAKEABANDONFAILED); + + callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); + PKIX_CHECK(callbackList->sendCallback + (client->clientSocket, + encoded->data, + encoded->len, + &bytesWritten, + plContext), + PKIX_SOCKETSENDFAILED); + + if (bytesWritten < 0) { + client->connectStatus = ABANDON_PENDING; + } else { + client->connectStatus = BOUND; + } + } + + PKIX_DECREF(client->entriesFound); + PKIX_DECREF(client->currentRequest); + PKIX_DECREF(client->currentResponse); + +cleanup: + + PKIX_DECREF(client); + + PKIX_RETURN(CERTSTORE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h new file mode 100644 index 0000000000..4abe043281 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h @@ -0,0 +1,82 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldapdefaultclient.h + * + * LDAPDefaultClient Object Type Definition + * + */ + +#ifndef _PKIX_PL_LDAPDEFAULTCLIENT_H +#define _PKIX_PL_LDAPDEFAULTCLIENT_H + +#include "pkix_pl_ldapt.h" +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * At the time of this version, there are unresolved questions about the LDAP + * protocol. Although RFC1777 describes a BIND and UNBIND message, it is not + * clear whether they are appropriate to this application. We have tested only + * using servers that do not expect authentication, and that reject BIND + * messages. It is not clear what values might be appropriate for the bindname + * and authentication fields, which are currently implemented as char strings + * supplied by the caller. (If this changes, the API and possibly the templates + * will have to change.) Therefore the LDAPClient_Create API contains a + * BindAPI structure, a union, which will have to be revised and extended when + * this area of the protocol is better understood. + * + */ + +typedef enum { + CONNECT_PENDING, + CONNECTED, + BIND_PENDING, + BIND_RESPONSE, + BIND_RESPONSE_PENDING, + BOUND, + SEND_PENDING, + RECV, + RECV_PENDING, + RECV_INITIAL, + RECV_NONINITIAL, + ABANDON_PENDING +} LdapClientConnectStatus; + +struct PKIX_PL_LdapDefaultClientStruct { + PKIX_PL_LdapClient vtable; + LdapClientConnectStatus connectStatus; + PKIX_UInt32 messageID; + PKIX_PL_HashTable *cachePtr; + PKIX_PL_Socket *clientSocket; + PRPollDesc pollDesc; + void *callbackList; /* cast this to (PKIX_PL_Socket_Callback *) */ + LDAPBindAPI *bindAPI; + PLArenaPool *arena; + PRTime lastIO; + void *sendBuf; + PKIX_UInt32 bytesToWrite; + void *rcvBuf; + PKIX_UInt32 capacity; + void *currentInPtr; + PKIX_UInt32 currentBytesAvailable; + void *bindMsg; + PKIX_UInt32 bindMsgLen; + PKIX_List *entriesFound; + PKIX_PL_LdapRequest *currentRequest; + PKIX_PL_LdapResponse *currentResponse; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_LdapDefaultClient_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_LDAPDEFAULTCLIENT_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c new file mode 100644 index 0000000000..4546e339a5 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c @@ -0,0 +1,757 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldaprequest.c + * + */ + +#include "pkix_pl_ldaprequest.h" + +/* --Private-LdapRequest-Functions------------------------------------- */ + +/* Note: lengths do not include the NULL terminator */ +static const char caAttr[] = "caCertificate;binary"; +static unsigned int caAttrLen = sizeof(caAttr) - 1; +static const char uAttr[] = "userCertificate;binary"; +static unsigned int uAttrLen = sizeof(uAttr) - 1; +static const char ccpAttr[] = "crossCertificatePair;binary"; +static unsigned int ccpAttrLen = sizeof(ccpAttr) - 1; +static const char crlAttr[] = "certificateRevocationList;binary"; +static unsigned int crlAttrLen = sizeof(crlAttr) - 1; +static const char arlAttr[] = "authorityRevocationList;binary"; +static unsigned int arlAttrLen = sizeof(arlAttr) - 1; + +/* + * XXX If this function were moved into pkix_pl_ldapcertstore.c then all of + * LdapRequest and LdapResponse could be considered part of the LDAP client. + * But the constants, above, would have to be copied as well, and they are + * also needed in pkix_pl_LdapRequest_EncodeAttrs. So there would have to be + * two copies. + */ + +/* + * FUNCTION: pkix_pl_LdapRequest_AttrTypeToBit + * DESCRIPTION: + * + * This function creates an attribute mask bit corresponding to the SECItem + * pointed to by "attrType", storing the result at "pAttrBit". The comparison + * is case-insensitive. If "attrType" does not match any of the known types, + * zero is stored at "pAttrBit". + * + * PARAMETERS + * "attrType" + * The address of the SECItem whose string contents are to be compared to + * the various known attribute types. Must be non-NULL. + * "pAttrBit" + * The address where the result is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapRequest Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapRequest_AttrTypeToBit( + SECItem *attrType, + LdapAttrMask *pAttrBit, + void *plContext) +{ + LdapAttrMask attrBit = 0; + unsigned int attrLen = 0; + const char *s = NULL; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_AttrTypeToBit"); + PKIX_NULLCHECK_TWO(attrType, pAttrBit); + + s = (const char *)attrType->data; + attrLen = attrType->len; + + /* + * Taking note of the fact that all of the comparand strings are + * different lengths, we do a slight optimization. If a string + * length matches but the string does not match, we skip comparing + * to the other strings. If new strings are added to the comparand + * list, and any are of equal length, be careful to change the + * grouping of tests accordingly. + */ + if (attrLen == caAttrLen) { + if (PORT_Strncasecmp(caAttr, s, attrLen) == 0) { + attrBit = LDAPATTR_CACERT; + } + } else if (attrLen == uAttrLen) { + if (PORT_Strncasecmp(uAttr, s, attrLen) == 0) { + attrBit = LDAPATTR_USERCERT; + } + } else if (attrLen == ccpAttrLen) { + if (PORT_Strncasecmp(ccpAttr, s, attrLen) == 0) { + attrBit = LDAPATTR_CROSSPAIRCERT; + } + } else if (attrLen == crlAttrLen) { + if (PORT_Strncasecmp(crlAttr, s, attrLen) == 0) { + attrBit = LDAPATTR_CERTREVLIST; + } + } else if (attrLen == arlAttrLen) { + if (PORT_Strncasecmp(arlAttr, s, attrLen) == 0) { + attrBit = LDAPATTR_AUTHREVLIST; + } + } + + *pAttrBit = attrBit; + + PKIX_RETURN(LDAPREQUEST); +} + +/* + * FUNCTION: pkix_pl_LdapRequest_AttrStringToBit + * DESCRIPTION: + * + * This function creates an attribute mask bit corresponding to the null- + * terminated string pointed to by "attrString", storing the result at + * "pAttrBit". The comparison is case-insensitive. If "attrString" does not + * match any of the known types, zero is stored at "pAttrBit". + * + * PARAMETERS + * "attrString" + * The address of the null-terminated string whose contents are to be compared to + * the various known attribute types. Must be non-NULL. + * "pAttrBit" + * The address where the result is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapRequest Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapRequest_AttrStringToBit( + char *attrString, + LdapAttrMask *pAttrBit, + void *plContext) +{ + LdapAttrMask attrBit = 0; + unsigned int attrLen = 0; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_AttrStringToBit"); + PKIX_NULLCHECK_TWO(attrString, pAttrBit); + + attrLen = PL_strlen(attrString); + + /* + * Taking note of the fact that all of the comparand strings are + * different lengths, we do a slight optimization. If a string + * length matches but the string does not match, we skip comparing + * to the other strings. If new strings are added to the comparand + * list, and any are of equal length, be careful to change the + * grouping of tests accordingly. + */ + if (attrLen == caAttrLen) { + if (PORT_Strncasecmp(caAttr, attrString, attrLen) == 0) { + attrBit = LDAPATTR_CACERT; + } + } else if (attrLen == uAttrLen) { + if (PORT_Strncasecmp(uAttr, attrString, attrLen) == 0) { + attrBit = LDAPATTR_USERCERT; + } + } else if (attrLen == ccpAttrLen) { + if (PORT_Strncasecmp(ccpAttr, attrString, attrLen) == 0) { + attrBit = LDAPATTR_CROSSPAIRCERT; + } + } else if (attrLen == crlAttrLen) { + if (PORT_Strncasecmp(crlAttr, attrString, attrLen) == 0) { + attrBit = LDAPATTR_CERTREVLIST; + } + } else if (attrLen == arlAttrLen) { + if (PORT_Strncasecmp(arlAttr, attrString, attrLen) == 0) { + attrBit = LDAPATTR_AUTHREVLIST; + } + } + + *pAttrBit = attrBit; + + PKIX_RETURN(LDAPREQUEST); +} + +/* + * FUNCTION: pkix_pl_LdapRequest_EncodeAttrs + * DESCRIPTION: + * + * This function obtains the attribute mask bits from the LdapRequest pointed + * to by "request", creates the corresponding array of AttributeTypes for the + * encoding of the SearchRequest message. + * + * PARAMETERS + * "request" + * The address of the LdapRequest whose attributes are to be encoded. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapRequest Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_LdapRequest_EncodeAttrs( + PKIX_PL_LdapRequest *request, + void *plContext) +{ + SECItem **attrArray = NULL; + PKIX_UInt32 attrIndex = 0; + LdapAttrMask attrBits; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_EncodeAttrs"); + PKIX_NULLCHECK_ONE(request); + + /* construct "attrs" according to bits in request->attrBits */ + attrBits = request->attrBits; + attrArray = request->attrArray; + if ((attrBits & LDAPATTR_CACERT) == LDAPATTR_CACERT) { + attrArray[attrIndex] = &(request->attributes[attrIndex]); + request->attributes[attrIndex].type = siAsciiString; + request->attributes[attrIndex].data = (unsigned char *)caAttr; + request->attributes[attrIndex].len = caAttrLen; + attrIndex++; + } + if ((attrBits & LDAPATTR_USERCERT) == LDAPATTR_USERCERT) { + attrArray[attrIndex] = &(request->attributes[attrIndex]); + request->attributes[attrIndex].type = siAsciiString; + request->attributes[attrIndex].data = (unsigned char *)uAttr; + request->attributes[attrIndex].len = uAttrLen; + attrIndex++; + } + if ((attrBits & LDAPATTR_CROSSPAIRCERT) == LDAPATTR_CROSSPAIRCERT) { + attrArray[attrIndex] = &(request->attributes[attrIndex]); + request->attributes[attrIndex].type = siAsciiString; + request->attributes[attrIndex].data = (unsigned char *)ccpAttr; + request->attributes[attrIndex].len = ccpAttrLen; + attrIndex++; + } + if ((attrBits & LDAPATTR_CERTREVLIST) == LDAPATTR_CERTREVLIST) { + attrArray[attrIndex] = &(request->attributes[attrIndex]); + request->attributes[attrIndex].type = siAsciiString; + request->attributes[attrIndex].data = (unsigned char *)crlAttr; + request->attributes[attrIndex].len = crlAttrLen; + attrIndex++; + } + if ((attrBits & LDAPATTR_AUTHREVLIST) == LDAPATTR_AUTHREVLIST) { + attrArray[attrIndex] = &(request->attributes[attrIndex]); + request->attributes[attrIndex].type = siAsciiString; + request->attributes[attrIndex].data = (unsigned char *)arlAttr; + request->attributes[attrIndex].len = arlAttrLen; + attrIndex++; + } + attrArray[attrIndex] = (SECItem *)NULL; + + PKIX_RETURN(LDAPREQUEST); +} + +/* + * FUNCTION: pkix_pl_LdapRequest_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapRequest_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPREQUEST_TYPE, plContext), + PKIX_OBJECTNOTLDAPREQUEST); + + /* + * All dynamic fields in an LDAPRequest are allocated + * in an arena, and will be freed when the arena is destroyed. + */ + +cleanup: + + PKIX_RETURN(LDAPREQUEST); +} + +/* + * FUNCTION: pkix_pl_LdapRequest_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapRequest_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_UInt32 dataLen = 0; + PKIX_UInt32 dindex = 0; + PKIX_UInt32 sizeOfLength = 0; + PKIX_UInt32 idLen = 0; + const unsigned char *msgBuf = NULL; + PKIX_PL_LdapRequest *ldapRq = NULL; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPREQUEST_TYPE, plContext), + PKIX_OBJECTNOTLDAPREQUEST); + + ldapRq = (PKIX_PL_LdapRequest *)object; + + *pHashcode = 0; + + /* + * Two requests that differ only in msgnum are a match! Therefore, + * start hashcoding beyond the encoded messageID field. + */ + if (ldapRq->encoded) { + msgBuf = (const unsigned char *)ldapRq->encoded->data; + /* Is message length short form (one octet) or long form? */ + if ((msgBuf[1] & 0x80) != 0) { + sizeOfLength = msgBuf[1] & 0x7F; + for (dindex = 0; dindex < sizeOfLength; dindex++) { + dataLen = (dataLen << 8) + msgBuf[dindex + 2]; + } + } else { + dataLen = msgBuf[1]; + } + + /* How many bytes for the messageID? (Assume short form) */ + idLen = msgBuf[dindex + 3] + 2; + dindex += idLen; + dataLen -= idLen; + msgBuf = &msgBuf[dindex + 2]; + + PKIX_CHECK(pkix_hash(msgBuf, dataLen, pHashcode, plContext), + PKIX_HASHFAILED); + } + +cleanup: + + PKIX_RETURN(LDAPREQUEST); + +} + +/* + * FUNCTION: pkix_pl_LdapRequest_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapRequest_Equals( + PKIX_PL_Object *firstObj, + PKIX_PL_Object *secondObj, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_LdapRequest *firstReq = NULL; + PKIX_PL_LdapRequest *secondReq = NULL; + PKIX_UInt32 secondType = 0; + PKIX_UInt32 firstLen = 0; + const unsigned char *firstData = NULL; + const unsigned char *secondData = NULL; + PKIX_UInt32 sizeOfLength = 0; + PKIX_UInt32 dindex = 0; + PKIX_UInt32 i = 0; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Equals"); + PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); + + /* test that firstObj is a LdapRequest */ + PKIX_CHECK(pkix_CheckType(firstObj, PKIX_LDAPREQUEST_TYPE, plContext), + PKIX_FIRSTOBJARGUMENTNOTLDAPREQUEST); + + /* + * Since we know firstObj is a LdapRequest, if both references are + * identical, they must be equal + */ + if (firstObj == secondObj){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObj isn't a LdapRequest, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObj, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_LDAPREQUEST_TYPE) { + goto cleanup; + } + + firstReq = (PKIX_PL_LdapRequest *)firstObj; + secondReq = (PKIX_PL_LdapRequest *)secondObj; + + /* If either lacks an encoded string, they cannot be compared */ + if (!(firstReq->encoded) || !(secondReq->encoded)) { + goto cleanup; + } + + if (firstReq->encoded->len != secondReq->encoded->len) { + goto cleanup; + } + + firstData = (const unsigned char *)firstReq->encoded->data; + secondData = (const unsigned char *)secondReq->encoded->data; + + /* + * Two requests that differ only in msgnum are equal! Therefore, + * start the byte comparison beyond the encoded messageID field. + */ + + /* Is message length short form (one octet) or long form? */ + if ((firstData[1] & 0x80) != 0) { + sizeOfLength = firstData[1] & 0x7F; + for (dindex = 0; dindex < sizeOfLength; dindex++) { + firstLen = (firstLen << 8) + firstData[dindex + 2]; + } + } else { + firstLen = firstData[1]; + } + + /* How many bytes for the messageID? (Assume short form) */ + i = firstData[dindex + 3] + 2; + dindex += i; + firstLen -= i; + firstData = &firstData[dindex + 2]; + + /* + * In theory, we have to calculate where the second message data + * begins by checking its length encodings. But if these messages + * are equal, we can re-use the calculation we already did. If they + * are not equal, the byte comparisons will surely fail. + */ + + secondData = &secondData[dindex + 2]; + + for (i = 0; i < firstLen; i++) { + if (firstData[i] != secondData[i]) { + goto cleanup; + } + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(LDAPREQUEST); +} + +/* + * FUNCTION: pkix_pl_LdapRequest_RegisterSelf + * DESCRIPTION: + * Registers PKIX_LDAPREQUEST_TYPE and its related functions with + * systemClasses[] + * PARAMETERS: + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_LdapRequest_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_RegisterSelf"); + + entry.description = "LdapRequest"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_LdapRequest); + entry.destructor = pkix_pl_LdapRequest_Destroy; + entry.equalsFunction = pkix_pl_LdapRequest_Equals; + entry.hashcodeFunction = pkix_pl_LdapRequest_Hashcode; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_LDAPREQUEST_TYPE] = entry; + + PKIX_RETURN(LDAPREQUEST); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_LdapRequest_Create + * DESCRIPTION: + * + * This function creates an LdapRequest using the PLArenaPool pointed to by + * "arena", a message number whose value is "msgnum", a base object pointed to + * by "issuerDN", a scope whose value is "scope", a derefAliases flag whose + * value is "derefAliases", a sizeLimit whose value is "sizeLimit", a timeLimit + * whose value is "timeLimit", an attrsOnly flag whose value is "attrsOnly", a + * filter whose value is "filter", and attribute bits whose value is + * "attrBits"; storing the result at "pRequestMsg". + * + * See pkix_pl_ldaptemplates.c (and below) for the ASN.1 representation of + * message components, and see pkix_pl_ldapt.h for data types. + * + * PARAMETERS + * "arena" + * The address of the PLArenaPool to be used in the encoding. Must be + * non-NULL. + * "msgnum" + * The UInt32 message number to be used for the messageID component of the + * LDAP message exchange. + * "issuerDN" + * The address of the string to be used for the baseObject component of the + * LDAP SearchRequest message. Must be non-NULL. + * "scope" + * The (enumerated) ScopeType to be used for the scope component of the + * LDAP SearchRequest message + * "derefAliases" + * The (enumerated) DerefType to be used for the derefAliases component of + * the LDAP SearchRequest message + * "sizeLimit" + * The UInt32 value to be used for the sizeLimit component of the LDAP + * SearchRequest message + * "timeLimit" + * The UInt32 value to be used for the timeLimit component of the LDAP + * SearchRequest message + * "attrsOnly" + * The Boolean value to be used for the attrsOnly component of the LDAP + * SearchRequest message + * "filter" + * The filter to be used for the filter component of the LDAP + * SearchRequest message + * "attrBits" + * The LdapAttrMask bits indicating the attributes to be included in the + * attributes sequence of the LDAP SearchRequest message + * "pRequestMsg" + * The address at which the address of the LdapRequest is stored. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapRequest Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +/* + * SearchRequest ::= + * [APPLICATION 3] SEQUENCE { + * baseObject LDAPDN, + * scope ENUMERATED { + * baseObject (0), + * singleLevel (1), + * wholeSubtree (2) + * }, + * derefAliases ENUMERATED { + * neverDerefAliases (0), + * derefInSearching (1), + * derefFindingBaseObj (2), + * alwaysDerefAliases (3) + * }, + * sizeLimit INTEGER (0 .. MAXINT), + * -- value of 0 implies no sizeLimit + * timeLimit INTEGER (0 .. MAXINT), + * -- value of 0 implies no timeLimit + * attrsOnly BOOLEAN, + * -- TRUE, if only attributes (without values) + * -- to be returned + * filter Filter, + * attributes SEQUENCE OF AttributeType + * } + * + * Filter ::= + * CHOICE { + * and [0] SET OF Filter, + * or [1] SET OF Filter, + * not [2] Filter, + * equalityMatch [3] AttributeValueAssertion, + * substrings [4] SubstringFilter, + * greaterOrEqual [5] AttributeValueAssertion, + * lessOrEqual [6] AttributeValueAssertion, + * present [7] AttributeType, + * approxMatch [8] AttributeValueAssertion + * } + * + * SubstringFilter ::= + * SEQUENCE { + * type AttributeType, + * SEQUENCE OF CHOICE { + * initial [0] LDAPString, + * any [1] LDAPString, + * final [2] LDAPString, + * } + * } + * + * AttributeValueAssertion ::= + * SEQUENCE { + * attributeType AttributeType, + * attributeValue AttributeValue, + * } + * + * AttributeValue ::= OCTET STRING + * + * AttributeType ::= LDAPString + * -- text name of the attribute, or dotted + * -- OID representation + * + * LDAPDN ::= LDAPString + * + * LDAPString ::= OCTET STRING + * + */ +PKIX_Error * +pkix_pl_LdapRequest_Create( + PLArenaPool *arena, + PKIX_UInt32 msgnum, + char *issuerDN, + ScopeType scope, + DerefType derefAliases, + PKIX_UInt32 sizeLimit, + PKIX_UInt32 timeLimit, + char attrsOnly, + LDAPFilter *filter, + LdapAttrMask attrBits, + PKIX_PL_LdapRequest **pRequestMsg, + void *plContext) +{ + LDAPMessage msg; + LDAPSearch *search; + PKIX_PL_LdapRequest *ldapRequest = NULL; + char scopeTypeAsChar; + char derefAliasesTypeAsChar; + SECItem *attrArray[MAX_LDAPATTRS + 1]; + + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Create"); + PKIX_NULLCHECK_THREE(arena, issuerDN, pRequestMsg); + + /* create a PKIX_PL_LdapRequest object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_LDAPREQUEST_TYPE, + sizeof (PKIX_PL_LdapRequest), + (PKIX_PL_Object **)&ldapRequest, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + ldapRequest->arena = arena; + ldapRequest->msgnum = msgnum; + ldapRequest->issuerDN = issuerDN; + ldapRequest->scope = scope; + ldapRequest->derefAliases = derefAliases; + ldapRequest->sizeLimit = sizeLimit; + ldapRequest->timeLimit = timeLimit; + ldapRequest->attrsOnly = attrsOnly; + ldapRequest->filter = filter; + ldapRequest->attrBits = attrBits; + + ldapRequest->attrArray = attrArray; + + PKIX_CHECK(pkix_pl_LdapRequest_EncodeAttrs + (ldapRequest, plContext), + PKIX_LDAPREQUESTENCODEATTRSFAILED); + + PKIX_PL_NSSCALL + (LDAPREQUEST, PORT_Memset, (&msg, 0, sizeof (LDAPMessage))); + + msg.messageID.type = siUnsignedInteger; + msg.messageID.data = (void*)&msgnum; + msg.messageID.len = sizeof (msgnum); + + msg.protocolOp.selector = LDAP_SEARCH_TYPE; + + search = &(msg.protocolOp.op.searchMsg); + + search->baseObject.type = siAsciiString; + search->baseObject.data = (void *)issuerDN; + search->baseObject.len = PL_strlen(issuerDN); + scopeTypeAsChar = (char)scope; + search->scope.type = siUnsignedInteger; + search->scope.data = (void *)&scopeTypeAsChar; + search->scope.len = sizeof (scopeTypeAsChar); + derefAliasesTypeAsChar = (char)derefAliases; + search->derefAliases.type = siUnsignedInteger; + search->derefAliases.data = + (void *)&derefAliasesTypeAsChar; + search->derefAliases.len = + sizeof (derefAliasesTypeAsChar); + search->sizeLimit.type = siUnsignedInteger; + search->sizeLimit.data = (void *)&sizeLimit; + search->sizeLimit.len = sizeof (PKIX_UInt32); + search->timeLimit.type = siUnsignedInteger; + search->timeLimit.data = (void *)&timeLimit; + search->timeLimit.len = sizeof (PKIX_UInt32); + search->attrsOnly.type = siBuffer; + search->attrsOnly.data = (void *)&attrsOnly; + search->attrsOnly.len = sizeof (attrsOnly); + + PKIX_PL_NSSCALL + (LDAPREQUEST, + PORT_Memcpy, + (&search->filter, filter, sizeof (LDAPFilter))); + + search->attributes = attrArray; + + PKIX_PL_NSSCALLRV + (LDAPREQUEST, ldapRequest->encoded, SEC_ASN1EncodeItem, + (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate)); + + if (!(ldapRequest->encoded)) { + PKIX_ERROR(PKIX_FAILEDINENCODINGSEARCHREQUEST); + } + + *pRequestMsg = ldapRequest; + +cleanup: + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(ldapRequest); + } + + PKIX_RETURN(LDAPREQUEST); +} + +/* + * FUNCTION: pkix_pl_LdapRequest_GetEncoded + * DESCRIPTION: + * + * This function obtains the encoded message from the LdapRequest pointed to + * by "request", storing the result at "pRequestBuf". + * + * PARAMETERS + * "request" + * The address of the LdapRequest whose encoded message is to be + * retrieved. Must be non-NULL. + * "pRequestBuf" + * The address at which is stored the address of the encoded message. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapRequest Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapRequest_GetEncoded( + PKIX_PL_LdapRequest *request, + SECItem **pRequestBuf, + void *plContext) +{ + PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_GetEncoded"); + PKIX_NULLCHECK_TWO(request, pRequestBuf); + + *pRequestBuf = request->encoded; + + PKIX_RETURN(LDAPREQUEST); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h new file mode 100644 index 0000000000..1d05a9447e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h @@ -0,0 +1,86 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldaprequest.h + * + * LdapRequest Object Definitions + * + */ + +#ifndef _PKIX_PL_LDAPREQUEST_H +#define _PKIX_PL_LDAPREQUEST_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + USER_CERT, + CA_CERT, + CROSS_CERT, + CRL, + ARL, + DELTA_CRL +} PKIX_PL_LdapAttr; + +struct PKIX_PL_LdapRequestStruct{ + PLArenaPool *arena; + PKIX_UInt32 msgnum; + char *issuerDN; + ScopeType scope; + DerefType derefAliases; + PKIX_UInt32 sizeLimit; + PKIX_UInt32 timeLimit; + char attrsOnly; + LDAPFilter *filter; + LdapAttrMask attrBits; + SECItem attributes[MAX_LDAPATTRS]; + SECItem **attrArray; + SECItem *encoded; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_LdapRequest_Create( + PLArenaPool *arena, + PKIX_UInt32 msgnum, + char *issuerDN, + ScopeType scope, + DerefType derefAliases, + PKIX_UInt32 sizeLimit, + PKIX_UInt32 timeLimit, + char attrsOnly, + LDAPFilter *filter, + LdapAttrMask attrBits, + PKIX_PL_LdapRequest **pRequestMsg, + void *plContext); + +PKIX_Error * +pkix_pl_LdapRequest_AttrTypeToBit( + SECItem *attrType, + LdapAttrMask *pAttrBit, + void *plContext); + +PKIX_Error * +pkix_pl_LdapRequest_AttrStringToBit( + char *attrString, + LdapAttrMask *pAttrBit, + void *plContext); + +PKIX_Error * +pkix_pl_LdapRequest_GetEncoded( + PKIX_PL_LdapRequest *request, + SECItem **pRequestBuf, + void *plContext); + +PKIX_Error *pkix_pl_LdapRequest_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_LDAPREQUEST_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c new file mode 100644 index 0000000000..cd2543f3be --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c @@ -0,0 +1,786 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldapresponse.c + * + */ + +#include <fcntl.h> +#include "pkix_pl_ldapresponse.h" + +/* --Private-LdapResponse-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_LdapResponse_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapResponse_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_LdapResponse *ldapRsp = NULL; + LDAPMessage *m = NULL; + LDAPSearchResponseEntry *entry = NULL; + LDAPSearchResponseResult *result = NULL; + LDAPSearchResponseAttr **attributes = NULL; + LDAPSearchResponseAttr *attr = NULL; + SECItem **valp = NULL; + SECItem *val = NULL; + + PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext), + PKIX_OBJECTNOTLDAPRESPONSE); + + ldapRsp = (PKIX_PL_LdapResponse *)object; + + m = &ldapRsp->decoded; + + if (m->messageID.data != NULL) { + PR_Free(m->messageID.data); + } + + if (m->protocolOp.selector == + LDAP_SEARCHRESPONSEENTRY_TYPE) { + entry = &m->protocolOp.op.searchResponseEntryMsg; + if (entry->objectName.data != NULL) { + PR_Free(entry->objectName.data); + } + if (entry->attributes != NULL) { + for (attributes = entry->attributes; + *attributes != NULL; + attributes++) { + attr = *attributes; + PR_Free(attr->attrType.data); + for (valp = attr->val; *valp != NULL; valp++) { + val = *valp; + if (val->data != NULL) { + PR_Free(val->data); + } + PR_Free(val); + } + PR_Free(attr->val); + PR_Free(attr); + } + PR_Free(entry->attributes); + } + } else if (m->protocolOp.selector == + LDAP_SEARCHRESPONSERESULT_TYPE) { + result = &m->protocolOp.op.searchResponseResultMsg; + if (result->resultCode.data != NULL) { + PR_Free(result->resultCode.data); + } + } + + PKIX_FREE(ldapRsp->derEncoded.data); + +cleanup: + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapResponse_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_UInt32 dataLen = 0; + PKIX_UInt32 dindex = 0; + PKIX_UInt32 sizeOfLength = 0; + PKIX_UInt32 idLen = 0; + const unsigned char *msgBuf = NULL; + PKIX_PL_LdapResponse *ldapRsp = NULL; + + PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext), + PKIX_OBJECTNOTLDAPRESPONSE); + + ldapRsp = (PKIX_PL_LdapResponse *)object; + + *pHashcode = 0; + + /* + * Two responses that differ only in msgnum are a match! Therefore, + * start hashcoding beyond the encoded messageID field. + */ + if (ldapRsp->derEncoded.data) { + msgBuf = (const unsigned char *)ldapRsp->derEncoded.data; + /* Is message length short form (one octet) or long form? */ + if ((msgBuf[1] & 0x80) != 0) { + sizeOfLength = msgBuf[1] & 0x7F; + for (dindex = 0; dindex < sizeOfLength; dindex++) { + dataLen = (dataLen << 8) + msgBuf[dindex + 2]; + } + } else { + dataLen = msgBuf[1]; + } + + /* How many bytes for the messageID? (Assume short form) */ + idLen = msgBuf[dindex + 3] + 2; + dindex += idLen; + dataLen -= idLen; + msgBuf = &msgBuf[dindex + 2]; + + PKIX_CHECK(pkix_hash(msgBuf, dataLen, pHashcode, plContext), + PKIX_HASHFAILED); + } + +cleanup: + + PKIX_RETURN(LDAPRESPONSE); + +} + +/* + * FUNCTION: pkix_pl_LdapResponse_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_LdapResponse_Equals( + PKIX_PL_Object *firstObj, + PKIX_PL_Object *secondObj, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_LdapResponse *rsp1 = NULL; + PKIX_PL_LdapResponse *rsp2 = NULL; + PKIX_UInt32 secondType = 0; + PKIX_UInt32 firstLen = 0; + const unsigned char *firstData = NULL; + const unsigned char *secondData = NULL; + PKIX_UInt32 sizeOfLength = 0; + PKIX_UInt32 dindex = 0; + PKIX_UInt32 i = 0; + + PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Equals"); + PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); + + /* test that firstObj is a LdapResponse */ + PKIX_CHECK(pkix_CheckType(firstObj, PKIX_LDAPRESPONSE_TYPE, plContext), + PKIX_FIRSTOBJARGUMENTNOTLDAPRESPONSE); + + /* + * Since we know firstObj is a LdapResponse, if both references are + * identical, they must be equal + */ + if (firstObj == secondObj){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObj isn't a LdapResponse, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_LDAPRESPONSE_TYPE) { + goto cleanup; + } + + rsp1 = (PKIX_PL_LdapResponse *)firstObj; + rsp2 = (PKIX_PL_LdapResponse *)secondObj; + + /* If either lacks an encoded string, they cannot be compared */ + if (!(rsp1->derEncoded.data) || !(rsp2->derEncoded.data)) { + goto cleanup; + } + + if (rsp1->derEncoded.len != rsp2->derEncoded.len) { + goto cleanup; + } + + firstData = (const unsigned char *)rsp1->derEncoded.data; + secondData = (const unsigned char *)rsp2->derEncoded.data; + + /* + * Two responses that differ only in msgnum are equal! Therefore, + * start the byte comparison beyond the encoded messageID field. + */ + + /* Is message length short form (one octet) or long form? */ + if ((firstData[1] & 0x80) != 0) { + sizeOfLength = firstData[1] & 0x7F; + for (dindex = 0; dindex < sizeOfLength; dindex++) { + firstLen = (firstLen << 8) + firstData[dindex + 2]; + } + } else { + firstLen = firstData[1]; + } + + /* How many bytes for the messageID? (Assume short form) */ + i = firstData[dindex + 3] + 2; + dindex += i; + firstLen -= i; + firstData = &firstData[dindex + 2]; + + /* + * In theory, we have to calculate where the second message data + * begins by checking its length encodings. But if these messages + * are equal, we can re-use the calculation we already did. If they + * are not equal, the byte comparisons will surely fail. + */ + + secondData = &secondData[dindex + 2]; + + for (i = 0; i < firstLen; i++) { + if (firstData[i] != secondData[i]) { + goto cleanup; + } + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_RegisterSelf + * DESCRIPTION: + * Registers PKIX_LDAPRESPONSE_TYPE and its related functions with + * systemClasses[] + * PARAMETERS: + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_LdapResponse_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_RegisterSelf"); + + entry.description = "LdapResponse"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_LdapResponse); + entry.destructor = pkix_pl_LdapResponse_Destroy; + entry.equalsFunction = pkix_pl_LdapResponse_Equals; + entry.hashcodeFunction = pkix_pl_LdapResponse_Hashcode; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_LDAPRESPONSE_TYPE] = entry; + + PKIX_RETURN(LDAPRESPONSE); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_LdapResponse_Create + * DESCRIPTION: + * + * This function creates an LdapResponse for the LDAPMessageType provided in + * "responseType" and a buffer capacity provided by "totalLength". It copies + * into its buffer either "totalLength" or "bytesAvailable" bytes, whichever + * is less, from the buffer pointed to by "partialData", storing the number of + * bytes copied at "pBytesConsumed" and storing the address of the LdapResponse + * at "pLdapResponse". + * + * If a message is complete in a single I/O buffer, the LdapResponse will be + * complete when this function returns. If the message carries over into + * additional buffers, their contents will be added to the LdapResponse by + * susequent calls to pkix_pl_LdapResponse_Append. + * + * PARAMETERS + * "responseType" + * The value of the message type (LDAP_SEARCHRESPONSEENTRY_TYPE or + * LDAP_SEARCHRESPONSERESULT_TYPE) for the LdapResponse being created + * "totalLength" + * The UInt32 value for the total length of the encoded message to be + * stored in the LdapResponse + * "bytesAvailable" + * The UInt32 value for the number of bytes of data available in the + * current buffer. + * "partialData" + * The address from which data is to be copied. + * "pBytesConsumed" + * The address at which is stored the UInt32 number of bytes taken from the + * current buffer. If this number is less than "bytesAvailable", then bytes + * remain in the buffer for the next LdapResponse. Must be non-NULL. + * "pLdapResponse" + * The address where the created LdapResponse is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_Create( + LDAPMessageType responseType, + PKIX_UInt32 totalLength, + PKIX_UInt32 bytesAvailable, + void *partialData, + PKIX_UInt32 *pBytesConsumed, + PKIX_PL_LdapResponse **pLdapResponse, + void *plContext) +{ + PKIX_UInt32 bytesConsumed = 0; + PKIX_PL_LdapResponse *ldapResponse = NULL; + void *data = NULL; + + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Create"); + PKIX_NULLCHECK_ONE(pLdapResponse); + + if (bytesAvailable <= totalLength) { + bytesConsumed = bytesAvailable; + } else { + bytesConsumed = totalLength; + } + + /* create a PKIX_PL_LdapResponse object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_LDAPRESPONSE_TYPE, + sizeof (PKIX_PL_LdapResponse), + (PKIX_PL_Object **)&ldapResponse, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + ldapResponse->decoded.protocolOp.selector = responseType; + ldapResponse->totalLength = totalLength; + ldapResponse->partialLength = bytesConsumed; + + if (totalLength != 0){ + /* Alloc space for array */ + PKIX_NULLCHECK_ONE(partialData); + + PKIX_CHECK(PKIX_PL_Malloc + (totalLength, + &data, + plContext), + PKIX_MALLOCFAILED); + + PKIX_PL_NSSCALL + (LDAPRESPONSE, + PORT_Memcpy, + (data, partialData, bytesConsumed)); + } + + ldapResponse->derEncoded.type = siBuffer; + ldapResponse->derEncoded.data = data; + ldapResponse->derEncoded.len = totalLength; + *pBytesConsumed = bytesConsumed; + *pLdapResponse = ldapResponse; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(ldapResponse); + } + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_Append + * DESCRIPTION: + * + * This function updates the LdapResponse pointed to by "response" with up to + * "incrLength" from the buffer pointer to by "incrData", storing the number of + * bytes copied at "pBytesConsumed". + * + * PARAMETERS + * "response" + * The address of the LdapResponse being updated. Must be non-zero. + * "incrLength" + * The UInt32 value for the number of bytes of data available in the + * current buffer. + * "incrData" + * The address from which data is to be copied. + * "pBytesConsumed" + * The address at which is stored the UInt32 number of bytes taken from the + * current buffer. If this number is less than "incrLength", then bytes + * remain in the buffer for the next LdapResponse. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_Append( + PKIX_PL_LdapResponse *response, + PKIX_UInt32 incrLength, + void *incrData, + PKIX_UInt32 *pBytesConsumed, + void *plContext) +{ + PKIX_UInt32 newPartialLength = 0; + PKIX_UInt32 bytesConsumed = 0; + void *dest = NULL; + + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Append"); + PKIX_NULLCHECK_TWO(response, pBytesConsumed); + + if (incrLength > 0) { + + /* Calculate how many bytes we have room for. */ + bytesConsumed = + response->totalLength - response->partialLength; + + if (bytesConsumed > incrLength) { + bytesConsumed = incrLength; + } + + newPartialLength = response->partialLength + bytesConsumed; + + PKIX_NULLCHECK_ONE(incrData); + + dest = &(((char *)response->derEncoded.data)[ + response->partialLength]); + + PKIX_PL_NSSCALL + (LDAPRESPONSE, + PORT_Memcpy, + (dest, incrData, bytesConsumed)); + + response->partialLength = newPartialLength; + } + + *pBytesConsumed = bytesConsumed; + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_IsComplete + * DESCRIPTION: + * + * This function determines whether the LdapResponse pointed to by "response" + * contains all the data called for by the "totalLength" parameter provided + * when it was created, storing PKIX_TRUE at "pIsComplete" if so, and + * PKIX_FALSE otherwise. + * + * PARAMETERS + * "response" + * The address of the LdapResponse being evaluaTED. Must be non-zero. + * "incrLength" + * The UInt32 value for the number of bytes of data available in the + * current buffer. + * "incrData" + * The address from which data is to be copied. + * "pIsComplete" + * The address at which is stored the Boolean indication of whether the + * LdapResponse is complete. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_IsComplete( + PKIX_PL_LdapResponse *response, + PKIX_Boolean *pIsComplete, + void *plContext) +{ + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_IsComplete"); + PKIX_NULLCHECK_TWO(response, pIsComplete); + + if (response->totalLength == response->partialLength) { + *pIsComplete = PKIX_TRUE; + } else { + *pIsComplete = PKIX_FALSE; + } + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_Decode + * DESCRIPTION: + * + * This function decodes the DER data contained in the LdapResponse pointed to + * by "response", using the arena pointed to by "arena", and storing at + * "pStatus" SECSuccess if the decoding was successful and SECFailure + * otherwise. The decoded message is stored in an element of "response". + * + * PARAMETERS + * "arena" + * The address of the PLArenaPool to be used in the decoding. Must be + * non-NULL. + * "response" + * The address of the LdapResponse whose DER data is to be decoded. Must + * be non-NULL. + * "pStatus" + * The address at which is stored the status from the decoding, SECSuccess + * if successful, SECFailure otherwise. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_Decode( + PLArenaPool *arena, + PKIX_PL_LdapResponse *response, + SECStatus *pStatus, + void *plContext) +{ + LDAPMessage *msg; + SECStatus rv = SECFailure; + + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Decode"); + PKIX_NULLCHECK_THREE(arena, response, pStatus); + + if (response->totalLength != response->partialLength) { + PKIX_ERROR(PKIX_ATTEMPTTODECODEANINCOMPLETERESPONSE); + } + + msg = &(response->decoded); + + PKIX_PL_NSSCALL + (LDAPRESPONSE, PORT_Memset, (msg, 0, sizeof (LDAPMessage))); + + PKIX_PL_NSSCALLRV(LDAPRESPONSE, rv, SEC_ASN1DecodeItem, + (NULL, msg, PKIX_PL_LDAPMessageTemplate, &(response->derEncoded))); + + *pStatus = rv; +cleanup: + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_GetMessage + * DESCRIPTION: + * + * This function obtains the decoded message from the LdapResponse pointed to + * by "response", storing the result at "pMessage". + * + * PARAMETERS + * "response" + * The address of the LdapResponse whose decoded message is to be + * retrieved. Must be non-NULL. + * "pMessage" + * The address at which is stored the address of the decoded message. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_GetMessage( + PKIX_PL_LdapResponse *response, + LDAPMessage **pMessage, + void *plContext) +{ + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessage"); + PKIX_NULLCHECK_TWO(response, pMessage); + + *pMessage = &response->decoded; + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_GetCapacity + * DESCRIPTION: + * + * This function obtains from the LdapResponse pointed to by "response" the + * number of bytes remaining to be read, based on the totalLength that was + * provided to LdapResponse_Create and the data subsequently provided to + * LdapResponse_Append, storing the result at "pMessage". + * + * PARAMETERS + * "response" + * The address of the LdapResponse whose remaining capacity is to be + * retrieved. Must be non-NULL. + * "pCapacity" + * The address at which is stored the address of the decoded message. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_GetCapacity( + PKIX_PL_LdapResponse *response, + PKIX_UInt32 *pCapacity, + void *plContext) +{ + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetCapacity"); + PKIX_NULLCHECK_TWO(response, pCapacity); + + *pCapacity = response->totalLength - response->partialLength; + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_GetMessageType + * DESCRIPTION: + * + * This function obtains the message type from the LdapResponse pointed to + * by "response", storing the result at "pMessageType". + * + * PARAMETERS + * "response" + * The address of the LdapResponse whose message type is to be + * retrieved. Must be non-NULL. + * "pMessageType" + * The address at which is stored the type of the response message. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_GetMessageType( + PKIX_PL_LdapResponse *response, + LDAPMessageType *pMessageType, + void *plContext) +{ + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessageType"); + PKIX_NULLCHECK_TWO(response, pMessageType); + + *pMessageType = response->decoded.protocolOp.selector; + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_GetResultCode + * DESCRIPTION: + * + * This function obtains the result code from the LdapResponse pointed to + * by "response", storing the result at "pResultCode". + * + * PARAMETERS + * "response" + * The address of the LdapResponse whose result code is to be + * retrieved. Must be non-NULL. + * "pResultCode" + * The address at which is stored the address of the decoded message. Must + * be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_GetResultCode( + PKIX_PL_LdapResponse *response, + LDAPResultCode *pResultCode, + void *plContext) +{ + LDAPMessageType messageType = 0; + LDAPSearchResponseResult *resultMsg = NULL; + + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode"); + PKIX_NULLCHECK_TWO(response, pResultCode); + + messageType = response->decoded.protocolOp.selector; + + if (messageType != LDAP_SEARCHRESPONSERESULT_TYPE) { + PKIX_ERROR(PKIX_GETRESULTCODECALLEDFORNONRESULTMESSAGE); + } + + resultMsg = &response->decoded.protocolOp.op.searchResponseResultMsg; + + *pResultCode = *(resultMsg->resultCode.data); + +cleanup: + + PKIX_RETURN(LDAPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_LdapResponse_GetAttributes + * DESCRIPTION: + * + * This function obtains the attributes from the LdapResponse pointed to + * by "response", storing the result at "pAttributes". + * + * PARAMETERS + * "response" + * The address of the LdapResponse whose decoded message is to be + * retrieved. Must be non-NULL. + * "pAttributes" + * The address at which is stored the attributes of the message. Must be + * non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an LdapResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_LdapResponse_GetAttributes( + PKIX_PL_LdapResponse *response, + LDAPSearchResponseAttr ***pAttributes, + void *plContext) +{ + LDAPMessageType messageType = 0; + + PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode"); + PKIX_NULLCHECK_TWO(response, pAttributes); + + messageType = response->decoded.protocolOp.selector; + + if (messageType != LDAP_SEARCHRESPONSEENTRY_TYPE) { + PKIX_ERROR(PKIX_GETATTRIBUTESCALLEDFORNONENTRYMESSAGE); + } + + *pAttributes = response-> + decoded.protocolOp.op.searchResponseEntryMsg.attributes; + +cleanup: + + PKIX_RETURN(LDAPRESPONSE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h new file mode 100644 index 0000000000..37dc916b1e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h @@ -0,0 +1,96 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ldapresponse.h + * + * LdapResponse Object Definitions + * + */ + +#ifndef _PKIX_PL_LDAPRESPONSE_H +#define _PKIX_PL_LDAPRESPONSE_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_LdapResponseStruct{ + LDAPMessage decoded; + PKIX_UInt32 partialLength; + PKIX_UInt32 totalLength; + SECItem derEncoded; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_LdapResponse_Create( + LDAPMessageType responseType, + PKIX_UInt32 totalLength, + PKIX_UInt32 bytesAvailable, + void *partialData, + PKIX_UInt32 *pBytesConsumed, + PKIX_PL_LdapResponse **pResponse, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_Append( + PKIX_PL_LdapResponse *response, + PKIX_UInt32 partialLength, + void *partialData, + PKIX_UInt32 *bytesConsumed, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_IsComplete( + PKIX_PL_LdapResponse *response, + PKIX_Boolean *pIsComplete, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_Decode( + PLArenaPool *arena, + PKIX_PL_LdapResponse *response, + SECStatus *pStatus, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_GetMessage( + PKIX_PL_LdapResponse *response, + LDAPMessage **pMessage, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_GetMessageType( + PKIX_PL_LdapResponse *response, + LDAPMessageType *pMessageType, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_GetCapacity( + PKIX_PL_LdapResponse *response, + PKIX_UInt32 *pCapacity, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_GetResultCode( + PKIX_PL_LdapResponse *response, + LDAPResultCode *pResultCode, + void *plContext); + +PKIX_Error * +pkix_pl_LdapResponse_GetAttributes( + PKIX_PL_LdapResponse *response, + LDAPSearchResponseAttr ***pAttributes, + void *plContext); + +PKIX_Error *pkix_pl_LdapResponse_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_LDAPRESPONSE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h new file mode 100644 index 0000000000..539803638c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h @@ -0,0 +1,314 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _LDAP_H_ +#define _LDAP_H_ + +#include "certt.h" +#include "pkixt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const SEC_ASN1Template PKIX_PL_LDAPCrossCertPairTemplate[]; +SEC_ASN1_CHOOSER_DECLARE(PKIX_PL_LDAPCrossCertPairTemplate) +extern const SEC_ASN1Template PKIX_PL_LDAPMessageTemplate[]; +SEC_ASN1_CHOOSER_DECLARE(PKIX_PL_LDAPMessageTemplate) +extern const SEC_ASN1Template LDAPFilterTemplate[]; +SEC_ASN1_CHOOSER_DECLARE(LDAPFilterTemplate) + +/* ********************************************************************** */ + +#define SEC_ASN1_LDAP_STRING SEC_ASN1_OCTET_STRING + +#define LDAPATTR_CACERT (1<<0) +#define LDAPATTR_USERCERT (1<<1) +#define LDAPATTR_CROSSPAIRCERT (1<<2) +#define LDAPATTR_CERTREVLIST (1<<3) +#define LDAPATTR_AUTHREVLIST (1<<4) +#define MAX_LDAPATTRS 5 +typedef PKIX_UInt32 LdapAttrMask; + +typedef enum { + SIMPLE_AUTH = 0, + KRBV42LDAP_AUTH = 1, + KRBV42DSA_AUTH = 2 +} AuthType; + +typedef enum { + BASE_OBJECT = 0, + SINGLE_LEVEL = 1, + WHOLE_SUBTREE = 2 +} ScopeType; + +typedef enum { + NEVER_DEREF = 0, + DEREF_IN_SEARCHING = 1, + DEREF_FINDING_BASEOBJ = 2, + ALWAYS_DEREF = 3 +} DerefType; + +typedef enum { + LDAP_INITIALSUBSTRING_TYPE = 0, + LDAP_ANYSUBSTRING_TYPE = 1, + LDAP_FINALSUBSTRING_TYPE = 2 +} LDAPSubstringFilterType; + +typedef enum { + LDAP_ANDFILTER_TYPE = 0, + LDAP_ORFILTER_TYPE = 1, + LDAP_NOTFILTER_TYPE = 2, + LDAP_EQUALFILTER_TYPE = 3, + LDAP_SUBSTRINGFILTER_TYPE = 4, + LDAP_GREATEROREQUALFILTER_TYPE = 5, + LDAP_LESSOREQUALFILTER_TYPE = 6, + LDAP_PRESENTFILTER_TYPE = 7, + LDAP_APPROXMATCHFILTER_TYPE = 8 +} LDAPFilterType; + +typedef enum { + LDAP_BIND_TYPE = 0, + LDAP_BINDRESPONSE_TYPE = 1, + LDAP_UNBIND_TYPE = 2, + LDAP_SEARCH_TYPE = 3, + LDAP_SEARCHRESPONSEENTRY_TYPE = 4, + LDAP_SEARCHRESPONSERESULT_TYPE = 5, + LDAP_ABANDONREQUEST_TYPE = 16 +} LDAPMessageType; + +typedef enum { + SUCCESS = 0, + OPERATIONSERROR = 1, + PROTOCOLERROR = 2, + TIMELIMITEXCEEDED = 3, + SIZELIMITEXCEEDED = 4, + COMPAREFALSE = 5, + COMPARETRUE = 6, + AUTHMETHODNOTSUPPORTED = 7, + STRONGAUTHREQUIRED = 8, + NOSUCHATTRIBUTE = 16, + UNDEFINEDATTRIBUTETYPE = 17, + INAPPROPRIATEMATCHING = 18, + CONSTRAINTVIOLATION = 19, + ATTRIBUTEORVALUEEXISTS = 20, + INVALIDATTRIBUTESYNTAX = 21, + NOSUCHOBJECT = 32, + ALIASPROBLEM = 33, + INVALIDDNSYNTAX = 34, + ISLEAF = 35, + ALIASDEREFERENCINGPROBLEM = 36, + INAPPROPRIATEAUTHENTICATION = 48, + INVALIDCREDENTIALS = 49, + INSUFFICIENTACCESSRIGHTS = 50, + BUSY = 51, + UNAVAILABLE = 52, + UNWILLINGTOPERFORM = 53, + LOOPDETECT = 54, + NAMINGVIOLATION = 64, + OBJECTCLASSVIOLATION = 65, + NOTALLOWEDONNONLEAF = 66, + NOTALLOWEDONRDN = 67, + ENTRYALREADYEXISTS = 68, + OBJECTCLASSMODSPROHIBITED = 69, + OTHER = 80 +} LDAPResultCode; + +typedef struct LDAPLocationStruct LDAPLocation; +typedef struct LDAPCertPairStruct LDAPCertPair; +typedef struct LDAPSimpleBindStruct LDAPSimpleBind; +typedef struct LDAPBindAPIStruct LDAPBindAPI; +typedef struct LDAPBindStruct LDAPBind; +typedef struct LDAPResultStruct LDAPBindResponse; +typedef struct LDAPResultStruct LDAPResult; +typedef struct LDAPSearchResponseAttrStruct LDAPSearchResponseAttr; +typedef struct LDAPSearchResponseEntryStruct LDAPSearchResponseEntry; +typedef struct LDAPResultStruct LDAPSearchResponseResult; +typedef struct LDAPUnbindStruct LDAPUnbind; +typedef struct LDAPFilterStruct LDAPFilter; +typedef struct LDAPAndFilterStruct LDAPAndFilter; +typedef struct LDAPNotFilterStruct LDAPNotFilter; +typedef struct LDAPSubstringStruct LDAPSubstring; +typedef struct LDAPSubstringFilterStruct LDAPSubstringFilter; +typedef struct LDAPPresentFilterStruct LDAPPresentFilter; +typedef struct LDAPAttributeValueAssertionStruct LDAPAttributeValueAssertion; +typedef struct LDAPNameComponentStruct LDAPNameComponent; +typedef struct LDAPRequestParamsStruct LDAPRequestParams; +typedef struct LDAPSearchStruct LDAPSearch; +typedef struct LDAPAbandonRequestStruct LDAPAbandonRequest; +typedef struct protocolOpStruct LDAPProtocolOp; +typedef struct LDAPMessageStruct LDAPMessage; +typedef LDAPAndFilter LDAPOrFilter; +typedef LDAPAttributeValueAssertion LDAPEqualFilter; +typedef LDAPAttributeValueAssertion LDAPGreaterOrEqualFilter; +typedef LDAPAttributeValueAssertion LDAPLessOrEqualFilter; +typedef LDAPAttributeValueAssertion LDAPApproxMatchFilter; + +struct LDAPLocationStruct { + PLArenaPool *arena; + void *serverSite; + void **filterString; + void **attrBitString; +}; + +struct LDAPCertPairStruct { + SECItem forward; + SECItem reverse; +}; + +struct LDAPSimpleBindStruct { + char *bindName; + char *authentication; +}; + +struct LDAPBindAPIStruct { + AuthType selector; + union { + LDAPSimpleBind simple; + } chooser; +}; + +struct LDAPBindStruct { + SECItem version; + SECItem bindName; + SECItem authentication; +}; + +struct LDAPResultStruct { + SECItem resultCode; + SECItem matchedDN; + SECItem errorMessage; +}; + +struct LDAPSearchResponseAttrStruct { + SECItem attrType; + SECItem **val; +}; + +struct LDAPSearchResponseEntryStruct { + SECItem objectName; + LDAPSearchResponseAttr **attributes; +}; + +struct LDAPUnbindStruct { + SECItem dummy; +}; + +struct LDAPAndFilterStruct { + LDAPFilter **filters; +}; + +struct LDAPNotFilterStruct { + LDAPFilter *filter; +}; + +struct LDAPSubstringStruct { + LDAPSubstringFilterType selector; + SECItem item; +}; + +struct LDAPSubstringFilterStruct { + SECItem attrType; + LDAPSubstring *strings; +}; + +struct LDAPPresentFilterStruct { + SECItem attrType; +}; + +struct LDAPAttributeValueAssertionStruct { + SECItem attrType; + SECItem attrValue; +}; + +struct LDAPFilterStruct { + LDAPFilterType selector; + union { + LDAPAndFilter andFilter; + LDAPOrFilter orFilter; + LDAPNotFilter notFilter; + LDAPEqualFilter equalFilter; + LDAPSubstringFilter substringFilter; + LDAPGreaterOrEqualFilter greaterOrEqualFilter; + LDAPLessOrEqualFilter lessOrEqualFilter; + LDAPPresentFilter presentFilter; + LDAPApproxMatchFilter approxMatchFilter; + } filter; +}; + +struct LDAPNameComponentStruct { + unsigned char *attrType; + unsigned char *attrValue; +}; + +struct LDAPRequestParamsStruct { + char *baseObject; /* e.g. "c=US" */ + ScopeType scope; + DerefType derefAliases; + PKIX_UInt32 sizeLimit; /* 0 = no limit */ + PRIntervalTime timeLimit; /* 0 = no limit */ + LDAPNameComponent **nc; /* e.g. {{"cn","xxx"},{"o","yyy"},NULL} */ + LdapAttrMask attributes; +}; + +struct LDAPSearchStruct { + SECItem baseObject; + SECItem scope; + SECItem derefAliases; + SECItem sizeLimit; + SECItem timeLimit; + SECItem attrsOnly; + LDAPFilter filter; + SECItem **attributes; +}; + +struct LDAPAbandonRequestStruct { + SECItem messageID; +}; + +struct protocolOpStruct { + LDAPMessageType selector; + union { + LDAPBind bindMsg; + LDAPBindResponse bindResponseMsg; + LDAPUnbind unbindMsg; + LDAPSearch searchMsg; + LDAPSearchResponseEntry searchResponseEntryMsg; + LDAPSearchResponseResult searchResponseResultMsg; + LDAPAbandonRequest abandonRequestMsg; + } op; +}; + +struct LDAPMessageStruct { + SECItem messageID; + LDAPProtocolOp protocolOp; +}; + +typedef struct PKIX_PL_LdapClientStruct PKIX_PL_LdapClient; + +typedef PKIX_Error * +(*PKIX_PL_LdapClient_InitiateFcn)( + PKIX_PL_LdapClient *client, + LDAPRequestParams *requestParams, + void **pNBIO, + PKIX_List **pResponse, + void *plContext); + +typedef PKIX_Error * +(*PKIX_PL_LdapClient_ResumeFcn)( + PKIX_PL_LdapClient *client, + void **pNBIO, + PKIX_List **pResponse, + void *plContext); + +struct PKIX_PL_LdapClientStruct { + PKIX_PL_LdapClient_InitiateFcn initiateFcn; + PKIX_PL_LdapClient_ResumeFcn resumeFcn; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c new file mode 100644 index 0000000000..ecb681929b --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c @@ -0,0 +1,417 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "pkix_pl_ldapt.h" + +SEC_ASN1_MKSUB(SEC_AnyTemplate) +SEC_ASN1_MKSUB(SEC_NullTemplate) +SEC_ASN1_MKSUB(SEC_OctetStringTemplate) + +/* + * CertificatePair ::= SEQUENCE { + * forward [0] Certificate OPTIONAL, + * reverse [1] Certificate OPTIONAL + * -- at least one of the pair shall be present -- + * } + */ + +const SEC_ASN1Template PKIX_PL_LDAPCrossCertPairTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(LDAPCertPair) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0, + offsetof(LDAPCertPair, forward), SEC_ASN1_SUB(SEC_AnyTemplate) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 1, + offsetof(LDAPCertPair, reverse), SEC_ASN1_SUB(SEC_AnyTemplate) }, + { 0 } +}; + +/* + * BindRequest ::= + * [APPLICATION 0] SEQUENCE { + * version INTEGER (1..127), + * name LDAPDN, + * authentication CHOICE { + * simple [0] OCTET STRING, + * krbv42LDAP [1] OCTET STRING, + * krbv42DSA [2] OCTET STRING + * } + * } + * + * LDAPDN ::= LDAPString + * + * LDAPString ::= OCTET STRING + */ + +#define LDAPStringTemplate SEC_ASN1_SUB(SEC_OctetStringTemplate) + +static const SEC_ASN1Template LDAPBindApplTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL }, + { SEC_ASN1_INTEGER, offsetof(LDAPBind, version) }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPBind, bindName) }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPBind, authentication) }, + { 0 } +}; + +static const SEC_ASN1Template LDAPBindTemplate[] = { + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_BIND_TYPE, 0, + LDAPBindApplTemplate, sizeof (LDAPBind) } +}; + +/* + * BindResponse ::= [APPLICATION 1] LDAPResult + * + * LDAPResult ::= + * SEQUENCE { + * resultCode ENUMERATED { + * success (0), + * operationsError (1), + * protocolError (2), + * timeLimitExceeded (3), + * sizeLimitExceeded (4), + * compareFalse (5), + * compareTrue (6), + * authMethodNotSupported (7), + * strongAuthRequired (8), + * noSuchAttribute (16), + * undefinedAttributeType (17), + * inappropriateMatching (18), + * constraintViolation (19), + * attributeOrValueExists (20), + * invalidAttributeSyntax (21), + * noSuchObject (32), + * aliasProblem (33), + * invalidDNSyntax (34), + * isLeaf (35), + * aliasDereferencingProblem (36), + * inappropriateAuthentication (48), + * invalidCredentials (49), + * insufficientAccessRights (50), + * busy (51), + * unavailable (52), + * unwillingToPerform (53), + * loopDetect (54), + * namingViolation (64), + * objectClassViolation (65), + * notAllowedOnNonLeaf (66), + * notAllowedOnRDN (67), + * entryAlreadyExists (68), + * objectClassModsProhibited (69), + * other (80) + * }, + * matchedDN LDAPDN, + * errorMessage LDAPString + * } + */ + +static const SEC_ASN1Template LDAPResultTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL }, + { SEC_ASN1_ENUMERATED, offsetof(LDAPResult, resultCode) }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPResult, matchedDN) }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPResult, errorMessage) }, + { 0 } +}; + +static const SEC_ASN1Template LDAPBindResponseTemplate[] = { + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_BINDRESPONSE_TYPE, 0, + LDAPResultTemplate, sizeof (LDAPBindResponse) } +}; + +/* + * UnbindRequest ::= [APPLICATION 2] NULL + */ + +static const SEC_ASN1Template LDAPUnbindTemplate[] = { + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | SEC_ASN1_XTRN | + LDAP_UNBIND_TYPE , 0, SEC_ASN1_SUB(SEC_NullTemplate) } +}; + +/* + * AttributeValueAssertion ::= + * SEQUENCE { + * attributeType AttributeType, + * attributeValue AttributeValue, + * } + * + * AttributeType ::= LDAPString + * -- text name of the attribute, or dotted + * -- OID representation + * + * AttributeValue ::= OCTET STRING + */ + +#define LDAPAttributeTypeTemplate LDAPStringTemplate + +/* + * SubstringFilter ::= + * SEQUENCE { + * type AttributeType, + * SEQUENCE OF CHOICE { + * initial [0] LDAPString, + * any [1] LDAPString, + * final [2] LDAPString, + * } + * } + */ + +#define LDAPSubstringFilterInitialTemplate LDAPStringTemplate +#define LDAPSubstringFilterAnyTemplate LDAPStringTemplate +#define LDAPSubstringFilterFinalTemplate LDAPStringTemplate + +static const SEC_ASN1Template LDAPSubstringFilterChoiceTemplate[] = { + { SEC_ASN1_CHOICE, offsetof(LDAPSubstring, selector), 0, + sizeof (LDAPFilter) }, + { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, + offsetof(LDAPSubstring, item), + LDAPSubstringFilterInitialTemplate, + LDAP_INITIALSUBSTRING_TYPE }, + { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, + offsetof(LDAPSubstring, item), + LDAPSubstringFilterAnyTemplate, + LDAP_ANYSUBSTRING_TYPE }, + { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2, + offsetof(LDAPSubstring, item), + LDAPSubstringFilterFinalTemplate, + LDAP_FINALSUBSTRING_TYPE }, + { 0 } +}; + +/* + * Filter ::= + * CHOICE { + * and [0] SET OF Filter, + * or [1] SET OF Filter, + * not [2] Filter, + * equalityMatch [3] AttributeValueAssertion, + * substrings [4] SubstringFilter, + * greaterOrEqual [5] AttributeValueAssertion, + * lessOrEqual [6] AttributeValueAssertion, + * present [7] AttributeType, + * approxMatch [8] AttributeValueAssertion + } + */ + +static const SEC_ASN1Template LDAPSubstringFilterTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (LDAPSubstringFilter) }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPSubstringFilter, attrType) }, + { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSubstringFilter, strings), + LDAPSubstringFilterChoiceTemplate }, + { 0 } +}; + +const SEC_ASN1Template LDAPFilterTemplate[]; /* forward reference */ + +static const SEC_ASN1Template LDAPSetOfFiltersTemplate[] = { + { SEC_ASN1_SET_OF, 0, LDAPFilterTemplate } +}; + +static const SEC_ASN1Template LDAPAVAFilterTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (LDAPAttributeValueAssertion) }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPAttributeValueAssertion, attrType) }, + { SEC_ASN1_OCTET_STRING, offsetof(LDAPAttributeValueAssertion, attrValue) }, + { 0 } +}; + +static const SEC_ASN1Template LDAPPresentFilterTemplate[] = { + { SEC_ASN1_LDAP_STRING, offsetof(LDAPPresentFilter, attrType) } +}; + +#define LDAPEqualFilterTemplate LDAPAVAFilterTemplate +#define LDAPGreaterOrEqualFilterTemplate LDAPAVAFilterTemplate +#define LDAPLessOrEqualFilterTemplate LDAPAVAFilterTemplate +#define LDAPApproxMatchFilterTemplate LDAPAVAFilterTemplate + +const SEC_ASN1Template LDAPFilterTemplate[] = { + { SEC_ASN1_CHOICE, offsetof(LDAPFilter, selector), 0, sizeof(LDAPFilter) }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_ANDFILTER_TYPE, + offsetof(LDAPFilter, filter.andFilter.filters), + LDAPSetOfFiltersTemplate, LDAP_ANDFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_ORFILTER_TYPE, + offsetof(LDAPFilter, filter.orFilter.filters), + LDAPSetOfFiltersTemplate, LDAP_ORFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_NOTFILTER_TYPE | SEC_ASN1_POINTER, + offsetof(LDAPFilter, filter.notFilter), + LDAPFilterTemplate, LDAP_NOTFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_EQUALFILTER_TYPE, + offsetof(LDAPFilter, filter.equalFilter), + LDAPEqualFilterTemplate, LDAP_EQUALFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_SUBSTRINGFILTER_TYPE, offsetof(LDAPFilter, filter.substringFilter), + LDAPSubstringFilterTemplate, LDAP_SUBSTRINGFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_GREATEROREQUALFILTER_TYPE, + offsetof(LDAPFilter, filter.greaterOrEqualFilter), + LDAPGreaterOrEqualFilterTemplate, LDAP_GREATEROREQUALFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_LESSOREQUALFILTER_TYPE, + offsetof(LDAPFilter, filter.lessOrEqualFilter), + LDAPLessOrEqualFilterTemplate, LDAP_LESSOREQUALFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_PRESENTFILTER_TYPE, + offsetof(LDAPFilter, filter.presentFilter), + LDAPPresentFilterTemplate, LDAP_PRESENTFILTER_TYPE }, + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | + LDAP_APPROXMATCHFILTER_TYPE, + offsetof(LDAPFilter, filter.approxMatchFilter), + LDAPApproxMatchFilterTemplate, LDAP_APPROXMATCHFILTER_TYPE }, + { 0 } +}; + +/* + * SearchRequest ::= + * [APPLICATION 3] SEQUENCE { + * baseObject LDAPDN, + * scope ENUMERATED { + * baseObject (0), + * singleLevel (1), + * wholeSubtree (2) + * }, + * derefAliases ENUMERATED { + * neverDerefAliases (0), + * derefInSearching (1), + * derefFindingBaseObj (2), + * alwaysDerefAliases (3) + * }, + * sizeLimit INTEGER (0 .. MAXINT), + * -- value of 0 implies no sizeLimit + * timeLimit INTEGER (0 .. MAXINT), + * -- value of 0 implies no timeLimit + * attrsOnly BOOLEAN, + * -- TRUE, if only attributes (without values) + * -- to be returned + * filter Filter, + * attributes SEQUENCE OF AttributeType + * } + */ + +static const SEC_ASN1Template LDAPAttributeTemplate[] = { + { SEC_ASN1_LDAP_STRING, 0, NULL, sizeof (SECItem) } +}; + +static const SEC_ASN1Template LDAPSearchApplTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearch, baseObject) }, + { SEC_ASN1_ENUMERATED, offsetof(LDAPSearch, scope) }, + { SEC_ASN1_ENUMERATED, offsetof(LDAPSearch, derefAliases) }, + { SEC_ASN1_INTEGER, offsetof(LDAPSearch, sizeLimit) }, + { SEC_ASN1_INTEGER, offsetof(LDAPSearch, timeLimit) }, + { SEC_ASN1_BOOLEAN, offsetof(LDAPSearch, attrsOnly) }, + { SEC_ASN1_INLINE, offsetof(LDAPSearch, filter), LDAPFilterTemplate }, + { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSearch, attributes), LDAPAttributeTemplate }, + { 0 } +}; + +static const SEC_ASN1Template LDAPSearchTemplate[] = { + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCH_TYPE, 0, + LDAPSearchApplTemplate, sizeof (LDAPSearch) } +}; + +/* + * SearchResponse ::= + * CHOICE { + * entry [APPLICATION 4] SEQUENCE { + * objectName LDAPDN, + * attributes SEQUENCE OF SEQUENCE { + * AttributeType, + * SET OF AttributeValue + * } + * } + * resultCode [APPLICATION 5] LDAPResult + * } + */ + +static const SEC_ASN1Template LDAPSearchResponseAttrTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(LDAPSearchResponseAttr) }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearchResponseAttr, attrType) }, + { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(LDAPSearchResponseAttr, val), + LDAPStringTemplate }, + { 0 } +}; + +static const SEC_ASN1Template LDAPEntryTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL }, + { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearchResponseEntry, objectName) }, + { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSearchResponseEntry, attributes), + LDAPSearchResponseAttrTemplate }, + { 0 } +}; + +static const SEC_ASN1Template LDAPSearchResponseEntryTemplate[] = { + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSEENTRY_TYPE, 0, + LDAPEntryTemplate, sizeof (LDAPSearchResponseEntry) } +}; + +static const SEC_ASN1Template LDAPSearchResponseResultTemplate[] = { + { SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSERESULT_TYPE, 0, + LDAPResultTemplate, sizeof (LDAPSearchResponseResult) } +}; + +/* + * AbandonRequest ::= + * [APPLICATION 16] MessageID + */ + +static const SEC_ASN1Template LDAPAbandonTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(LDAPAbandonRequest, messageID) } +}; + +static const SEC_ASN1Template LDAPAbandonRequestTemplate[] = { + { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_ABANDONREQUEST_TYPE, 0, + LDAPAbandonTemplate, sizeof (LDAPAbandonRequest) } +}; + +/* + * LDAPMessage ::= + * SEQUENCE { + * messageID MessageID, + * protocolOp CHOICE { + * bindRequest BindRequest, + * bindResponse BindResponse, + * unbindRequest UnbindRequest, + * searchRequest SearchRequest, + * searchResponse SearchResponse, + * abandonRequest AbandonRequest + * } + * } + * + * (other choices exist, not shown) + * + * MessageID ::= INTEGER (0 .. maxInt) + */ + +static const SEC_ASN1Template LDAPMessageProtocolOpTemplate[] = { + { SEC_ASN1_CHOICE, offsetof(LDAPProtocolOp, selector), 0, sizeof (LDAPProtocolOp) }, + { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.bindMsg), + LDAPBindTemplate, LDAP_BIND_TYPE }, + { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.bindResponseMsg), + LDAPBindResponseTemplate, LDAP_BINDRESPONSE_TYPE }, + { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.unbindMsg), + LDAPUnbindTemplate, LDAP_UNBIND_TYPE }, + { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchMsg), + LDAPSearchTemplate, LDAP_SEARCH_TYPE }, + { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchResponseEntryMsg), + LDAPSearchResponseEntryTemplate, LDAP_SEARCHRESPONSEENTRY_TYPE }, + { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchResponseResultMsg), + LDAPSearchResponseResultTemplate, LDAP_SEARCHRESPONSERESULT_TYPE }, + { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.abandonRequestMsg), + LDAPAbandonRequestTemplate, LDAP_ABANDONREQUEST_TYPE }, + { 0 } +}; + +const SEC_ASN1Template PKIX_PL_LDAPMessageTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL }, + { SEC_ASN1_INTEGER, offsetof(LDAPMessage, messageID) }, + { SEC_ASN1_INLINE, offsetof(LDAPMessage, protocolOp), + LDAPMessageProtocolOpTemplate }, + { 0 } +}; + +/* This function simply returns the address of the message template. + * This is necessary for Windows DLLs. + */ +SEC_ASN1_CHOOSER_IMPLEMENT(PKIX_PL_LDAPMessageTemplate) diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c new file mode 100644 index 0000000000..966c6f37e4 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c @@ -0,0 +1,389 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_nsscontext.c + * + * NSSContext Function Definitions + * + */ + + +#include "pkix_pl_nsscontext.h" + +#define PKIX_DEFAULT_MAX_RESPONSE_LENGTH 64 * 1024 +#define PKIX_DEFAULT_COMM_TIMEOUT_SECONDS 60 + +#define PKIX_DEFAULT_CRL_RELOAD_DELAY_SECONDS 6 * 24 * 60 * 60 +#define PKIX_DEFAULT_BAD_CRL_RELOAD_DELAY_SECONDS 60 * 60 + +/* --Public-NSSContext-Functions--------------------------- */ + +/* + * FUNCTION: PKIX_PL_NssContext_Create + * (see comments in pkix_samples_modules.h) + */ +PKIX_Error * +PKIX_PL_NssContext_Create( + PKIX_UInt32 certificateUsage, + PKIX_Boolean useNssArena, + void *wincx, + void **pNssContext) +{ + PKIX_PL_NssContext *context = NULL; + PLArenaPool *arena = NULL; + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_Create"); + PKIX_NULLCHECK_ONE(pNssContext); + + PKIX_CHECK(PKIX_PL_Malloc + (sizeof(PKIX_PL_NssContext), (void **)&context, NULL), + PKIX_MALLOCFAILED); + + if (useNssArena == PKIX_TRUE) { + PKIX_CONTEXT_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + } + + context->arena = arena; + context->certificateUsage = (SECCertificateUsage)certificateUsage; + context->wincx = wincx; + context->timeoutSeconds = PKIX_DEFAULT_COMM_TIMEOUT_SECONDS; + context->maxResponseLength = PKIX_DEFAULT_MAX_RESPONSE_LENGTH; + context->crlReloadDelay = PKIX_DEFAULT_CRL_RELOAD_DELAY_SECONDS; + context->badDerCrlReloadDelay = + PKIX_DEFAULT_BAD_CRL_RELOAD_DELAY_SECONDS; + context->certSignatureCheck = PKIX_TRUE; + context->chainVerifyCallback.isChainValid = NULL; + context->chainVerifyCallback.isChainValidArg = NULL; + *pNssContext = context; + +cleanup: + + PKIX_RETURN(CONTEXT); +} + + +/* + * FUNCTION: PKIX_PL_NssContext_Destroy + * (see comments in pkix_samples_modules.h) + */ +PKIX_Error * +PKIX_PL_NssContext_Destroy( + void *nssContext) +{ + void *plContext = NULL; + PKIX_PL_NssContext *context = NULL; + + PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_Destroy"); + PKIX_NULLCHECK_ONE(nssContext); + + context = (PKIX_PL_NssContext*)nssContext; + + if (context->arena != NULL) { + PKIX_CONTEXT_DEBUG("\t\tCalling PORT_FreeArena\n"); + PORT_FreeArena(context->arena, PKIX_FALSE); + } + + PKIX_PL_Free(nssContext, NULL); + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: pkix_pl_NssContext_GetCertUsage + * DESCRIPTION: + * + * This function obtains the platform-dependent SECCertificateUsage parameter + * from the context object pointed to by "nssContext", storing the result at + * "pCertUsage". + * + * PARAMETERS: + * "nssContext" + * The address of the context object whose wincx parameter is to be + * obtained. Must be non-NULL. + * "pCertUsage" + * The address where the result is stored. Must be non-NULL. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_NssContext_GetCertUsage( + PKIX_PL_NssContext *nssContext, + SECCertificateUsage *pCertUsage) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetCertUsage"); + PKIX_NULLCHECK_TWO(nssContext, pCertUsage); + + *pCertUsage = nssContext->certificateUsage; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: pkix_pl_NssContext_SetCertUsage + * DESCRIPTION: + * + * This function sets the platform-dependent SECCertificateUsage parameter in + * the context object pointed to by "nssContext" to the value provided in + * "certUsage". + * + * PARAMETERS: + * "certUsage" + * Platform-dependent value to be stored. + * "nssContext" + * The address of the context object whose wincx parameter is to be + * obtained. Must be non-NULL. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_NssContext_SetCertUsage( + SECCertificateUsage certUsage, + PKIX_PL_NssContext *nssContext) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetCertUsage"); + PKIX_NULLCHECK_ONE(nssContext); + + nssContext->certificateUsage = certUsage; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: pkix_pl_NssContext_GetCertSignatureCheck + * DESCRIPTION: + * + * This function obtains the platform-dependent flag to turn on or off + * signature checks. + * + * PARAMETERS: + * "nssContext" + * The address of the context object whose wincx parameter is to be + * obtained. Must be non-NULL. + * "pCheckSig" + * The address where the result is stored. Must be non-NULL. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_NssContext_GetCertSignatureCheck( + PKIX_PL_NssContext *nssContext, + PKIX_Boolean *pCheckSig) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetCertUsage"); + PKIX_NULLCHECK_TWO(nssContext, pCheckSig); + + *pCheckSig = nssContext->certSignatureCheck; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: pkix_pl_NssContext_SetCertSignatureCheck + * DESCRIPTION: + * + * This function sets the check signature flag in + * the context object pointed to by "nssContext" to the value provided in + * "checkSig". + * + * PARAMETERS: + * "checkSig" + * Boolean that tells whether or not to check the signatues on certs. + * "nssContext" + * The address of the context object whose wincx parameter is to be + * obtained. Must be non-NULL. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_NssContext_SetCertSignatureCheck( + PKIX_Boolean checkSig, + PKIX_PL_NssContext *nssContext) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetCertUsage"); + PKIX_NULLCHECK_ONE(nssContext); + + nssContext->certSignatureCheck = checkSig; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: pkix_pl_NssContext_GetWincx + * DESCRIPTION: + * + * This function obtains the platform-dependent wincx parameter from the + * context object pointed to by "nssContext", storing the result at "pWincx". + * + * PARAMETERS: + * "nssContext" + * The address of the context object whose wincx parameter is to be + * obtained. Must be non-NULL. + * "pWincx" + * The address where the result is stored. Must be non-NULL. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_NssContext_GetWincx( + PKIX_PL_NssContext *nssContext, + void **pWincx) +{ + void *plContext = NULL; + PKIX_PL_NssContext *context = NULL; + + PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetWincx"); + PKIX_NULLCHECK_TWO(nssContext, pWincx); + + context = (PKIX_PL_NssContext *)nssContext; + + *pWincx = context->wincx; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: pkix_pl_NssContext_SetWincx + * DESCRIPTION: + * + * This function sets the platform-dependent wincx parameter in the context + * object pointed to by "nssContext" to the value provided in "wincx". + * + * PARAMETERS: + * "wincx" + * Platform-dependent value to be stored. + * "nssContext" + * The address of the context object whose wincx parameter is to be + * obtained. Must be non-NULL. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_NssContext_SetWincx( + void *wincx, + PKIX_PL_NssContext *nssContext) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetWincx"); + PKIX_NULLCHECK_ONE(nssContext); + + nssContext->wincx = wincx; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: PKIX_PL_NssContext_SetTimeout + * DESCRIPTION: + * + * Sets user defined socket timeout for the validation + * session. Default is 60 seconds. + * + */ +PKIX_Error * +PKIX_PL_NssContext_SetTimeout(PKIX_UInt32 timeout, + PKIX_PL_NssContext *nssContext) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetTimeout"); + PKIX_NULLCHECK_ONE(nssContext); + + nssContext->timeoutSeconds = timeout; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: PKIX_PL_NssContext_SetMaxResponseLen + * DESCRIPTION: + * + * Sets user defined maximum transmission length of a message. + * + */ +PKIX_Error * +PKIX_PL_NssContext_SetMaxResponseLen(PKIX_UInt32 len, + PKIX_PL_NssContext *nssContext) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetMaxResponseLen"); + PKIX_NULLCHECK_ONE(nssContext); + + nssContext->maxResponseLength = len; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: PKIX_PL_NssContext_SetCrlReloadDelay + * DESCRIPTION: + * + * Sets user defined delay between attempts to load crl using + * CRLDP. + * + */ +PKIX_Error * +PKIX_PL_NssContext_SetCrlReloadDelay(PKIX_UInt32 delay, + PKIX_PL_NssContext *nssContext) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetCrlReloadDelay"); + PKIX_NULLCHECK_ONE(nssContext); + + nssContext->crlReloadDelay = delay; + + PKIX_RETURN(CONTEXT); +} + +/* + * FUNCTION: PKIX_PL_NssContext_SetBadDerCrlReloadDelay + * DESCRIPTION: + * + * Sets user defined delay between attempts to load crl that + * failed to decode. + * + */ +PKIX_Error * +PKIX_PL_NssContext_SetBadDerCrlReloadDelay(PKIX_UInt32 delay, + PKIX_PL_NssContext *nssContext) +{ + void *plContext = NULL; + + PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetBadDerCrlReloadDelay"); + PKIX_NULLCHECK_ONE(nssContext); + + nssContext->badDerCrlReloadDelay = delay; + + PKIX_RETURN(CONTEXT); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h new file mode 100644 index 0000000000..5de44214e5 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_nsscontext.h + * + * NSSContext Object Type Definition + * + */ + + +#ifndef _PKIX_PL_NSSCONTEXT_H +#define _PKIX_PL_NSSCONTEXT_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_NssContextStruct { + SECCertificateUsage certificateUsage; + PLArenaPool *arena; + void *wincx; + PKIX_UInt32 timeoutSeconds; + PKIX_UInt32 maxResponseLength; + PRTime crlReloadDelay; + PRTime badDerCrlReloadDelay; + CERTChainVerifyCallback chainVerifyCallback; + PKIX_Boolean certSignatureCheck; +}; + +PKIX_Error * +pkix_pl_NssContext_GetCertUsage + (PKIX_PL_NssContext *nssContext, SECCertificateUsage *pCertUsage); + +/* XXX move the setter into the public header. */ +PKIX_Error * +pkix_pl_NssContext_SetCertUsage + (SECCertificateUsage certUsage, PKIX_PL_NssContext *nssContext); + +PKIX_Error * +pkix_pl_NssContext_GetCertSignatureCheck + (PKIX_PL_NssContext *nssContext, PKIX_Boolean *pCheckSig); + +PKIX_Error * +pkix_pl_NssContext_SetCertSignatureCheck + (PKIX_Boolean checkSig, PKIX_PL_NssContext *nssContext); + +PKIX_Error * +pkix_pl_NssContext_GetWincx(PKIX_PL_NssContext *nssContext, void **pWincx); + +/* XXX move the setter into the public header. */ +PKIX_Error * +pkix_pl_NssContext_SetWincx(void *wincx, PKIX_PL_NssContext *nssContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_NSSCONTEXT_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c new file mode 100644 index 0000000000..7de614ea68 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c @@ -0,0 +1,1039 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_pk11certstore.c + * + * PKCS11CertStore Function Definitions + * + */ + +#include "pkix_pl_pk11certstore.h" + +/* + * PKIX_DEFAULT_MAX_RESPONSE_LENGTH (64 * 1024) is too small for downloading + * CRLs. We observed CRLs of sizes 338759 and 439035 in practice. So we + * need to use a higher max response length for CRLs. + */ +#define PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH (512 * 1024) + +/* --Private-Pk11CertStore-Functions---------------------------------- */ + +/* + * FUNCTION: pkix_pl_Pk11CertStore_CheckTrust + * DESCRIPTION: + * This function checks the trust status of this "cert" that was retrieved + * from the CertStore "store" and returns its trust status at "pTrusted". + * + * PARAMETERS: + * "store" + * Address of the CertStore. Must be non-NULL. + * "cert" + * Address of the Cert. Must be non-NULL. + * "pTrusted" + * Address of PKIX_Boolean where the "cert" trust status is returned. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Pk11CertStore_CheckTrust( + PKIX_CertStore *store, + PKIX_PL_Cert *cert, + PKIX_Boolean *pTrusted, + void *plContext) +{ + SECStatus rv = SECFailure; + PKIX_Boolean trusted = PKIX_FALSE; + SECCertUsage certUsage = 0; + SECCertificateUsage certificateUsage; + unsigned int requiredFlags; + SECTrustType trustType; + CERTCertTrust trust; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckTrust"); + PKIX_NULLCHECK_THREE(store, cert, pTrusted); + PKIX_NULLCHECK_ONE(cert->nssCert); + + certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage; + + /* ensure we obtained a single usage bit only */ + PORT_Assert(!(certificateUsage & (certificateUsage - 1))); + + /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */ + while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; } + + rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType); + if (rv == SECSuccess) { + rv = CERT_GetCertTrust(cert->nssCert, &trust); + } + + if (rv == SECSuccess) { + unsigned int certFlags; + + if (certUsage != certUsageAnyCA && + certUsage != certUsageStatusResponder) { + CERTCertificate *nssCert = cert->nssCert; + + if (certUsage == certUsageVerifyCA) { + if (nssCert->nsCertType & NS_CERT_TYPE_EMAIL_CA) { + trustType = trustEmail; + } else if (nssCert->nsCertType & NS_CERT_TYPE_SSL_CA) { + trustType = trustSSL; + } else { + trustType = trustObjectSigning; + } + } + + certFlags = SEC_GET_TRUST_FLAGS((&trust), trustType); + if ((certFlags & requiredFlags) == requiredFlags) { + trusted = PKIX_TRUE; + } + } else { + for (trustType = trustSSL; trustType < trustTypeNone; + trustType++) { + certFlags = + SEC_GET_TRUST_FLAGS((&trust), trustType); + if ((certFlags & requiredFlags) == requiredFlags) { + trusted = PKIX_TRUE; + break; + } + } + } + } + + *pTrusted = trusted; + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_Pk11CertStore_CertQuery + * DESCRIPTION: + * + * This function obtains from the database the Certs specified by the + * ComCertSelParams pointed to by "params" and stores the resulting + * List at "pSelected". If no matching Certs are found, a NULL pointer + * will be stored. + * + * This function uses a "smart" database query if the Subject has been set + * in ComCertSelParams. Otherwise, it uses a very inefficient call to + * retrieve all Certs in the database (and run them through the selector). + * + * PARAMETERS: + * "params" + * Address of the ComCertSelParams. Must be non-NULL. + * "pSelected" + * Address at which List will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Pk11CertStore_CertQuery( + PKIX_ComCertSelParams *params, + PKIX_List **pSelected, + void *plContext) +{ + PRBool validOnly = PR_FALSE; + PRTime prtime = 0; + PKIX_PL_X500Name *subjectName = NULL; + PKIX_PL_Date *certValid = NULL; + PKIX_List *certList = NULL; + PKIX_PL_Cert *cert = NULL; + CERTCertList *pk11CertList = NULL; + CERTCertListNode *node = NULL; + CERTCertificate *nssCert = NULL; + CERTCertDBHandle *dbHandle = NULL; + + PLArenaPool *arena = NULL; + SECItem *nameItem = NULL; + void *wincx = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CertQuery"); + PKIX_NULLCHECK_TWO(params, pSelected); + + /* avoid multiple calls to retrieve a constant */ + PKIX_PL_NSSCALLRV(CERTSTORE, dbHandle, CERT_GetDefaultCertDB, ()); + + /* + * Any of the ComCertSelParams may be obtained and used to constrain + * the database query, to allow the use of a "smart" query. See + * pkix_certsel.h for a list of the PKIX_ComCertSelParams_Get* + * calls available. No corresponding "smart" queries exist at present, + * except for CERT_CreateSubjectCertList based on Subject. When others + * are added, corresponding code should be added to + * pkix_pl_Pk11CertStore_CertQuery to use them when appropriate + * selector parameters have been set. + */ + + PKIX_CHECK(PKIX_ComCertSelParams_GetSubject + (params, &subjectName, plContext), + PKIX_COMCERTSELPARAMSGETSUBJECTFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_GetCertificateValid + (params, &certValid, plContext), + PKIX_COMCERTSELPARAMSGETCERTIFICATEVALIDFAILED); + + /* If caller specified a Date, convert it to PRTime */ + if (certValid) { + PKIX_CHECK(pkix_pl_Date_GetPRTime + (certValid, &prtime, plContext), + PKIX_DATEGETPRTIMEFAILED); + validOnly = PR_TRUE; + } + + /* + * If we have the subject name for the desired subject, + * ask the database for Certs with that subject. Otherwise + * ask the database for all Certs. + */ + if (subjectName) { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena) { + + PKIX_CHECK(pkix_pl_X500Name_GetDERName + (subjectName, arena, &nameItem, plContext), + PKIX_X500NAMEGETSECNAMEFAILED); + + if (nameItem) { + + PKIX_PL_NSSCALLRV + (CERTSTORE, + pk11CertList, + CERT_CreateSubjectCertList, + (NULL, dbHandle, nameItem, prtime, validOnly)); + } + PKIX_PL_NSSCALL + (CERTSTORE, PORT_FreeArena, (arena, PR_FALSE)); + arena = NULL; + } + + } else { + + PKIX_CHECK(pkix_pl_NssContext_GetWincx + ((PKIX_PL_NssContext *)plContext, &wincx), + PKIX_NSSCONTEXTGETWINCXFAILED); + + PKIX_PL_NSSCALLRV + (CERTSTORE, + pk11CertList, + PK11_ListCerts, + (PK11CertListAll, wincx)); + } + + if (pk11CertList) { + + PKIX_CHECK(PKIX_List_Create(&certList, plContext), + PKIX_LISTCREATEFAILED); + + for (node = CERT_LIST_HEAD(pk11CertList); + !(CERT_LIST_END(node, pk11CertList)); + node = CERT_LIST_NEXT(node)) { + + PKIX_PL_NSSCALLRV + (CERTSTORE, + nssCert, + CERT_DupCertificate, + (node->cert)); + + if (!nssCert) { + continue; /* just skip bad certs */ + } + + PKIX_CHECK_ONLY_FATAL(pkix_pl_Cert_CreateWithNSSCert + (nssCert, &cert, plContext), + PKIX_CERTCREATEWITHNSSCERTFAILED); + + if (PKIX_ERROR_RECEIVED) { + CERT_DestroyCertificate(nssCert); + nssCert = NULL; + continue; /* just skip bad certs */ + } + + PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem + (certList, (PKIX_PL_Object *)cert, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(cert); + + } + + /* Don't throw away the list if one cert was bad! */ + pkixTempErrorReceived = PKIX_FALSE; + } + + *pSelected = certList; + certList = NULL; + +cleanup: + + if (pk11CertList) { + CERT_DestroyCertList(pk11CertList); + } + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_DECREF(subjectName); + PKIX_DECREF(certValid); + PKIX_DECREF(cert); + PKIX_DECREF(certList); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_Pk11CertStore_ImportCrl + * DESCRIPTION: + * + * PARAMETERS: + * "params" + * Address of the ComCRLSelParams. Must be non-NULL. + * "pSelected" + * Address at which List will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Pk11CertStore_ImportCrl( + PKIX_CertStore *store, + PKIX_PL_X500Name *issuerName, + PKIX_List *crlList, + void *plContext) +{ + CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB(); + PKIX_PL_CRL *crl = NULL; + SECItem *derCrl = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ImportCrl"); + PKIX_NULLCHECK_TWO(store, plContext); + + if (!crlList) { + goto cleanup; + } + while (crlList->length > 0) { + PKIX_CHECK( + PKIX_List_GetItem(crlList, 0, (PKIX_PL_Object**)&crl, + plContext), + PKIX_LISTGETITEMFAILED); + + /* Delete crl from the list to keep controll of the + * last reference. crl need to be destroyed right after + * it released the ownership of the crl der. */ + PKIX_CHECK( + PKIX_List_DeleteItem(crlList, 0, plContext), + PKIX_LISTDELETEITEMFAILED); + + /* acquire the crlder ownership */ + pkixErrorResult = + PKIX_PL_CRL_ReleaseDerCrl(crl, &derCrl, plContext); + PORT_Assert(!pkixErrorResult && derCrl); + if (pkixErrorResult || !derCrl) { + /* All pkix delivered crls should be able to + * release their ders. */ + PKIX_DECREF(pkixErrorResult); + PKIX_DECREF(crl); + continue; + } + cert_CacheCRLByGeneralName(certHandle, derCrl, + crl->derGenName); + /* Do not check the status. If it is a SECFailure, + * derCrl is already destroyed. */ + derCrl = NULL; + PKIX_DECREF(crl); + } + +cleanup: + PKIX_DECREF(crl); + + PKIX_RETURN(CERTSTORE); +} + +static PKIX_Error * +NameCacheHasFetchedCrlInfo(PKIX_PL_Cert *pkixCert, + PRTime time, + PKIX_Boolean *pHasFetchedCrlInCache, + void *plContext) +{ + /* Returning true result in this case will mean, that case info + * is currect and should used as is. */ + NamedCRLCache* nameCrlCache = NULL; + PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE; + PKIX_List *dpList = NULL; + pkix_pl_CrlDp *dp = NULL; + PKIX_UInt32 dpIndex = 0; + SECStatus rv = SECSuccess; + PRTime reloadDelay = 0, badCrlInvalDelay = 0; + + PKIX_ENTER(CERTSTORE, "ChechCacheHasFetchedCrl"); + + reloadDelay = + ((PKIX_PL_NssContext*)plContext)->crlReloadDelay * + PR_USEC_PER_SEC; + badCrlInvalDelay = + ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay * + PR_USEC_PER_SEC; + if (!time) { + time = PR_Now(); + } + /* If we already download the crl and inserted into the cache, then + * there is no need to check for fetched crl. We have what we have. */ + PKIX_CHECK( + PKIX_PL_Cert_GetCrlDp(pkixCert, &dpList, plContext), + PKIX_CERTGETCRLDPFAILED); + if (dpList && dpList->length) { + hasFetchedCrlInCache = PKIX_FALSE; + rv = cert_AcquireNamedCRLCache(&nameCrlCache); + if (rv != SECSuccess) { + PKIX_DECREF(dpList); + } + } else { + /* If no dp then treat it as if we already have + * a fetched crl. */ + PKIX_DECREF(dpList); + } + for (;!hasFetchedCrlInCache && + dpList && dpIndex < dpList->length;dpIndex++) { + SECItem **derDpNames = NULL; + pkixErrorResult = + PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp, + plContext); + if (pkixErrorResult) { + PKIX_DECREF(pkixErrorResult); + continue; + } + if (dp->nssdp->distPointType == generalName) { + /* dp can only be created from nssdp. */ + derDpNames = dp->nssdp->derFullName; + } + while (derDpNames && *derDpNames != NULL) { + NamedCRLCacheEntry* cacheEntry = NULL; + const SECItem *derDpName = *derDpNames++; + rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName, + &cacheEntry); + if (rv == SECSuccess && cacheEntry) { + if ((cacheEntry->inCRLCache && + (cacheEntry->successfulInsertionTime + reloadDelay > time || + (cacheEntry->dupe && + cacheEntry->lastAttemptTime + reloadDelay > time))) || + (cacheEntry->badDER && + cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) { + hasFetchedCrlInCache = PKIX_TRUE; + break; + } + } + } + PKIX_DECREF(dp); + } +cleanup: + *pHasFetchedCrlInCache = hasFetchedCrlInCache; + if (nameCrlCache) { + cert_ReleaseNamedCRLCache(nameCrlCache); + } + PKIX_DECREF(dpList); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_Pk11CertStore_CheckCrl + * DESCRIPTION: + * + * PARAMETERS: + * "params" + * Address of the ComCRLSelParams. Must be non-NULL. + * "pSelected" + * Address at which List will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertStore Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Pk11CertStore_CheckRevByCrl( + PKIX_CertStore *store, + PKIX_PL_Cert *pkixCert, + PKIX_PL_Cert *pkixIssuer, + PKIX_PL_Date *date, + PKIX_Boolean crlDownloadDone, + CERTCRLEntryReasonCode *pReasonCode, + PKIX_RevocationStatus *pStatus, + void *plContext) +{ + PKIX_RevocationStatus pkixRevStatus = PKIX_RevStatus_NoInfo; + CERTRevocationStatus revStatus = certRevocationStatusUnknown; + PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE; + CERTCertificate *cert = NULL, *issuer = NULL; + SECStatus rv = SECSuccess; + void *wincx = NULL; + PRTime time = 0; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckRevByCrl"); + PKIX_NULLCHECK_FOUR(store, pkixCert, pkixIssuer, plContext); + + cert = pkixCert->nssCert; + issuer = pkixIssuer->nssCert; + if (date) { + PKIX_CHECK( + pkix_pl_Date_GetPRTime(date, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + } + PKIX_CHECK( + pkix_pl_NssContext_GetWincx((PKIX_PL_NssContext*)plContext, + &wincx), + PKIX_NSSCONTEXTGETWINCXFAILED); + /* No need to check any cDPs, since partitioned crls are not + * supported. If a ds does not point to partitioned crl, then + * the crl should be in issuer cache that is unrelated to any + * dp. Using NULL as a dp pointer to check it.*/ + rv = cert_CheckCertRevocationStatus(cert, issuer, NULL, + /* Will not validate the signature + * on the crl if time is not specified.*/ + time, wincx, &revStatus, pReasonCode); + if (rv == SECFailure) { + pkixRevStatus = PKIX_RevStatus_Revoked; + goto cleanup; + } + if (crlDownloadDone) { + if (revStatus == certRevocationStatusRevoked) { + pkixRevStatus = PKIX_RevStatus_Revoked; + } else if (revStatus == certRevocationStatusValid) { + pkixRevStatus = PKIX_RevStatus_Success; + } + } else { + pkixErrorResult = + NameCacheHasFetchedCrlInfo(pkixCert, time, &hasFetchedCrlInCache, + plContext); + if (pkixErrorResult) { + goto cleanup; + } + if (revStatus == certRevocationStatusRevoked && + (hasFetchedCrlInCache || + *pReasonCode != crlEntryReasoncertificatedHold)) { + pkixRevStatus = PKIX_RevStatus_Revoked; + } else if (revStatus == certRevocationStatusValid && + hasFetchedCrlInCache) { + pkixRevStatus = PKIX_RevStatus_Success; + } + } +cleanup: + *pStatus = pkixRevStatus; + + PKIX_RETURN(CERTSTORE); +} + + +/* + * FUNCTION: pkix_pl_Pk11CertStore_GetCert + * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h) + */ +PKIX_Error * +pkix_pl_Pk11CertStore_GetCert( + PKIX_CertStore *store, + PKIX_CertSelector *selector, + PKIX_VerifyNode *parentVerifyNode, + void **pNBIOContext, + PKIX_List **pCertList, + void *plContext) +{ + PKIX_UInt32 i = 0; + PKIX_UInt32 numFound = 0; + PKIX_PL_Cert *candidate = NULL; + PKIX_List *selected = NULL; + PKIX_List *filtered = NULL; + PKIX_CertSelector_MatchCallback selectorCallback = NULL; + PKIX_CertStore_CheckTrustCallback trustCallback = NULL; + PKIX_ComCertSelParams *params = NULL; + PKIX_Boolean cacheFlag = PKIX_FALSE; + PKIX_VerifyNode *verifyNode = NULL; + PKIX_Error *selectorError = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCert"); + PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCertList); + + *pNBIOContext = NULL; /* We don't use non-blocking I/O */ + + PKIX_CHECK(PKIX_CertSelector_GetMatchCallback + (selector, &selectorCallback, plContext), + PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); + + PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams + (selector, ¶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; + unsigned int dpIndex = 0; + PRTime time; + PRTime reloadDelay = 0, badCrlInvalDelay = 0; + SECStatus rv; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ListRemovePrtDp"); + + if (!dpList || !dpList->length) { + PKIX_RETURN(CERTSTORE); + } + reloadDelay = + ((PKIX_PL_NssContext*)plContext)->crlReloadDelay * + PR_USEC_PER_SEC; + badCrlInvalDelay = + ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay * + PR_USEC_PER_SEC; + PKIX_CHECK(pkix_pl_Date_GetPRTime(date, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + rv = cert_AcquireNamedCRLCache(&nameCrlCache); + if (rv == SECFailure) { + /* Baling out. Wont find out any thing useful. */ + PKIX_RETURN(CERTSTORE); + } + while (dpIndex < dpList->length) { + SECItem **derDpNames = NULL; + PKIX_Boolean removeDp = PKIX_FALSE; + + PKIX_CHECK( + PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp, + plContext), + PKIX_LISTGETITEMFAILED); + if (!dp->isPartitionedByReasonCode) { + /* See if we know about this dp anything why we should + * not use it to download a crl. */ + if (dp->nssdp->distPointType == generalName) { + /* dp can only be created from nssdp. */ + derDpNames = dp->nssdp->derFullName; + } else { + removeDp = PKIX_TRUE; + } + while (derDpNames && *derDpNames != NULL) { + NamedCRLCacheEntry* cacheEntry = NULL; + const SECItem *derDpName = *derDpNames++; + /* Removing from the list all dps that we know about. */ + rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName, + &cacheEntry); + if (rv && cacheEntry) { + if (cacheEntry->unsupported || + (cacheEntry->inCRLCache && + (cacheEntry->successfulInsertionTime + reloadDelay > time || + (cacheEntry->dupe && + cacheEntry->lastAttemptTime + reloadDelay > time))) || + (cacheEntry->badDER && + cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) { + removeDp = PKIX_TRUE; + } + } + } + } else { + /* Remove dp that point to a partitioned crl . RFC 5280 + * recommends against crl partitioned by reason code. + * Will skip such crls */ + removeDp = PKIX_TRUE; + } + if (removeDp) { + PKIX_CHECK_ONLY_FATAL( + pkix_List_Remove(dpList,(PKIX_PL_Object*)dp, + plContext), + PKIX_LISTGETITEMFAILED); + } else { + dpIndex += 1; + } + PKIX_DECREF(dp); + } + +cleanup: + if (nameCrlCache) { + cert_ReleaseNamedCRLCache(nameCrlCache); + } + PKIX_DECREF(dp); + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_Pk11CertStore_DownloadCrl + */ +static PKIX_Error * +DownloadCrl(pkix_pl_CrlDp *dp, PKIX_PL_CRL **crl, + const SEC_HttpClientFcnV1 *hcv1, void *plContext) +{ + char *location = NULL; + char *hostname = NULL; + char *path = NULL; + PRUint16 port; + SEC_HTTP_SERVER_SESSION pServerSession = NULL; + SEC_HTTP_REQUEST_SESSION pRequestSession = NULL; + PRUint16 myHttpResponseCode; + const char *myHttpResponseData = NULL; + PRUint32 myHttpResponseDataLen; + SECItem *uri = NULL; + SECItem *derCrlCopy = NULL; + CERTSignedCrl *nssCrl = NULL; + CERTGeneralName *genName = NULL; + SECItem **derGenNames = NULL; + SECItem *derGenName = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_DownloadCrl"); + + /* Do not support dps others than a one with GeneralName + * name type. */ + if (dp->distPointType != generalName || + !dp->nssdp->derFullName) { + PKIX_ERROR(PKIX_UNSUPPORTEDCRLDPTYPE); + } + genName = dp->name.fullName; + derGenNames = dp->nssdp->derFullName; + do { + derGenName = *derGenNames; + do { + if (!derGenName || + !genName->name.other.data) { + /* get to next name if no data. */ + break; + } + uri = &genName->name.other; + location = (char*)PR_Malloc(1 + uri->len); + if (!location) { + break; + } + PORT_Memcpy(location, uri->data, uri->len); + location[uri->len] = 0; + if (CERT_ParseURL(location, &hostname, + &port, &path) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL); + break; + } + + PORT_Assert(hostname != NULL); + PORT_Assert(path != NULL); + + if ((*hcv1->createSessionFcn)(hostname, port, + &pServerSession) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL); + break; + } + + if ((*hcv1->createFcn)(pServerSession, "http", path, "GET", + /* Users with slow connections might not get CRL revocation + checking for certs that use big CRLs because of the timeout + We absolutely need code that limits our retry attempts. + */ + PR_SecondsToInterval( + ((PKIX_PL_NssContext*)plContext)->timeoutSeconds), + &pRequestSession) != SECSuccess) { + break; + } + + myHttpResponseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + if (myHttpResponseDataLen < PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH) + myHttpResponseDataLen = PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH; + + /* We use a non-zero timeout, which means: + - the client will use blocking I/O + - TryFcn will not return WOULD_BLOCK nor a poll descriptor + - it's sufficient to call TryFcn once + */ + /* we don't want result objects larger than this: */ + if ((*hcv1->trySendAndReceiveFcn)( + pRequestSession, + NULL, + &myHttpResponseCode, + NULL, + NULL, + &myHttpResponseData, + &myHttpResponseDataLen) != SECSuccess) { + break; + } + + if (myHttpResponseCode != 200) { + break; + } + } while(0); + if (!myHttpResponseData) { + /* Going to the next one. */ + genName = CERT_GetNextGeneralName(genName); + derGenNames++; + } + /* Staing in the loop through all the names until + * we have a successful download. */ + } while (!myHttpResponseData && *derGenNames && + genName != dp->name.fullName); + /* Need this name to track the crl source location. */ + PORT_Assert(derGenName); + + if (!myHttpResponseData) { + /* Generating fake bad CRL to keep track of this dp */ + SECItem derCrl = {siBuffer, (void*)"BadCrl", 6 }; + + derCrlCopy = SECITEM_DupItem(&derCrl); + if (!derCrlCopy) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + derGenName = *dp->nssdp->derFullName; + } else { + SECItem derCrl = { siBuffer, + (void*)myHttpResponseData, + myHttpResponseDataLen }; + derCrlCopy = SECITEM_DupItem(&derCrl); + if (!derCrlCopy) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + /* crl will be based on derCrlCopy, but will not own the der. */ + nssCrl = + CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE, + CRL_DECODE_DONT_COPY_DER | + CRL_DECODE_SKIP_ENTRIES); + } + /* pkix crl owns the der. */ + PKIX_CHECK( + pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy, + derGenName, + crl, plContext), + PKIX_CRLCREATEWITHSIGNEDCRLFAILED); + /* pkix crl now own both objects. */ + derCrlCopy = NULL; + nssCrl = NULL; + +cleanup: + if (derCrlCopy) + PORT_Free(derCrlCopy); + if (nssCrl) + SEC_DestroyCrl(nssCrl); + if (pRequestSession != NULL) + (*hcv1->freeFcn)(pRequestSession); + if (pServerSession != NULL) + (*hcv1->freeSessionFcn)(pServerSession); + if (path != NULL) + PORT_Free(path); + if (hostname != NULL) + PORT_Free(hostname); + if (location) { + PORT_Free(location); + } + + PKIX_RETURN(CERTSTORE); +} + +/* + * FUNCTION: pkix_pl_Pk11CertStore_GetCRL + * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) + */ +static PKIX_Error * +pkix_pl_Pk11CertStore_GetCRL( + PKIX_CertStore *store, + PKIX_CRLSelector *selector, + void **pNBIOContext, + PKIX_List **pCrlList, + void *plContext) +{ + PKIX_UInt32 dpIndex = 0; + PKIX_PL_CRL *crl = NULL; + PKIX_List *crlList = NULL; + PKIX_List *dpList = NULL; + pkix_pl_CrlDp *dp = NULL; + PKIX_PL_Date *date = NULL; + const SEC_HttpClientFcn *registeredHttpClient = NULL; + + PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCRL"); + PKIX_NULLCHECK_THREE(store, pNBIOContext, pCrlList); + PKIX_NULLCHECK_TWO(selector, selector->params); + + registeredHttpClient = SEC_GetRegisteredHttpClient(); + if (!registeredHttpClient || registeredHttpClient->version != 1) { + goto cleanup; + } + dpList = selector->params->crldpList; + date = selector->params->date; + PKIX_CHECK( + RemovePartitionedDpsFromList(dpList, date, + plContext), + PKIX_FAILTOREMOVEDPFROMLIST); + for (;dpIndex < dpList->length;dpIndex++) { + PKIX_DECREF(dp); + pkixErrorResult = + PKIX_List_GetItem(dpList, dpIndex, + (PKIX_PL_Object **)&dp, + plContext); + if (pkixErrorResult) { + PKIX_DECREF(pkixErrorResult); + continue; + } + pkixErrorResult = + DownloadCrl(dp, &crl, + ®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/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h new file mode 100644 index 0000000000..506707683d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_pk11certstore.h + * + * PK11Certstore Object Type Definition + * + */ + +#ifndef _PKIX_PL_PK11CERTSTORE_H +#define _PKIX_PL_PK11CERTSTORE_H + +#include "pkix_pl_common.h" +#include "certi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* see source file for function documentation */ +PKIX_Error * +PKIX_PL_Pk11CertStore_Create( + PKIX_CertStore **pCertStore, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_PK11CERTSTORE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c new file mode 100644 index 0000000000..ac5e9d3796 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c @@ -0,0 +1,1695 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_socket.c + * + * Socket Function Definitions + * + */ + +/* + * If Socket Tracing is active, messages sent and received will be + * timestamped and dumped (to stdout) in standard hex-dump format. E.g., + * + * 1116612359156140: + * 28F0: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 Hello, world!. + * + * The timestamp is not formatted to be meaningful except as an increasing + * value of seconds.microseconds, which is good enough to correlate two + * sides of a message exchange and to figure durations. + * + * Code to perform Socket tracing will be compiled in if PKIX_SOCKETTRACE + * is defined, but that doesn't mean socket tracing is active. Tracing also + * requires that the Boolean socketTraceFlag is set to PKIX_TRUE. That is + * the default value, but it can be overridden by using the debugger to + * change its value -- allowing tracing to be turned on and off at various + * breakpoints -- or by setting the environment variable SOCKETTRACE. A + * value of 1 sets socketTraceFlag to PKIX_TRUE (tracing on), and any other + * value sets socketTraceFlag to PKIX_FALSE (tracing off). The environment + * value is checked during system initialization. + */ +#ifndef BUILD_OPT +#define PKIX_SOCKETTRACE 1 +#endif + +#ifdef PKIX_SOCKETDEBUG +#define PKIX_SOCKETTRACE 1 +#endif + +#include "pkix_pl_socket.h" + +/* --Private-Socket-Functions---------------------------------- */ + +#ifdef PKIX_SOCKETTRACE +static PKIX_Boolean socketTraceFlag = PKIX_FALSE; + +/* + * FUNCTION: pkix_pl_socket_timestamp + * DESCRIPTION: + * + * This functions prints to stdout the time of day, as obtained from the + * system function gettimeofday, as seconds.microseconds. Its resolution + * is whatever the system call provides. + * + * PARAMETERS: + * none + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static void pkix_pl_socket_timestamp() { + PRInt64 prTime; + prTime = PR_Now(); +/* We shouldn't use PR_ALTERNATE_INT64_TYPEDEF, but nor can we use PRId64 */ +#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF) + printf("%ld:\n", prTime); +#else + printf("%lld:\n", prTime); +#endif +} + +/* + * FUNCTION: pkix_pl_socket_hexDigit + * DESCRIPTION: + * + * This functions prints to stdout the byte "byteVal" as two hex digits. + * + * PARAMETERS: + * "byteVal" + * The value to be printed. + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static void pkix_pl_socket_hexDigit(char byteVal) { + int n = 0; + char cHi = '\0'; + char cLow = '\0'; + n = ((byteVal >> 4) & 0xf); + if (n > 9) { + cHi = (char) ((n - 10) + 'A'); + } else { + cHi = (char) (n + '0'); + } + n = byteVal & 0xf; + if (n > 9) { + cLow = (char) ((n - 10) + 'A'); + } else { + cLow = (char) (n + '0'); + } + (void) printf("%c%c", cHi, cLow); +} + +/* + * FUNCTION: pkix_pl_socket_linePrefix + * DESCRIPTION: + * + * This functions prints to stdout the address provided by "addr" as four + * hexadecimal digits followed by a colon and a space. + * + * PARAMETERS: + * "addr" + * The address to be printed + * none + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static void pkix_pl_socket_linePrefix(PKIX_UInt32 addr) { + pkix_pl_socket_hexDigit((char)((addr >> 8) & 0xff)); + pkix_pl_socket_hexDigit((char)(addr & 0xff)); + (void) printf(": "); +} + +/* + * FUNCTION: pkix_pl_socket_traceLine + * DESCRIPTION: + * + * This functions prints to stdout the sixteen bytes beginning at the + * address pointed to by "ptr". The bytes are printed as sixteen pairs + * of hexadecimal characters followed by an ascii interpretation, in which + * characters from 0x20 to 0x7d are shown as their ascii equivalents, and + * other values are represented as periods. + * + * PARAMETERS: + * "ptr" + * The address of the first of the bytes to be printed + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static void pkix_pl_socket_traceLine(char *ptr) { + PKIX_UInt32 i = 0; + pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL)); + for (i = 0; i < 16; i++) { + printf(" "); + pkix_pl_socket_hexDigit(ptr[i]); + if (i == 7) { + printf(" "); + } + } + printf(" "); + for (i = 0; i < 16; i++) { + if ((ptr[i] < ' ') || (ptr[i] > '}')) { + printf("."); + } else { + printf("%c", ptr[i]); + } + } + printf("\n"); +} + +/* + * FUNCTION: pkix_pl_socket_tracePartialLine + * DESCRIPTION: + * + * This functions prints to stdout the number of bytes given by "nBytes", + * beginning at the address pointed to by "ptr". The bytes are printed as + * pairs of hexadecimal characters followed by an ascii interpretation, in + * which characters from 0x20 to 0x7d are shown as their ascii equivalents, + * and other values are represented as periods. + * + * PARAMETERS: + * "ptr" + * The address of the first of the bytes to be printed + * "nBytes" + * The Int32 value giving the number of bytes to be printed. If "nBytes" + * is greater than sixteen, the results will be unattractive. + * none + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static void pkix_pl_socket_tracePartialLine(char *ptr, PKIX_UInt32 nBytes) { + PKIX_UInt32 i = 0; + if (nBytes > 0) { + pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL)); + } + for (i = 0; i < nBytes; i++) { + printf(" "); + pkix_pl_socket_hexDigit(ptr[i]); + if (i == 7) { + printf(" "); + } + } + for (i = nBytes; i < 16; i++) { + printf(" "); + if (i == 7) { + printf(" "); + } + } + printf(" "); + for (i = 0; i < nBytes; i++) { + if ((ptr[i] < ' ') || (ptr[i] > '}')) { + printf("."); + } else { + printf("%c", ptr[i]); + } + } + printf("\n"); +} + +/* + * FUNCTION: pkix_pl_socket_tracebuff + * DESCRIPTION: + * + * This functions prints to stdout the number of bytes given by "nBytes", + * beginning with the byte pointed to by "buf". The output is preceded by + * a timestamp, and each group of sixteen (and a remainder, if any) is + * preceded by its address. The contents are shown in hexadecimal and as + * ascii characters. If "nBytes" is zero, the timestamp and starting + * address are displayed. + * + * PARAMETERS: + * "buf" + * The starting address of the bytes to be printed + * "nBytes" + * The number of bytes to be printed + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +void pkix_pl_socket_tracebuff(void *buf, PKIX_UInt32 nBytes) { + PKIX_UInt32 bytesRemaining = nBytes; + PKIX_UInt32 offset = 0; + char *bufptr = (char *)buf; + + if (socketTraceFlag == PKIX_FALSE) return; + + pkix_pl_socket_timestamp(); + /* + * Special case: if called with length of zero, just do address + */ + if (nBytes == 0) { + pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)buf - (char *)NULL)); + printf("\n"); + } else { + while (bytesRemaining >= 16) { + pkix_pl_socket_traceLine(&bufptr[offset]); + bytesRemaining -= 16; + offset += 16; + } + pkix_pl_socket_tracePartialLine + (&bufptr[offset], bytesRemaining); + } +} + +#endif + +/* + * FUNCTION: pkix_pl_Socket_SetNonBlocking + * DESCRIPTION: + * + * This functions sets the socket represented by the PRFileDesc "fileDesc" + * to nonblocking mode. + * + * PARAMETERS: + * "fileDesc" + * The address of the PRFileDesc whose I/O mode is to be set + * non-blocking. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_SetNonBlocking( + PRFileDesc *fileDesc, + void *plContext) +{ + PRStatus rv = PR_FAILURE; + PRSocketOptionData sockOptionData; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_SetNonBlocking"); + PKIX_NULLCHECK_ONE(fileDesc); + + sockOptionData.option = PR_SockOpt_Nonblocking; + sockOptionData.value.non_blocking = PR_TRUE; + + PKIX_PL_NSSCALLRV(SOCKET, rv, fileDesc->methods->setsocketoption, + (fileDesc, &sockOptionData)); + + if (rv != PR_SUCCESS) { + PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING); + } +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_CreateClient + * DESCRIPTION: + * + * This functions creates a client socket for the PKIX_PL_Socket pointed to + * by "socket". If "socket" was created with a timeout value of zero, the + * client socket is set to use nonblocking I/O. + * + * PARAMETERS: + * "socket" + * The address of the Socket for which a client socket is to be + * created. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ + +static PKIX_Error * +pkix_pl_Socket_CreateClient( + PKIX_PL_Socket *socket, + void *plContext) +{ +#ifdef PKIX_SOCKETDEBUG + PRErrorCode errorcode = 0; +#endif + PRFileDesc *mySock = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateClient"); + PKIX_NULLCHECK_ONE(socket); + + PKIX_PL_NSSCALLRV(SOCKET, mySock, PR_NewTCPSocket, ()); + if (!mySock) { +#ifdef PKIX_SOCKETDEBUG + errorcode = PR_GetError(); + printf + ("pkix_pl_Socket_CreateClient: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED); + } + +#ifdef PKIX_SOCKETDEBUG + printf("Created socket, PRFileDesc @ %#X\n", mySock); +#endif + + socket->clientSock = mySock; + socket->status = SOCKET_UNCONNECTED; + if (socket->timeout == 0) { + PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(mySock, plContext), + PKIX_SOCKETSETNONBLOCKINGFAILED); + } + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_CreateServer + * DESCRIPTION: + * + * This functions creates a server socket for the PKIX_PL_Socket pointed to + * by "socket". If "socket" was created with a timeout value of zero, the + * server socket is set to use nonblocking I/O. + * + * Warning: there seems to be a problem with operating a server socket in + * non-blocking mode. If the server calls Recv prior to a corresponding + * Send, the message may be lost. + * + * PARAMETERS: + * "socket" + * The address of the Socket for which a server socket is to be + * created. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_CreateServer( + PKIX_PL_Socket *socket, + void *plContext) +{ +/* #ifdef PKIX_SOCKETDEBUG */ + PRErrorCode errorcode = 0; +/* #endif */ + PRStatus rv = PR_FAILURE; + PRFileDesc *serverSock = NULL; + PRSocketOptionData sockOptionData; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateServer"); + PKIX_NULLCHECK_ONE(socket); + + PKIX_PL_NSSCALLRV(SOCKET, serverSock, PR_NewTCPSocket, ()); + if (!serverSock) { +#ifdef PKIX_SOCKETDEBUG + errorcode = PR_GetError(); + printf + ("pkix_pl_Socket_CreateServer: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED); + } + + socket->serverSock = serverSock; + +#ifdef PKIX_SOCKETDEBUG + printf("Created socket, PRFileDesc @ %#X\n", serverSock); +#endif + + if (socket->timeout == 0) { + PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(serverSock, plContext), + PKIX_SOCKETSETNONBLOCKINGFAILED); + } + + sockOptionData.option = PR_SockOpt_Reuseaddr; + sockOptionData.value.reuse_addr = PR_TRUE; + + PKIX_PL_NSSCALLRV(SOCKET, rv, serverSock->methods->setsocketoption, + (serverSock, &sockOptionData)); + + if (rv != PR_SUCCESS) { + PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING); + } + + PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Bind, (serverSock, socket->netAddr)); + + if (rv == PR_FAILURE) { +/* #ifdef PKIX_SOCKETDEBUG */ + errorcode = PR_GetError(); + printf + ("pkix_pl_Socket_CreateServer: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +/* #endif */ + PKIX_ERROR(PKIX_PRBINDFAILED); + } + +#ifdef PKIX_SOCKETDEBUG + printf("Successful bind!\n"); +#endif + + socket->status = SOCKET_BOUND; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Connect + * DESCRIPTION: + * + * This functions performs the connect function for the client socket + * specified in "socket", storing the status at "pStatus". + * + * PARAMETERS: + * "socket" + * The address of the Socket for which a connect is to be performed. + * Must be non-NULL. + * "pStatus" + * The address at which the connection status is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_Connect( + PKIX_PL_Socket *socket, + PRErrorCode *pStatus, + void *plContext) +{ + PRStatus rv = PR_FAILURE; + PRErrorCode errorcode = 0; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Connect"); + PKIX_NULLCHECK_TWO(socket, socket->clientSock); + + PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Connect, + (socket->clientSock, socket->netAddr, socket->timeout)); + + if (rv == PR_FAILURE) { + errorcode = PR_GetError(); + *pStatus = errorcode; + if (errorcode == PR_IN_PROGRESS_ERROR) { + socket->status = SOCKET_CONNECTPENDING; + goto cleanup; + } else { +#ifdef PKIX_SOCKETDEBUG + printf + ("pkix_pl_Socket_Connect: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRCONNECTFAILED); + } + } + +#ifdef PKIX_SOCKETDEBUG + printf("Successful connect!\n"); +#endif + + *pStatus = 0; + socket->status = SOCKET_CONNECTED; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_ConnectContinue + * DESCRIPTION: + * + * This functions continues the connect function for the client socket + * specified in "socket", storing the status at "pStatus". It is expected that + * the non-blocking connect has returned PR_IN_PROGRESS_ERROR. + * + * PARAMETERS: + * "socket" + * The address of the Socket for which a connect is to be continued. + * Must be non-NULL. + * "pStatus" + * The address at which the connection status is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_ConnectContinue( + PKIX_PL_Socket *socket, + PRErrorCode *pStatus, + void *plContext) +{ + PRStatus rv = PR_FAILURE; + PRErrorCode errorcode = 0; + PRPollDesc pollDesc; + PRInt32 numEvents = 0; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_ConnectContinue"); + PKIX_NULLCHECK_TWO(socket, socket->clientSock); + + pollDesc.fd = socket->clientSock; + pollDesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + pollDesc.out_flags = 0; + PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0)); + if (numEvents < 0) { + PKIX_ERROR(PKIX_PRPOLLFAILED); + } + + if (numEvents == 0) { + *pStatus = PR_IN_PROGRESS_ERROR; + goto cleanup; + } + + PKIX_PL_NSSCALLRV(SOCKET, rv, PR_ConnectContinue, + (socket->clientSock, pollDesc.out_flags)); + + /* + * PR_ConnectContinue sometimes lies. It returns PR_SUCCESS + * even though the connection is not yet ready. But its deceit + * is betrayed by the contents of out_flags! + */ + if ((rv == PR_SUCCESS) && (pollDesc.out_flags == PR_POLL_ERR)) { + *pStatus = PR_IN_PROGRESS_ERROR; + goto cleanup; + } + + if (rv == PR_FAILURE) { + errorcode = PR_GetError(); + *pStatus = errorcode; + if (errorcode == PR_IN_PROGRESS_ERROR) { + goto cleanup; + } else { +#ifdef PKIX_SOCKETDEBUG + printf + ("pkix_pl_Socket_ConnectContinue: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRCONNECTCONTINUEFAILED); + } + } + +#ifdef PKIX_SOCKETDEBUG + printf("Successful connect!\n"); +#endif + + *pStatus = 0; + socket->status = SOCKET_CONNECTED; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Socket_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Socket *socket = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_SOCKET_TYPE, plContext), + PKIX_OBJECTNOTANSOCKET); + + socket = (PKIX_PL_Socket *)object; + + if (socket->isServer) { + if (socket->serverSock) { + PR_Close(socket->serverSock); + } + } else { + if (socket->clientSock) { + PR_Close(socket->clientSock); + } + } + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Socket_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_Socket *socket = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_SOCKET_TYPE, plContext), + PKIX_OBJECTNOTSOCKET); + + socket = (PKIX_PL_Socket *)object; + + *pHashcode = (((socket->timeout << 3) + + (socket->netAddr->inet.family << 3)) + + (*((PKIX_UInt32 *)&(socket->netAddr->inet.ip)))) + + socket->netAddr->inet.port; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Socket_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_PL_Socket *firstSocket = NULL; + PKIX_PL_Socket *secondSocket = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + *pResult = PKIX_FALSE; + + PKIX_CHECK(pkix_CheckTypes + (firstObject, secondObject, PKIX_SOCKET_TYPE, plContext), + PKIX_OBJECTNOTSOCKET); + + firstSocket = (PKIX_PL_Socket *)firstObject; + secondSocket = (PKIX_PL_Socket *)secondObject; + + if (firstSocket->timeout != secondSocket->timeout) { + goto cleanup; + } + + if (firstSocket->netAddr == secondSocket->netAddr) { + *pResult = PKIX_TRUE; + goto cleanup; + } + + if ((firstSocket->netAddr->inet.family != + secondSocket->netAddr->inet.family) || + (*((PKIX_UInt32 *)&(firstSocket->netAddr->inet.ip)) != + *((PKIX_UInt32 *)&(secondSocket->netAddr->inet.ip))) || + (firstSocket->netAddr->inet.port != + secondSocket->netAddr->inet.port)) { + + goto cleanup; + + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_PL_SOCKET_TYPE and its related + * functions with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_Socket_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_RegisterSelf"); + + entry.description = "Socket"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_Socket); + entry.destructor = pkix_pl_Socket_Destroy; + entry.equalsFunction = pkix_pl_Socket_Equals; + entry.hashcodeFunction = pkix_pl_Socket_Hashcode; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_SOCKET_TYPE] = entry; + +#ifdef PKIX_SOCKETTRACE + { + char *val = NULL; + val = PR_GetEnvSecure("SOCKETTRACE"); + /* Is SOCKETTRACE set in the environment? */ + if ((val != NULL) && (*val != '\0')) { + socketTraceFlag = + ((*val == '1')?PKIX_TRUE:PKIX_FALSE); + } + } +#endif + + PKIX_RETURN(SOCKET); +} + +/* --Public-Socket-Functions----------------------------------- */ + +/* + * FUNCTION: pkix_pl_Socket_Listen + * DESCRIPTION: + * + * This functions establishes a listening queue for the server Socket + * pointed to by "socket". + * + * PARAMETERS: + * "socket" + * The address of the server socket for which the queue is to be + * established. Must be non-NULL. + * "backlog" + * The UInt32 value of the length of the queue to be established. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_Listen( + PKIX_PL_Socket *socket, + PKIX_UInt32 backlog, + void *plContext) +{ +#ifdef PKIX_SOCKETDEBUG + PRErrorCode errorcode = 0; +#endif + PRStatus rv = PR_FAILURE; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Listen"); + PKIX_NULLCHECK_TWO(socket, socket->serverSock); + + PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Listen, + (socket->serverSock, (PRIntn)backlog)); + + if (rv == PR_FAILURE) { +#ifdef PKIX_SOCKETDEBUG + errorcode = PR_GetError(); + printf + ("pkix_pl_Socket_Listen: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRLISTENFAILED); + } + +#ifdef PKIX_SOCKETDEBUG + printf("Successful listen!\n"); +#endif + + socket->status = SOCKET_LISTENING; +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Shutdown + * DESCRIPTION: + * + * This functions performs the shutdown of any connections controlled by the + * socket pointed to by "socket". + * + * PARAMETERS: + * "socket" + * The address of the socket to be shut down. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_Shutdown( + PKIX_PL_Socket *socket, + void *plContext) +{ +#ifdef PKIX_SOCKETDEBUG + PRErrorCode errorcode = 0; +#endif + PRStatus rv = PR_FAILURE; + PRFileDesc *fileDesc = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Shutdown"); + PKIX_NULLCHECK_ONE(socket); + + fileDesc = + (socket->isServer)?(socket->serverSock):(socket->clientSock); + + PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Shutdown, + (fileDesc, PR_SHUTDOWN_BOTH)); + + if (rv == PR_FAILURE) { +#ifdef PKIX_SOCKETDEBUG + errorcode = PR_GetError(); + printf + ("pkix_pl_Socket_Shutdown: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRSHUTDOWNFAILED); + } + socket->status = SOCKET_SHUTDOWN; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Send + * DESCRIPTION: + * + * This functions sends a message using the socket pointed to by "sendSock", + * from the buffer pointed to by "buf", of the number of bytes given by + * "bytesToWrite", storing the number of bytes actually written at + * "pBytesWritten". If "socket" is in non-blocking mode, the send operation + * may store -1 at "pBytesWritten" and the write is not complete until a + * corresponding pkix_pl_Poll call has indicated its completion by returning + * a non-negative value for bytes written. + * + * PARAMETERS: + * "sendSock" + * The address of the Socket on which the message is to be sent. Must + * be non-NULL. + * "buf" + * The address of the data to be sent. Must be non-NULL. + * "bytesToWrite"" + * The UInt32 value indicating the number of bytes to write. + * "pBytesWritten" + * The address at which the Int32 value indicating the number of bytes + * actually written is to be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_Send( + PKIX_PL_Socket *sendSock, + void *buf, + PKIX_UInt32 bytesToWrite, + PKIX_Int32 *pBytesWritten, + void *plContext) +{ + PRInt32 bytesWritten = 0; + PRErrorCode errorcode = 0; + PRFileDesc *fd = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Send"); + PKIX_NULLCHECK_TWO(buf, pBytesWritten); + + fd = sendSock->clientSock; + + PKIX_PL_NSSCALLRV(SOCKET, bytesWritten, PR_Send, + (fd, buf, (PRInt32)bytesToWrite, 0, sendSock->timeout)); + + if (bytesWritten >= 0) { + if (sendSock->status == SOCKET_SENDRCVPENDING) { + sendSock->status = SOCKET_RCVPENDING; + } else { + sendSock->status = SOCKET_CONNECTED; + } +#ifdef PKIX_SOCKETTRACE + pkix_pl_socket_tracebuff(buf, bytesWritten); +#endif + } else { + errorcode = PR_GetError(); + if (errorcode != PR_WOULD_BLOCK_ERROR) { +#ifdef PKIX_SOCKETDEBUG + printf + ("pkix_pl_Socket_Send: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRSENDFAILED); + } + + sendSock->writeBuf = buf; + sendSock->writeBufSize = bytesToWrite; + if (sendSock->status == SOCKET_RCVPENDING) { + sendSock->status = SOCKET_SENDRCVPENDING; + } else { + sendSock->status = SOCKET_SENDPENDING; + } + } + + *pBytesWritten = (PKIX_Int32)bytesWritten; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Recv + * DESCRIPTION: + * + * This functions receives a message on the socket pointed to by "rcvSock", + * into the buffer pointed to by "buf", of capacity given by "capacity", + * storing the number of bytes actually received at "pBytesRead". If "socket" + * is in non-blocking mode, the receive operation may store -1 at + * "pBytesWritten". In that case the write is not complete until a + * corresponding pkix_pl_Poll call has indicated its completion by returning + * a non-negative value for bytes read. + * + * PARAMETERS: + * "rcvSock" + * The address of the Socket on which the message is to be received. + * Must be non-NULL. + * "buf" + * The address of the buffer into which the message is to be received. + * Must be non-NULL. + * "capacity" + * The UInt32 value of the size of the buffer; that is, the maximum + * number of bytes that can be received. + * "pBytesRead" + * The address at which is stored the Int32 value of the number of bytes + * actually received. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_Recv( + PKIX_PL_Socket *rcvSock, + void *buf, + PKIX_UInt32 capacity, + PKIX_Int32 *pBytesRead, + void *plContext) +{ + PRErrorCode errorcode = 0; + PRInt32 bytesRead = 0; + PRFileDesc *fd = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Recv"); + PKIX_NULLCHECK_THREE(rcvSock, buf, pBytesRead); + + fd = rcvSock->clientSock; + + PKIX_PL_NSSCALLRV(SOCKET, bytesRead, PR_Recv, + (fd, buf, (PRInt32)capacity, 0, rcvSock->timeout)); + + if (bytesRead > 0) { + if (rcvSock->status == SOCKET_SENDRCVPENDING) { + rcvSock->status = SOCKET_SENDPENDING; + } else { + rcvSock->status = SOCKET_CONNECTED; + } +#ifdef PKIX_SOCKETTRACE + pkix_pl_socket_tracebuff(buf, bytesRead); +#endif + } else if (bytesRead == 0) { + PKIX_ERROR(PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED); + } else { + errorcode = PR_GetError(); + if (errorcode != PR_WOULD_BLOCK_ERROR) { +#ifdef PKIX_SOCKETDEBUG + printf + ("pkix_pl_Socket_Recv: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRRECVFAILED); + } + rcvSock->readBuf = buf; + rcvSock->readBufSize = capacity; + if (rcvSock->status == SOCKET_SENDPENDING) { + rcvSock->status = SOCKET_SENDRCVPENDING; + } else { + rcvSock->status = SOCKET_RCVPENDING; + } + + } + + *pBytesRead = (PKIX_Int32)bytesRead; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Poll + * DESCRIPTION: + * + * This functions checks for completion of an earlier Send or Recv on the + * socket pointed to by "sock", storing in "pBytesWritten" the number of bytes + * written by a completed Send and in "pBytesRead" the number of bytes + * received in a completed Recv. A value of -1 returned indicates the + * operation has still not completed. A NULL pointer may be supplied for + * "pBytesWritten" to avoid checking for completion of a Send. A NULL pointer + * may be supplied for "pBytesRead" to avoid checking for completion of a Recv. + * + * PARAMETERS: + * "sock" + * The address of the socket for which completions are to be checked. + * "pBytesWritten" + * The address at which the number of bytes written is to be stored, if + * a pending Send has completed. If NULL, Sends are not checked. + * "pBytesRead" + * The address at which the number of bytes read is to be stored, if + * a pending Recv has completed. If NULL, Recvs are not checked. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_Poll( + PKIX_PL_Socket *sock, + PKIX_Int32 *pBytesWritten, + PKIX_Int32 *pBytesRead, + void *plContext) +{ + PRPollDesc pollDesc; + PRInt32 numEvents = 0; + PKIX_Int32 bytesRead = 0; + PKIX_Int32 bytesWritten = 0; + PRErrorCode errorcode = 0; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Poll"); + PKIX_NULLCHECK_ONE(sock); + + pollDesc.fd = sock->clientSock; + pollDesc.in_flags = 0; + pollDesc.out_flags = 0; + + if ((pBytesWritten) && + ((sock->status == SOCKET_SENDPENDING) || + (sock->status == SOCKET_SENDRCVPENDING))) { + pollDesc.in_flags = PR_POLL_WRITE; + } + + if ((pBytesRead) && + ((sock->status == SOCKET_RCVPENDING) || + (sock->status == SOCKET_SENDRCVPENDING))) { + pollDesc.in_flags |= PR_POLL_READ; + } + + PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0)); + + if (numEvents < 0) { + PKIX_ERROR(PKIX_PRPOLLFAILED); + } else if (numEvents > 0) { + if (pollDesc.out_flags & PR_POLL_WRITE) { + PKIX_CHECK(pkix_pl_Socket_Send + (sock, + sock->writeBuf, + sock->writeBufSize, + &bytesWritten, + plContext), + PKIX_SOCKETSENDFAILED); + *pBytesWritten = (PKIX_Int32)bytesWritten; + if (bytesWritten >= 0) { + sock->writeBuf = NULL; + sock->writeBufSize = 0; + } + } + + if (pollDesc.out_flags & PR_POLL_READ) { + PKIX_CHECK(pkix_pl_Socket_Recv + (sock, + sock->readBuf, + sock->readBufSize, + &bytesRead, + plContext), + PKIX_SOCKETRECVFAILED); + *pBytesRead = (PKIX_Int32)bytesRead; + if (bytesRead >= 0) { + sock->readBuf = NULL; + sock->readBufSize = 0; + } + } + } else if (numEvents == 0) { + errorcode = PR_GetError(); + if (errorcode != PR_WOULD_BLOCK_ERROR) { +#ifdef PKIX_SOCKETDEBUG + printf + ("pkix_pl_Socket_Poll: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRPOLLFAILED); + } + if (pBytesWritten) { + *pBytesWritten = 0; + } + if (pBytesRead) { + *pBytesRead = 0; + } + } + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Accept + * DESCRIPTION: + * + * This functions accepts a client connection for the server Socket pointed + * to by "serverSocket", creating a new Socket and storing the result at + * "pRendezvousSocket". If "serverSocket" is in non-blocking mode, this + * function will return NULL if there is no client connection to accept. + * Otherwise this function will block until a connection is available. + * When a client connection is available the new Socket will have the same + * blocking/non-blocking property as "serverSocket". + * + * PARAMETERS: + * "serverSocket" + * The address of the Socket for which a client connection is to be + * accepted. Must be non-NULL. + * "pRendezvousSocket" + * The address at which the created Socket is stored, when a client + * connection is available, or at which NULL is stored, if no connection + * is available for a non-blocking "serverSocket". Must be non-NULL. + * "plContext" + * Platform-specific context pointer + * THREAD SAFETY: + * Thread Safe (see Thread Safety definitions in Programmer's Guide) + * RETURNS: + * none + */ +static PKIX_Error * +pkix_pl_Socket_Accept( + PKIX_PL_Socket *serverSocket, + PKIX_PL_Socket **pRendezvousSocket, + void *plContext) +{ + PRErrorCode errorcode = 0; + PRFileDesc *rendezvousSock = NULL; + PRNetAddr *clientAddr = NULL; + PKIX_PL_Socket *newSocket = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Accept"); + PKIX_NULLCHECK_TWO(serverSocket, pRendezvousSocket); + + PKIX_PL_NSSCALLRV(SOCKET, rendezvousSock, PR_Accept, + (serverSocket->serverSock, clientAddr, serverSocket->timeout)); + + if (!rendezvousSock) { + errorcode = PR_GetError(); + if (errorcode != PR_WOULD_BLOCK_ERROR) { +#ifdef PKIX_SOCKETDEBUG + printf + ("pkix_pl_Socket_Accept: %s\n", + PR_ErrorToString(errorcode, PR_LANGUAGE_EN)); +#endif + PKIX_ERROR(PKIX_PRACCEPTFAILED); + } + serverSocket->status = SOCKET_ACCEPTPENDING; + *pRendezvousSocket = NULL; + goto cleanup; + + } + +#ifdef PKIX_SOCKETDEBUG + printf("Successful accept!\n"); +#endif + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_SOCKET_TYPE, + sizeof (PKIX_PL_Socket), + (PKIX_PL_Object **)&newSocket, + plContext), + PKIX_COULDNOTCREATESOCKETOBJECT); + + newSocket->isServer = PKIX_FALSE; + newSocket->timeout = serverSocket->timeout; + newSocket->clientSock = rendezvousSock; + newSocket->serverSock = NULL; + newSocket->netAddr = NULL; + newSocket->status = SOCKET_CONNECTED; + newSocket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; + newSocket->callbackList.listenCallback = pkix_pl_Socket_Listen; + newSocket->callbackList.acceptCallback = pkix_pl_Socket_Accept; + newSocket->callbackList.connectcontinueCallback = + pkix_pl_Socket_ConnectContinue; + newSocket->callbackList.sendCallback = pkix_pl_Socket_Send; + newSocket->callbackList.recvCallback = pkix_pl_Socket_Recv; + newSocket->callbackList.pollCallback = pkix_pl_Socket_Poll; + + if (serverSocket->timeout == 0) { + PKIX_CHECK(pkix_pl_Socket_SetNonBlocking + (rendezvousSock, plContext), + PKIX_SOCKETSETNONBLOCKINGFAILED); + } + + *pRendezvousSocket = newSocket; + +cleanup: + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_Create + * DESCRIPTION: + * + * This function creates a new Socket, setting it to be a server or a client + * according to the value of "isServer", setting its timeout value from + * "timeout" and server address from "netAddr", and stores the created Socket + * at "pSocket". + * + * PARAMETERS: + * "isServer" + * The Boolean value indicating if PKIX_TRUE, that a server socket (using + * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a + * client socket (using Connect) is to be created. + * "timeout" + * A PRTimeInterval value to be used for I/O waits for this socket. If + * zero, non-blocking I/O is to be used. + * "netAddr" + * The PRNetAddr to be used for the Bind function, if this is a server + * socket, or for the Connect, if this is a client socket. + * "pSocket" + * The address at which the Socket is to be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Socket Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_Socket_Create( + PKIX_Boolean isServer, + PRIntervalTime timeout, + PRNetAddr *netAddr, + PRErrorCode *status, + PKIX_PL_Socket **pSocket, + void *plContext) +{ + PKIX_PL_Socket *socket = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_Create"); + PKIX_NULLCHECK_ONE(pSocket); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_SOCKET_TYPE, + sizeof (PKIX_PL_Socket), + (PKIX_PL_Object **)&socket, + plContext), + PKIX_COULDNOTCREATESOCKETOBJECT); + + socket->isServer = isServer; + socket->timeout = timeout; + socket->clientSock = NULL; + socket->serverSock = NULL; + socket->netAddr = netAddr; + + socket->callbackList.listenCallback = pkix_pl_Socket_Listen; + socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; + socket->callbackList.connectcontinueCallback = + pkix_pl_Socket_ConnectContinue; + socket->callbackList.sendCallback = pkix_pl_Socket_Send; + socket->callbackList.recvCallback = pkix_pl_Socket_Recv; + socket->callbackList.pollCallback = pkix_pl_Socket_Poll; + socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; + + if (isServer) { + PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), + PKIX_SOCKETCREATESERVERFAILED); + *status = 0; + } else { + socket->timeout = timeout; + PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), + PKIX_SOCKETCREATECLIENTFAILED); + PKIX_CHECK(pkix_pl_Socket_Connect(socket, status, plContext), + PKIX_SOCKETCONNECTFAILED); + } + + *pSocket = socket; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(socket); + } + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_CreateByName + * DESCRIPTION: + * + * This function creates a new Socket, setting it to be a server or a client + * according to the value of "isServer", setting its timeout value from + * "timeout" and server address and port number from "serverName", and stores + * the status at "pStatus" and the created Socket at "pSocket". + * + * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip + * address of PR_INADDR_ANY. + * + * PARAMETERS: + * "isServer" + * The Boolean value indicating if PKIX_TRUE, that a server socket (using + * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a + * client socket (using Connect) is to be created. + * "timeout" + * A PRTimeInterval value to be used for I/O waits for this socket. If + * zero, non-blocking I/O is to be used. + * "serverName" + * Address of a character string consisting of the server's domain name + * followed by a colon and a port number for the desired socket. + * "pStatus" + * Address at which the PRErrorCode resulting from the create is + * stored. Must be non-NULL. + * "pSocket" + * The address at which the Socket is to be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Socket Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_Socket_CreateByName( + PKIX_Boolean isServer, + PRIntervalTime timeout, + char *serverName, + PRErrorCode *pStatus, + PKIX_PL_Socket **pSocket, + void *plContext) +{ + PRNetAddr netAddr; + PKIX_PL_Socket *socket = NULL; + char *sepPtr = NULL; + PRHostEnt hostent; + PRIntn hostenum; + PRStatus prstatus = PR_FAILURE; + char buf[PR_NETDB_BUF_SIZE]; + PRUint16 portNum = 0; + char *localCopyName = NULL; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByName"); + PKIX_NULLCHECK_TWO(serverName, pSocket); + + localCopyName = PL_strdup(serverName); + + sepPtr = strchr(localCopyName, ':'); + /* First strip off the portnum, if present, from the end of the name */ + if (sepPtr) { + *sepPtr++ = '\0'; + portNum = (PRUint16)atoi(sepPtr); + } else { + portNum = (PRUint16)LDAP_PORT; + } + + prstatus = PR_GetHostByName(localCopyName, buf, sizeof(buf), &hostent); + + if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { + /* + * The hostname may be a fully-qualified name. Try using just + * the leftmost component in our lookup. + */ + sepPtr = strchr(localCopyName, '.'); + if (sepPtr) { + *sepPtr++ = '\0'; + } + prstatus = PR_GetHostByName + (localCopyName, buf, sizeof(buf), &hostent); + + if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { + PKIX_ERROR + (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT); + } + } + + netAddr.inet.family = PR_AF_INET; + netAddr.inet.port = PR_htons(portNum); + + if (isServer) { + + netAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + } else { + + hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &netAddr); + if (hostenum == -1) { + PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED); + } + } + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_SOCKET_TYPE, + sizeof (PKIX_PL_Socket), + (PKIX_PL_Object **)&socket, + plContext), + PKIX_COULDNOTCREATESOCKETOBJECT); + + socket->isServer = isServer; + socket->timeout = timeout; + socket->clientSock = NULL; + socket->serverSock = NULL; + socket->netAddr = &netAddr; + + socket->callbackList.listenCallback = pkix_pl_Socket_Listen; + socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; + socket->callbackList.connectcontinueCallback = + pkix_pl_Socket_ConnectContinue; + socket->callbackList.sendCallback = pkix_pl_Socket_Send; + socket->callbackList.recvCallback = pkix_pl_Socket_Recv; + socket->callbackList.pollCallback = pkix_pl_Socket_Poll; + socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; + + if (isServer) { + PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), + PKIX_SOCKETCREATESERVERFAILED); + *pStatus = 0; + } else { + PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), + PKIX_SOCKETCREATECLIENTFAILED); + PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext), + PKIX_SOCKETCONNECTFAILED); + } + + *pSocket = socket; + +cleanup: + PL_strfree(localCopyName); + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(socket); + } + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_CreateByHostAndPort + * DESCRIPTION: + * + * This function creates a new Socket, setting it to be a server or a client + * according to the value of "isServer", setting its timeout value from + * "timeout", host from "hostname", and port number from "portNum", and stores + * the status at "pStatus" and the created Socket at "pSocket". + * + * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip + * address of PR_INADDR_ANY. + * + * PARAMETERS: + * "isServer" + * The Boolean value indicating if PKIX_TRUE, that a server socket (using + * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a + * client socket (using Connect) is to be created. + * "timeout" + * A PRTimeInterval value to be used for I/O waits for this socket. If + * zero, non-blocking I/O is to be used. + * "hostname" + * Address of a character string consisting of the server's domain name. + * "portNum" + * UInt16 value of the port number for the desired socket. + * "pStatus" + * Address at which the PRErrorCode resulting from the create is + * stored. Must be non-NULL. + * "pSocket" + * The address at which the Socket is to be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Socket Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_Socket_CreateByHostAndPort( + PKIX_Boolean isServer, + PRIntervalTime timeout, + char *hostname, + PRUint16 portnum, + PRErrorCode *pStatus, + PKIX_PL_Socket **pSocket, + void *plContext) +{ + PRNetAddr netAddr; + PKIX_PL_Socket *socket = NULL; + char *sepPtr = NULL; + PRHostEnt hostent; + PRIntn hostenum; + PRStatus prstatus = PR_FAILURE; + char buf[PR_NETDB_BUF_SIZE]; + + PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort"); + PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket); + + + prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent); + + if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { + /* + * The hostname may be a fully-qualified name. Try using just + * the leftmost component in our lookup. + */ + sepPtr = strchr(hostname, '.'); + if (sepPtr) { + *sepPtr++ = '\0'; + } + prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent); + + if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) { + PKIX_ERROR + (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT); + } + } + + netAddr.inet.family = PR_AF_INET; + netAddr.inet.port = PR_htons(portnum); + + if (isServer) { + + netAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + } else { + + hostenum = PR_EnumerateHostEnt(0, &hostent, portnum, &netAddr); + if (hostenum == -1) { + PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED); + } + } + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_SOCKET_TYPE, + sizeof (PKIX_PL_Socket), + (PKIX_PL_Object **)&socket, + plContext), + PKIX_COULDNOTCREATESOCKETOBJECT); + + socket->isServer = isServer; + socket->timeout = timeout; + socket->clientSock = NULL; + socket->serverSock = NULL; + socket->netAddr = &netAddr; + + socket->callbackList.listenCallback = pkix_pl_Socket_Listen; + socket->callbackList.acceptCallback = pkix_pl_Socket_Accept; + socket->callbackList.connectcontinueCallback = + pkix_pl_Socket_ConnectContinue; + socket->callbackList.sendCallback = pkix_pl_Socket_Send; + socket->callbackList.recvCallback = pkix_pl_Socket_Recv; + socket->callbackList.pollCallback = pkix_pl_Socket_Poll; + socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown; + + if (isServer) { + PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext), + PKIX_SOCKETCREATESERVERFAILED); + *pStatus = 0; + } else { + PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext), + PKIX_SOCKETCREATECLIENTFAILED); + PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext), + PKIX_SOCKETCONNECTFAILED); + } + + *pSocket = socket; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(socket); + } + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_GetCallbackList + */ +PKIX_Error * +pkix_pl_Socket_GetCallbackList( + PKIX_PL_Socket *socket, + PKIX_PL_Socket_Callback **pCallbackList, + void *plContext) +{ + PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetCallbackList"); + PKIX_NULLCHECK_TWO(socket, pCallbackList); + + *pCallbackList = &(socket->callbackList); + + PKIX_RETURN(SOCKET); +} + +/* + * FUNCTION: pkix_pl_Socket_GetPRFileDesc + */ +PKIX_Error * +pkix_pl_Socket_GetPRFileDesc( + PKIX_PL_Socket *socket, + PRFileDesc **pDesc, + void *plContext) +{ + PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetPRFileDesc"); + PKIX_NULLCHECK_TWO(socket, pDesc); + + *pDesc = socket->clientSock; + + PKIX_RETURN(SOCKET); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h new file mode 100644 index 0000000000..abf6628b32 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h @@ -0,0 +1,209 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_socket.h + * + * Socket Object Type Definition + * + */ + +#ifndef _PKIX_PL_SOCKET_H +#define _PKIX_PL_SOCKET_H + +#include <errno.h> +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SOCKET_BOUND, + SOCKET_LISTENING, + SOCKET_ACCEPTPENDING, + SOCKET_UNCONNECTED, + SOCKET_CONNECTPENDING, + SOCKET_CONNECTED, + SOCKET_SENDPENDING, + SOCKET_RCVPENDING, + SOCKET_SENDRCVPENDING, + SOCKET_SHUTDOWN +} SockStatus; + +/* This is the default port number, if none is supplied to CreateByName. */ +#define LDAP_PORT 389 + +/* + * These callbacks allow a user to substitute a counterfeit socket in places + * where a PKIX_PL_Socket is expected. A conforming usage will use the + * ListenCallback function instead of Listen, AcceptCallback instead of Accept, + * etc. The counterfeit socket may have special capabilites such as the + * ability to do proxy authentication, etc. + */ + +typedef PKIX_Error * +(*pkix_pl_Socket_ListenCallback)( + PKIX_PL_Socket *socket, + PKIX_UInt32 backlog, + void *plContext); + +typedef PKIX_Error * +(*pkix_pl_Socket_AcceptCallback)( + PKIX_PL_Socket *socket, + PKIX_PL_Socket **pRendezvousSock, + void *plContext); + +typedef PKIX_Error * +(*pkix_pl_Socket_ConnectContinueCallback)( + PKIX_PL_Socket *socket, + PRErrorCode *pStatus, + void *plContext); + +typedef PKIX_Error * +(*pkix_pl_Socket_SendCallback)( + PKIX_PL_Socket *sendSock, + void *buf, + PKIX_UInt32 bytesToWrite, + PKIX_Int32 *pBytesWritten, + void *plContext); + +typedef PKIX_Error * +(*pkix_pl_Socket_RecvCallback)( + PKIX_PL_Socket *rcvSock, + void *buf, + PKIX_UInt32 capacity, + PKIX_Int32 *pBytesRead, + void *plContext); + +typedef PKIX_Error * +(*pkix_pl_Socket_PollCallback)( + PKIX_PL_Socket *sock, + PKIX_Int32 *pBytesWritten, + PKIX_Int32 *pBytesRead, + void *plContext); + +typedef PKIX_Error * +(*pkix_pl_Socket_ShutdownCallback)( + PKIX_PL_Socket *socket, void *plContext); + +typedef struct PKIX_PL_Socket_CallbackStruct { + pkix_pl_Socket_ListenCallback listenCallback; + pkix_pl_Socket_AcceptCallback acceptCallback; + pkix_pl_Socket_ConnectContinueCallback connectcontinueCallback; + pkix_pl_Socket_SendCallback sendCallback; + pkix_pl_Socket_RecvCallback recvCallback; + pkix_pl_Socket_PollCallback pollCallback; + pkix_pl_Socket_ShutdownCallback shutdownCallback; +} PKIX_PL_Socket_Callback; + +struct PKIX_PL_SocketStruct { + PKIX_Boolean isServer; + PRIntervalTime timeout; /* zero for non-blocking I/O */ + SockStatus status; + PRFileDesc *clientSock; + PRFileDesc *serverSock; + void *readBuf; + void *writeBuf; + PKIX_UInt32 readBufSize; + PKIX_UInt32 writeBufSize; + PRNetAddr *netAddr; + PKIX_PL_Socket_Callback callbackList; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_Socket_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_Socket_Create( + PKIX_Boolean isServer, + PRIntervalTime timeout, /* zero for non-blocking I/O */ + PRNetAddr *netAddr, + PRErrorCode *status, + PKIX_PL_Socket **pSocket, + void *plContext); + +PKIX_Error * +pkix_pl_Socket_CreateByName( + PKIX_Boolean isServer, + PRIntervalTime timeout, + char *serverName, + PRErrorCode *pStatus, + PKIX_PL_Socket **pSocket, + void *plContext); + +PKIX_Error * +pkix_pl_Socket_CreateByHostAndPort( + PKIX_Boolean isServer, + PRIntervalTime timeout, + char *hostname, + PRUint16 portnum, + PRErrorCode *pStatus, + PKIX_PL_Socket **pSocket, + void *plContext); + +/* Do not use these functions directly; use their callback variants instead + * static PKIX_Error * + * pkix_pl_Socket_Listen( + * PKIX_PL_Socket *socket, + * PKIX_UInt32 backlog, + * void *plContext); + * + * static PKIX_Error * + * pkix_pl_Socket_Accept( + * PKIX_PL_Socket *socket, + * PKIX_PL_Socket **pRendezvousSock, + * void *plContext); + * + * static PKIX_Error * + * pkix_pl_Socket_ConnectContinue( + * PKIX_PL_Socket *socket, + * PRErrorCode *pStatus, + * void *plContext); + * + * static PKIX_Error * + * pkix_pl_Socket_Send( + * PKIX_PL_Socket *sendSock, + * void *buf, + * PKIX_UInt32 bytesToWrite, + * PKIX_Int32 *pBytesWritten, + * void *plContext); + * + * static PKIX_Error * + * pkix_pl_Socket_Recv( + * PKIX_PL_Socket *rcvSock, + * void *buf, + * PKIX_UInt32 capacity, + * PKIX_Int32 *pBytesRead, + * void *plContext); + * + * static PKIX_Error * + * pkix_pl_Socket_Poll( + * PKIX_PL_Socket *sock, + * PKIX_Int32 *pBytesWritten, + * PKIX_Int32 *pBytesRead, + * void *plContext); + * + * static PKIX_Error * + * pkix_pl_Socket_Shutdown( + * PKIX_PL_Socket *socket, void *plContext); + */ + +PKIX_Error * +pkix_pl_Socket_GetCallbackList( + PKIX_PL_Socket *socket, + PKIX_PL_Socket_Callback **pCallbackList, + void *plContext); + +PKIX_Error * +pkix_pl_Socket_GetPRFileDesc( + PKIX_PL_Socket *socket, + PRFileDesc **pDesc, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_SOCKET_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile new file mode 100644 index 0000000000..2b4b1574ab --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile @@ -0,0 +1,47 @@ +#! gmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp new file mode 100644 index 0000000000..616f94fd46 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp @@ -0,0 +1,41 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'lib_libpkix_pkix_pl_nss_pki_exports', + 'type': 'none', + 'copies': [ + { + 'files': [ + 'pkix_pl_basicconstraints.h', + 'pkix_pl_cert.h', + 'pkix_pl_certpolicyinfo.h', + 'pkix_pl_certpolicymap.h', + 'pkix_pl_certpolicyqualifier.h', + 'pkix_pl_crl.h', + 'pkix_pl_crldp.h', + 'pkix_pl_crlentry.h', + 'pkix_pl_date.h', + 'pkix_pl_generalname.h', + 'pkix_pl_infoaccess.h', + 'pkix_pl_nameconstraints.h', + 'pkix_pl_ocspcertid.h', + 'pkix_pl_ocsprequest.h', + 'pkix_pl_ocspresponse.h', + 'pkix_pl_publickey.h', + 'pkix_pl_x500name.h' + ], + 'destination': '<(nss_private_dist_dir)/<(module)' + } + ] + } + ], + 'variables': { + 'module': 'nss' + } +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn new file mode 100644 index 0000000000..aba1367e56 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn @@ -0,0 +1,50 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +CORE_DEPTH = ../../../.. + +PRIVATE_EXPORTS = \ + pkix_pl_basicconstraints.h \ + pkix_pl_cert.h \ + pkix_pl_certpolicyinfo.h \ + pkix_pl_certpolicymap.h \ + pkix_pl_certpolicyqualifier.h \ + pkix_pl_crl.h \ + pkix_pl_crldp.h \ + pkix_pl_crlentry.h \ + pkix_pl_date.h \ + pkix_pl_generalname.h \ + pkix_pl_infoaccess.h \ + pkix_pl_nameconstraints.h \ + pkix_pl_ocsprequest.h \ + pkix_pl_ocspresponse.h \ + pkix_pl_publickey.h \ + pkix_pl_x500name.h \ + pkix_pl_ocspcertid.h \ + $(NULL) + +MODULE = nss + +CSRCS = \ + pkix_pl_basicconstraints.c \ + pkix_pl_cert.c \ + pkix_pl_certpolicyinfo.c \ + pkix_pl_certpolicymap.c \ + pkix_pl_certpolicyqualifier.c \ + pkix_pl_crl.c \ + pkix_pl_crldp.c \ + pkix_pl_crlentry.c \ + pkix_pl_date.c \ + pkix_pl_generalname.c \ + pkix_pl_infoaccess.c \ + pkix_pl_nameconstraints.c \ + pkix_pl_ocsprequest.c \ + pkix_pl_ocspresponse.c \ + pkix_pl_publickey.c \ + pkix_pl_x500name.c \ + pkix_pl_ocspcertid.c \ + $(NULL) + +LIBRARY_NAME = pkixpki +SHARED_LIBRARY = $(NULL) diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp b/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp new file mode 100644 index 0000000000..af7730c0bf --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp @@ -0,0 +1,39 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'pkixpki', + 'type': 'static_library', + 'sources': [ + 'pkix_pl_basicconstraints.c', + 'pkix_pl_cert.c', + 'pkix_pl_certpolicyinfo.c', + 'pkix_pl_certpolicymap.c', + 'pkix_pl_certpolicyqualifier.c', + 'pkix_pl_crl.c', + 'pkix_pl_crldp.c', + 'pkix_pl_crlentry.c', + 'pkix_pl_date.c', + 'pkix_pl_generalname.c', + 'pkix_pl_infoaccess.c', + 'pkix_pl_nameconstraints.c', + 'pkix_pl_ocspcertid.c', + 'pkix_pl_ocsprequest.c', + 'pkix_pl_ocspresponse.c', + 'pkix_pl_publickey.c', + 'pkix_pl_x500name.c' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports' + ] + } + ], + 'variables': { + 'module': 'nss' + } +}
\ No newline at end of file diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c new file mode 100644 index 0000000000..81615da37a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c @@ -0,0 +1,407 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_basicconstraints.c + * + * BasicConstraints Object Functions + * + */ + +#include "pkix_pl_basicconstraints.h" + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Create + * DESCRIPTION: + * + * Creates a new CertBasicConstraints object whose CA Flag has the value + * given by the Boolean value of "isCA" and whose path length field has the + * value given by the "pathLen" argument and stores it at "pObject". + * + * PARAMETERS + * "isCA" + * Boolean value with the desired value of CA Flag. + * "pathLen" + * a PKIX_Int32 with the desired value of path length + * "pObject" + * Address of object pointer's destination. 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 CertBasicConstraints 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_CertBasicConstraints_Create( + PKIX_Boolean isCA, + PKIX_Int32 pathLen, + PKIX_PL_CertBasicConstraints **pObject, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *basic = NULL; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Create"); + PKIX_NULLCHECK_ONE(pObject); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTBASICCONSTRAINTS_TYPE, + sizeof (PKIX_PL_CertBasicConstraints), + (PKIX_PL_Object **)&basic, + plContext), + PKIX_COULDNOTCREATECERTBASICCONSTRAINTSOBJECT); + + basic->isCA = isCA; + + /* pathLen has meaning only for CAs, but it's not worth checking */ + basic->pathLen = pathLen; + + *pObject = basic; + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *certB = NULL; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTBASICCONSTRAINTS); + + certB = (PKIX_PL_CertBasicConstraints*)object; + + certB->isCA = PKIX_FALSE; + certB->pathLen = 0; + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *certBasicConstraintsString = NULL; + PKIX_PL_CertBasicConstraints *certB = NULL; + PKIX_Boolean isCA = PKIX_FALSE; + PKIX_Int32 pathLen = 0; + PKIX_PL_String *outString = NULL; + char *fmtString = NULL; + PKIX_Boolean pathlenArg = PKIX_FALSE; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_FIRSTARGUMENTNOTCERTBASICCONSTRAINTSOBJECT); + + certB = (PKIX_PL_CertBasicConstraints *)object; + + /* + * if CA == TRUE + * if pathLen == CERT_UNLIMITED_PATH_CONSTRAINT + * print "CA(-1)" + * else print "CA(nnn)" + * if CA == FALSE, print "~CA" + */ + + isCA = certB->isCA; + + if (isCA) { + pathLen = certB->pathLen; + + if (pathLen == CERT_UNLIMITED_PATH_CONSTRAINT) { + /* print "CA(-1)" */ + fmtString = "CA(-1)"; + pathlenArg = PKIX_FALSE; + } else { + /* print "CA(pathLen)" */ + fmtString = "CA(%d)"; + pathlenArg = PKIX_TRUE; + } + } else { + /* print "~CA" */ + fmtString = "~CA"; + pathlenArg = PKIX_FALSE; + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + fmtString, + 0, + &certBasicConstraintsString, + plContext), + PKIX_STRINGCREATEFAILED); + + if (pathlenArg) { + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, + plContext, + certBasicConstraintsString, + pathLen), + PKIX_SPRINTFFAILED); + } else { + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, + plContext, + certBasicConstraintsString), + PKIX_SPRINTFFAILED); + } + + *pString = outString; + +cleanup: + + PKIX_DECREF(certBasicConstraintsString); + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *certB = NULL; + PKIX_Boolean isCA = PKIX_FALSE; + PKIX_Int32 pathLen = 0; + PKIX_Int32 hashInput = 0; + PKIX_UInt32 cbcHash = 0; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTBASICCONSTRAINTS); + + certB = (PKIX_PL_CertBasicConstraints *)object; + + /* + * if CA == TRUE + * hash(pathLen + 1 - PKIX_UNLIMITED_PATH_CONSTRAINT) + * if CA == FALSE, hash(0) + */ + + isCA = certB->isCA; + + if (isCA) { + pathLen = certB->pathLen; + + hashInput = pathLen + 1 - PKIX_UNLIMITED_PATH_CONSTRAINT; + } + + PKIX_CHECK(pkix_hash + ((const unsigned char *)&hashInput, + sizeof (hashInput), + &cbcHash, + plContext), + PKIX_HASHFAILED); + + *pHashcode = cbcHash; + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *firstCBC = NULL; + PKIX_PL_CertBasicConstraints *secondCBC = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean firstIsCA = PKIX_FALSE; + PKIX_Boolean secondIsCA = PKIX_FALSE; + PKIX_Int32 firstPathLen = 0; + PKIX_Int32 secondPathLen = 0; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertBasicConstraints */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTBASICCONSTRAINTS); + + /* + * Since we know firstObject is a CertBasicConstraints, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertBasicConstraints, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTBASICCONSTRAINTS_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCBC = (PKIX_PL_CertBasicConstraints *)firstObject; + secondCBC = (PKIX_PL_CertBasicConstraints *)secondObject; + + /* + * Compare the value of the CAFlag components + */ + + firstIsCA = firstCBC->isCA; + + /* + * Failure here would be an error, not merely a miscompare, + * since we know second is a CertBasicConstraints. + */ + secondIsCA = secondCBC->isCA; + + /* + * If isCA flags differ, the objects are not equal. + */ + if (secondIsCA != firstIsCA) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + /* + * If isCA was FALSE, the objects are equal, because + * pathLen is meaningless in that case. + */ + if (!firstIsCA) { + *pResult = PKIX_TRUE; + goto cleanup; + } + + firstPathLen = firstCBC->pathLen; + secondPathLen = secondCBC->pathLen; + + *pResult = (secondPathLen == firstPathLen); + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTBASICCONSTRAINTS_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_CertBasicConstraints_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_RegisterSelf"); + + entry.description = "CertBasicConstraints"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertBasicConstraints); + entry.destructor = pkix_pl_CertBasicConstraints_Destroy; + entry.equalsFunction = pkix_pl_CertBasicConstraints_Equals; + entry.hashcodeFunction = pkix_pl_CertBasicConstraints_Hashcode; + entry.toStringFunction = pkix_pl_CertBasicConstraints_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTBASICCONSTRAINTS_TYPE] = entry; + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_BasicConstraints_GetCAFlag + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_BasicConstraints_GetCAFlag( + PKIX_PL_CertBasicConstraints *basicConstraints, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_ENTER(CERTBASICCONSTRAINTS, + "PKIX_PL_BasicConstraintsGetCAFlag"); + PKIX_NULLCHECK_TWO(basicConstraints, pResult); + + *pResult = basicConstraints->isCA; + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: PKIX_PL_BasicConstraints_GetPathLenConstraint + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_BasicConstraints_GetPathLenConstraint( + PKIX_PL_CertBasicConstraints *basicConstraints, + PKIX_Int32 *pPathLenConstraint, + void *plContext) +{ + PKIX_ENTER(CERTBASICCONSTRAINTS, + "PKIX_PL_BasicConstraintsGetPathLenConstraint"); + PKIX_NULLCHECK_TWO(basicConstraints, pPathLenConstraint); + + *pPathLenConstraint = basicConstraints->pathLen; + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h new file mode 100644 index 0000000000..857529c95c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_basicconstraints.h + * + * BasicConstraints Object Definitions + * + */ + +#ifndef _PKIX_PL_BASICCONSTRAINTS_H +#define _PKIX_PL_BASICCONSTRAINTS_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This structure reflects the contents of the basic constraints + * extension as described in Section 4.2.1.10 of RFC 3280. + * The cA flag indicates whether the public key in this certificate + * belongs to a certification authority. The pathLen constraint + * gives the maximum number of non-self-issued intermediate certificates + * that may follow this certificate in a valid certification path. + */ +struct PKIX_PL_CertBasicConstraintsStruct { + PKIX_Boolean isCA; + PKIX_Int32 pathLen; +}; + +PKIX_Error * +pkix_pl_CertBasicConstraints_Create( + PKIX_Boolean isCA, + PKIX_Int32 pathLen, + PKIX_PL_CertBasicConstraints **object, + void *plContext); + +PKIX_Error * +pkix_pl_CertBasicConstraints_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_BASICCONSTRAINTS_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c new file mode 100644 index 0000000000..9dddd2e40f --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c @@ -0,0 +1,3734 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_cert.c + * + * Certificate Object Functions + * + */ + +#include "pkix_pl_cert.h" + +extern PKIX_PL_HashTable *cachedCertSigTable; + +/* --Private-Cert-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_Cert_IsExtensionCritical + * DESCRIPTION: + * + * Checks the Cert specified by "cert" to determine whether the extension + * whose tag is the UInt32 value given by "tag" is marked as a critical + * extension, and stores the result in "pCritical". + * + * Tags are the index into the table "oids" of SECOidData defined in the + * file secoid.c. Constants, such as SEC_OID_X509_CERTIFICATE_POLICIES, are + * are defined in secoidt.h for most of the table entries. + * + * If the specified tag is invalid (not in the list of tags) or if the + * extension is not found in the certificate, PKIX_FALSE is stored. + * + * PARAMETERS + * "cert" + * Address of Cert whose extensions are to be examined. Must be non-NULL. + * "tag" + * The UInt32 value of the tag for the extension whose criticality is + * to be determined + * "pCritical" + * Address where the Boolean value 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. + */ +static PKIX_Error * +pkix_pl_Cert_IsExtensionCritical( + PKIX_PL_Cert *cert, + PKIX_UInt32 tag, + PKIX_Boolean *pCritical, + void *plContext) +{ + PKIX_Boolean criticality = PKIX_FALSE; + CERTCertExtension **extensions = NULL; + SECStatus rv; + + PKIX_ENTER(CERT, "pkix_pl_Cert_IsExtensionCritical"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCritical); + + extensions = cert->nssCert->extensions; + PKIX_NULLCHECK_ONE(extensions); + + PKIX_CERT_DEBUG("\t\tCalling CERT_GetExtenCriticality).\n"); + rv = CERT_GetExtenCriticality(extensions, tag, &criticality); + if (SECSuccess == rv) { + *pCritical = criticality; + } else { + *pCritical = PKIX_FALSE; + } + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_DecodePolicyInfo + * DESCRIPTION: + * + * Decodes the contents of the CertificatePolicy extension in the + * CERTCertificate pointed to by "nssCert", to create a List of + * CertPolicyInfos, which is stored at the address "pCertPolicyInfos". + * A CERTCertificate contains the DER representation of the Cert. + * If this certificate does not have a CertificatePolicy extension, + * NULL will be stored. If a List is returned, it will be immutable. + * + * PARAMETERS + * "nssCert" + * Address of the Cert data whose extension is to be examined. Must be + * non-NULL. + * "pCertPolicyInfos" + * Address where the List of CertPolicyInfos 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 Cert 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_Cert_DecodePolicyInfo( + CERTCertificate *nssCert, + PKIX_List **pCertPolicyInfos, + void *plContext) +{ + + SECStatus rv; + SECItem encodedCertPolicyInfo; + + /* Allocated in the arena; freed in CERT_Destroy... */ + CERTCertificatePolicies *certPol = NULL; + CERTPolicyInfo **policyInfos = NULL; + + /* Holder for the return value */ + PKIX_List *infos = NULL; + + PKIX_PL_OID *pkixOID = NULL; + PKIX_List *qualifiers = NULL; + PKIX_PL_CertPolicyInfo *certPolicyInfo = NULL; + PKIX_PL_CertPolicyQualifier *certPolicyQualifier = NULL; + PKIX_PL_ByteArray *qualifierArray = NULL; + + PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyInfo"); + PKIX_NULLCHECK_TWO(nssCert, pCertPolicyInfos); + + /* get PolicyInfo as a SECItem */ + PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n"); + rv = CERT_FindCertExtension + (nssCert, + SEC_OID_X509_CERTIFICATE_POLICIES, + &encodedCertPolicyInfo); + if (SECSuccess != rv) { + *pCertPolicyInfos = NULL; + goto cleanup; + } + + /* translate PolicyInfo to CERTCertificatePolicies */ + PKIX_CERT_DEBUG("\t\tCERT_DecodeCertificatePoliciesExtension).\n"); + certPol = CERT_DecodeCertificatePoliciesExtension + (&encodedCertPolicyInfo); + + PORT_Free(encodedCertPolicyInfo.data); + + if (NULL == certPol) { + PKIX_ERROR(PKIX_CERTDECODECERTIFICATEPOLICIESEXTENSIONFAILED); + } + + /* + * Check whether there are any policyInfos, so we can + * avoid creating an unnecessary List + */ + policyInfos = certPol->policyInfos; + if (!policyInfos) { + *pCertPolicyInfos = NULL; + goto cleanup; + } + + /* create a List of CertPolicyInfo Objects */ + PKIX_CHECK(PKIX_List_Create(&infos, plContext), + PKIX_LISTCREATEFAILED); + + /* + * Traverse the CERTCertificatePolicies structure, + * building each PKIX_PL_CertPolicyInfo object in turn + */ + while (*policyInfos != NULL) { + CERTPolicyInfo *policyInfo = *policyInfos; + CERTPolicyQualifier **policyQualifiers = + policyInfo->policyQualifiers; + if (policyQualifiers) { + /* create a PKIX_List of PKIX_PL_CertPolicyQualifiers */ + PKIX_CHECK(PKIX_List_Create(&qualifiers, plContext), + PKIX_LISTCREATEFAILED); + + while (*policyQualifiers != NULL) { + CERTPolicyQualifier *policyQualifier = + *policyQualifiers; + + /* create the qualifier's OID object */ + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (&policyQualifier->qualifierID, + &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + + /* create qualifier's ByteArray object */ + + PKIX_CHECK(PKIX_PL_ByteArray_Create + (policyQualifier->qualifierValue.data, + policyQualifier->qualifierValue.len, + &qualifierArray, + plContext), + PKIX_BYTEARRAYCREATEFAILED); + + /* create a CertPolicyQualifier object */ + + PKIX_CHECK(pkix_pl_CertPolicyQualifier_Create + (pkixOID, + qualifierArray, + &certPolicyQualifier, + plContext), + PKIX_CERTPOLICYQUALIFIERCREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (qualifiers, + (PKIX_PL_Object *)certPolicyQualifier, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(pkixOID); + PKIX_DECREF(qualifierArray); + PKIX_DECREF(certPolicyQualifier); + + policyQualifiers++; + } + + PKIX_CHECK(PKIX_List_SetImmutable + (qualifiers, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + } + + + /* + * Create an OID object pkixOID from policyInfo->policyID. + * (The CERTPolicyInfo structure has an oid field, but it + * is of type SECOidTag. This function wants a SECItem.) + */ + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (&policyInfo->policyID, &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + + /* Create a CertPolicyInfo object */ + PKIX_CHECK(pkix_pl_CertPolicyInfo_Create + (pkixOID, qualifiers, &certPolicyInfo, plContext), + PKIX_CERTPOLICYINFOCREATEFAILED); + + /* Append the new CertPolicyInfo object to the list */ + PKIX_CHECK(PKIX_List_AppendItem + (infos, (PKIX_PL_Object *)certPolicyInfo, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(pkixOID); + PKIX_DECREF(qualifiers); + PKIX_DECREF(certPolicyInfo); + + policyInfos++; + } + + /* + * If there were no policies, we went straight to + * cleanup, so we don't have to NULLCHECK infos. + */ + PKIX_CHECK(PKIX_List_SetImmutable(infos, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + *pCertPolicyInfos = infos; + infos = NULL; + +cleanup: + if (certPol) { + PKIX_CERT_DEBUG + ("\t\tCalling CERT_DestroyCertificatePoliciesExtension).\n"); + CERT_DestroyCertificatePoliciesExtension(certPol); + } + + PKIX_DECREF(infos); + PKIX_DECREF(pkixOID); + PKIX_DECREF(qualifiers); + PKIX_DECREF(certPolicyInfo); + PKIX_DECREF(certPolicyQualifier); + PKIX_DECREF(qualifierArray); + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_DecodePolicyMapping + * DESCRIPTION: + * + * Decodes the contents of the PolicyMapping extension of the CERTCertificate + * pointed to by "nssCert", storing the resulting List of CertPolicyMaps at + * the address pointed to by "pCertPolicyMaps". If this certificate does not + * have a PolicyMapping extension, NULL will be stored. If a List is returned, + * it will be immutable. + * + * PARAMETERS + * "nssCert" + * Address of the Cert data whose extension is to be examined. Must be + * non-NULL. + * "pCertPolicyMaps" + * Address where the List of CertPolicyMaps 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 Cert 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_Cert_DecodePolicyMapping( + CERTCertificate *nssCert, + PKIX_List **pCertPolicyMaps, + void *plContext) +{ + SECStatus rv; + SECItem encodedCertPolicyMaps; + + /* Allocated in the arena; freed in CERT_Destroy... */ + CERTCertificatePolicyMappings *certPolMaps = NULL; + CERTPolicyMap **policyMaps = NULL; + + /* Holder for the return value */ + PKIX_List *maps = NULL; + + PKIX_PL_OID *issuerDomainOID = NULL; + PKIX_PL_OID *subjectDomainOID = NULL; + PKIX_PL_CertPolicyMap *certPolicyMap = NULL; + + PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyMapping"); + PKIX_NULLCHECK_TWO(nssCert, pCertPolicyMaps); + + /* get PolicyMappings as a SECItem */ + PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n"); + rv = CERT_FindCertExtension + (nssCert, SEC_OID_X509_POLICY_MAPPINGS, &encodedCertPolicyMaps); + if (SECSuccess != rv) { + *pCertPolicyMaps = NULL; + goto cleanup; + } + + /* translate PolicyMaps to CERTCertificatePolicyMappings */ + certPolMaps = CERT_DecodePolicyMappingsExtension + (&encodedCertPolicyMaps); + + PORT_Free(encodedCertPolicyMaps.data); + + if (!certPolMaps) { + PKIX_ERROR(PKIX_CERTDECODEPOLICYMAPPINGSEXTENSIONFAILED); + } + + PKIX_NULLCHECK_ONE(certPolMaps->policyMaps); + + policyMaps = certPolMaps->policyMaps; + + /* create a List of CertPolicyMap Objects */ + PKIX_CHECK(PKIX_List_Create(&maps, plContext), + PKIX_LISTCREATEFAILED); + + /* + * Traverse the CERTCertificatePolicyMappings structure, + * building each CertPolicyMap object in turn + */ + do { + CERTPolicyMap *policyMap = *policyMaps; + + /* create the OID for the issuer Domain Policy */ + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (&policyMap->issuerDomainPolicy, + &issuerDomainOID, plContext), + PKIX_OIDCREATEFAILED); + + /* create the OID for the subject Domain Policy */ + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (&policyMap->subjectDomainPolicy, + &subjectDomainOID, plContext), + PKIX_OIDCREATEFAILED); + + /* create the CertPolicyMap */ + + PKIX_CHECK(pkix_pl_CertPolicyMap_Create + (issuerDomainOID, + subjectDomainOID, + &certPolicyMap, + plContext), + PKIX_CERTPOLICYMAPCREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (maps, (PKIX_PL_Object *)certPolicyMap, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(issuerDomainOID); + PKIX_DECREF(subjectDomainOID); + PKIX_DECREF(certPolicyMap); + + policyMaps++; + } while (*policyMaps != NULL); + + PKIX_CHECK(PKIX_List_SetImmutable(maps, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + *pCertPolicyMaps = maps; + maps = NULL; + +cleanup: + if (certPolMaps) { + PKIX_CERT_DEBUG + ("\t\tCalling CERT_DestroyPolicyMappingsExtension).\n"); + CERT_DestroyPolicyMappingsExtension(certPolMaps); + } + + PKIX_DECREF(maps); + PKIX_DECREF(issuerDomainOID); + PKIX_DECREF(subjectDomainOID); + PKIX_DECREF(certPolicyMap); + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_DecodePolicyConstraints + * DESCRIPTION: + * + * Decodes the contents of the PolicyConstraints extension in the + * CERTCertificate pointed to by "nssCert", to obtain SkipCerts values + * which are stored at the addresses "pExplicitPolicySkipCerts" and + * "pInhibitMappingSkipCerts", respectively. If this certificate does + * not have an PolicyConstraints extension, or if either of the optional + * components is not supplied, this function stores a value of -1 for any + * missing component. + * + * PARAMETERS + * "nssCert" + * Address of the Cert data whose extension is to be examined. Must be + * non-NULL. + * "pExplicitPolicySkipCerts" + * Address where the SkipCert value for the requireExplicitPolicy + * component will be stored. Must be non-NULL. + * "pInhibitMappingSkipCerts" + * Address where the SkipCert value for the inhibitPolicyMapping + * component 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 Cert 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_Cert_DecodePolicyConstraints( + CERTCertificate *nssCert, + PKIX_Int32 *pExplicitPolicySkipCerts, + PKIX_Int32 *pInhibitMappingSkipCerts, + void *plContext) +{ + CERTCertificatePolicyConstraints policyConstraints; + SECStatus rv; + SECItem encodedCertPolicyConstraints; + PKIX_Int32 explicitPolicySkipCerts = -1; + PKIX_Int32 inhibitMappingSkipCerts = -1; + + PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyConstraints"); + PKIX_NULLCHECK_THREE + (nssCert, pExplicitPolicySkipCerts, pInhibitMappingSkipCerts); + + /* get the two skipCert values as SECItems */ + PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n"); + rv = CERT_FindCertExtension + (nssCert, + SEC_OID_X509_POLICY_CONSTRAINTS, + &encodedCertPolicyConstraints); + + if (rv == SECSuccess) { + + policyConstraints.explicitPolicySkipCerts.data = + (unsigned char *)&explicitPolicySkipCerts; + policyConstraints.inhibitMappingSkipCerts.data = + (unsigned char *)&inhibitMappingSkipCerts; + + /* translate DER to CERTCertificatePolicyConstraints */ + rv = CERT_DecodePolicyConstraintsExtension + (&policyConstraints, &encodedCertPolicyConstraints); + + PORT_Free(encodedCertPolicyConstraints.data); + + if (rv != SECSuccess) { + PKIX_ERROR + (PKIX_CERTDECODEPOLICYCONSTRAINTSEXTENSIONFAILED); + } + } + + *pExplicitPolicySkipCerts = explicitPolicySkipCerts; + *pInhibitMappingSkipCerts = inhibitMappingSkipCerts; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_DecodeInhibitAnyPolicy + * DESCRIPTION: + * + * Decodes the contents of the InhibitAnyPolicy extension in the + * CERTCertificate pointed to by "nssCert", to obtain a SkipCerts value, + * which is stored at the address "pSkipCerts". If this certificate does + * not have an InhibitAnyPolicy extension, -1 will be stored. + * + * PARAMETERS + * "nssCert" + * Address of the Cert data whose InhibitAnyPolicy extension is to be + * processed. Must be non-NULL. + * "pSkipCerts" + * Address where the SkipCert value from the InhibitAnyPolicy extension + * 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 Cert 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_Cert_DecodeInhibitAnyPolicy( + CERTCertificate *nssCert, + PKIX_Int32 *pSkipCerts, + void *plContext) +{ + CERTCertificateInhibitAny inhibitAny; + SECStatus rv; + SECItem encodedCertInhibitAny; + PKIX_Int32 skipCerts = -1; + + PKIX_ENTER(CERT, "pkix_pl_Cert_DecodeInhibitAnyPolicy"); + PKIX_NULLCHECK_TWO(nssCert, pSkipCerts); + + /* get InhibitAny as a SECItem */ + PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n"); + rv = CERT_FindCertExtension + (nssCert, SEC_OID_X509_INHIBIT_ANY_POLICY, &encodedCertInhibitAny); + + if (rv == SECSuccess) { + inhibitAny.inhibitAnySkipCerts.data = + (unsigned char *)&skipCerts; + + /* translate DER to CERTCertificateInhibitAny */ + rv = CERT_DecodeInhibitAnyExtension + (&inhibitAny, &encodedCertInhibitAny); + + PORT_Free(encodedCertInhibitAny.data); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_CERTDECODEINHIBITANYEXTENSIONFAILED); + } + } + + *pSkipCerts = skipCerts; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_GetNssSubjectAltNames + * DESCRIPTION: + * + * Retrieves the Subject Alternative Names of the certificate specified by + * "cert" and stores it at "pNssSubjAltNames". If the Subject Alternative + * Name extension is not present, NULL is returned at "pNssSubjAltNames". + * If the Subject Alternative Names has not been previously decoded, it is + * decoded here with lock on the "cert" unless the flag "hasLock" indicates + * the lock had been obtained at a higher call level. + * + * PARAMETERS + * "cert" + * Address of the certificate whose Subject Alternative Names extensions + * is retrieved. Must be non-NULL. + * "hasLock" + * Boolean indicates caller has acquired a lock. + * Must be non-NULL. + * "pNssSubjAltNames" + * Address where the returned Subject Alternative Names 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 Cert 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_Cert_GetNssSubjectAltNames( + PKIX_PL_Cert *cert, + PKIX_Boolean hasLock, + CERTGeneralName **pNssSubjAltNames, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + CERTGeneralName *nssOriginalAltName = NULL; + PLArenaPool *arena = NULL; + SECItem altNameExtension = {siBuffer, NULL, 0}; + SECStatus rv = SECFailure; + + PKIX_ENTER(CERT, "pkix_pl_Cert_GetNssSubjectAltNames"); + PKIX_NULLCHECK_THREE(cert, pNssSubjAltNames, cert->nssCert); + + nssCert = cert->nssCert; + + if ((cert->nssSubjAltNames == NULL) && (!cert->subjAltNamesAbsent)){ + + if (!hasLock) { + PKIX_OBJECT_LOCK(cert); + } + + if ((cert->nssSubjAltNames == NULL) && + (!cert->subjAltNamesAbsent)){ + + PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension, + (nssCert, + SEC_OID_X509_SUBJECT_ALT_NAME, + &altNameExtension)); + + if (rv != SECSuccess) { + *pNssSubjAltNames = NULL; + cert->subjAltNamesAbsent = PKIX_TRUE; + goto cleanup; + } + + if (cert->arenaNameConstraints == NULL) { + PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena, + (DER_DEFAULT_CHUNKSIZE)); + + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + cert->arenaNameConstraints = arena; + } + + PKIX_PL_NSSCALLRV + (CERT, + nssOriginalAltName, + (CERTGeneralName *) CERT_DecodeAltNameExtension, + (cert->arenaNameConstraints, &altNameExtension)); + + PKIX_PL_NSSCALL(CERT, PORT_Free, (altNameExtension.data)); + + if (nssOriginalAltName == NULL) { + PKIX_ERROR(PKIX_CERTDECODEALTNAMEEXTENSIONFAILED); + } + cert->nssSubjAltNames = nssOriginalAltName; + + } + + if (!hasLock) { + PKIX_OBJECT_UNLOCK(cert); + } + } + + *pNssSubjAltNames = cert->nssSubjAltNames; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_CheckExtendKeyUsage + * DESCRIPTION: + * + * For each of the ON bit in "requiredExtendedKeyUsages" that represents its + * SECCertUsageEnum type, this function checks "cert"'s certType (extended + * key usage) and key usage with what is required for SECCertUsageEnum type. + * + * PARAMETERS + * "cert" + * Address of the certificate whose Extended Key Usage extensions + * is retrieved. Must be non-NULL. + * "requiredExtendedKeyUsages" + * An unsigned integer, its bit location is ON based on the required key + * usage value representing in SECCertUsageEnum. + * "pPass" + * Address where the return value, indicating key usage check passed, 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 Cert 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_Cert_CheckExtendedKeyUsage( + PKIX_PL_Cert *cert, + PKIX_UInt32 requiredExtendedKeyUsages, + PKIX_Boolean *pPass, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *basicConstraints = NULL; + PKIX_UInt32 certType = 0; + PKIX_UInt32 requiredKeyUsage = 0; + PKIX_UInt32 requiredCertType = 0; + PKIX_UInt32 requiredExtendedKeyUsage = 0; + PKIX_UInt32 i; + PKIX_Boolean isCA = PKIX_FALSE; + SECStatus rv = SECFailure; + + PKIX_ENTER(CERT, "pkix_pl_Cert_CheckExtendKeyUsage"); + PKIX_NULLCHECK_THREE(cert, pPass, cert->nssCert); + + *pPass = PKIX_FALSE; + + PKIX_CERT_DEBUG("\t\tCalling cert_GetCertType).\n"); + cert_GetCertType(cert->nssCert); + certType = cert->nssCert->nsCertType; + + PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints + (cert, + &basicConstraints, + plContext), + PKIX_CERTGETBASICCONSTRAINTFAILED); + + if (basicConstraints != NULL) { + PKIX_CHECK(PKIX_PL_BasicConstraints_GetCAFlag + (basicConstraints, &isCA, plContext), + PKIX_BASICCONSTRAINTSGETCAFLAGFAILED); + } + + i = 0; + while (requiredExtendedKeyUsages != 0) { + + /* Find the bit location of the right-most non-zero bit */ + while (requiredExtendedKeyUsages != 0) { + if (((1 << i) & requiredExtendedKeyUsages) != 0) { + requiredExtendedKeyUsage = 1 << i; + break; + } + i++; + } + requiredExtendedKeyUsages ^= requiredExtendedKeyUsage; + + requiredExtendedKeyUsage = i; + + PKIX_PL_NSSCALLRV(CERT, rv, CERT_KeyUsageAndTypeForCertUsage, + (requiredExtendedKeyUsage, + isCA, + &requiredKeyUsage, + &requiredCertType)); + + if (!(certType & requiredCertType)) { + goto cleanup; + } + + PKIX_PL_NSSCALLRV(CERT, rv, CERT_CheckKeyUsage, + (cert->nssCert, requiredKeyUsage)); + if (rv != SECSuccess) { + goto cleanup; + } + i++; + + } + + *pPass = PKIX_TRUE; + +cleanup: + PKIX_DECREF(basicConstraints); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the Cert pointed + * to by "cert" and stores it at "pString", where the value of + * "partialString" determines whether a full or partial representation of + * the Cert is stored. + * + * PARAMETERS + * "cert" + * Address of Cert whose string representation is desired. + * Must be non-NULL. + * "partialString" + * Boolean indicating whether a partial Cert representation is desired. + * "pString" + * 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 Cert 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_Cert_ToString_Helper( + PKIX_PL_Cert *cert, + PKIX_Boolean partialString, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *certString = NULL; + char *asciiFormat = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_UInt32 certVersion; + PKIX_PL_BigInt *certSN = NULL; + PKIX_PL_String *certSNString = NULL; + PKIX_PL_X500Name *certIssuer = NULL; + PKIX_PL_String *certIssuerString = NULL; + PKIX_PL_X500Name *certSubject = NULL; + PKIX_PL_String *certSubjectString = NULL; + PKIX_PL_String *notBeforeString = NULL; + PKIX_PL_String *notAfterString = NULL; + PKIX_List *subjAltNames = NULL; + PKIX_PL_String *subjAltNamesString = NULL; + PKIX_PL_ByteArray *authKeyId = NULL; + PKIX_PL_String *authKeyIdString = NULL; + PKIX_PL_ByteArray *subjKeyId = NULL; + PKIX_PL_String *subjKeyIdString = NULL; + PKIX_PL_PublicKey *nssPubKey = NULL; + PKIX_PL_String *nssPubKeyString = NULL; + PKIX_List *critExtOIDs = NULL; + PKIX_PL_String *critExtOIDsString = NULL; + PKIX_List *extKeyUsages = NULL; + PKIX_PL_String *extKeyUsagesString = NULL; + PKIX_PL_CertBasicConstraints *basicConstraint = NULL; + PKIX_PL_String *certBasicConstraintsString = NULL; + PKIX_List *policyInfo = NULL; + PKIX_PL_String *certPolicyInfoString = NULL; + PKIX_List *certPolicyMappings = NULL; + PKIX_PL_String *certPolicyMappingsString = NULL; + PKIX_Int32 certExplicitPolicy = 0; + PKIX_Int32 certInhibitMapping = 0; + PKIX_Int32 certInhibitAnyPolicy = 0; + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + PKIX_PL_String *nameConstraintsString = NULL; + PKIX_List *authorityInfoAccess = NULL; + PKIX_PL_String *authorityInfoAccessString = NULL; + PKIX_List *subjectInfoAccess = NULL; + PKIX_PL_String *subjectInfoAccessString = NULL; + + PKIX_ENTER(CERT, "pkix_pl_Cert_ToString_Helper"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pString); + + /* + * XXX Add to this format as certificate components are developed. + */ + + if (partialString){ + asciiFormat = + "\t[Issuer: %s\n" + "\t Subject: %s]"; + } else { + asciiFormat = + "[\n" + "\tVersion: v%d\n" + "\tSerialNumber: %s\n" + "\tIssuer: %s\n" + "\tSubject: %s\n" + "\tValidity: [From: %s\n" + "\t To: %s]\n" + "\tSubjectAltNames: %s\n" + "\tAuthorityKeyId: %s\n" + "\tSubjectKeyId: %s\n" + "\tSubjPubKeyAlgId: %s\n" + "\tCritExtOIDs: %s\n" + "\tExtKeyUsages: %s\n" + "\tBasicConstraint: %s\n" + "\tCertPolicyInfo: %s\n" + "\tPolicyMappings: %s\n" + "\tExplicitPolicy: %d\n" + "\tInhibitMapping: %d\n" + "\tInhibitAnyPolicy:%d\n" + "\tNameConstraints: %s\n" + "\tAuthorityInfoAccess: %s\n" + "\tSubjectInfoAccess: %s\n" + "\tCacheFlag: %d\n" + "]\n"; + } + + + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext), + PKIX_STRINGCREATEFAILED); + + /* Issuer */ + PKIX_CHECK(PKIX_PL_Cert_GetIssuer + (cert, &certIssuer, plContext), + PKIX_CERTGETISSUERFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)certIssuer, &certIssuerString, plContext), + PKIX_X500NAMETOSTRINGFAILED); + + /* Subject */ + PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &certSubject, plContext), + PKIX_CERTGETSUBJECTFAILED); + + PKIX_TOSTRING(certSubject, &certSubjectString, plContext, + PKIX_X500NAMETOSTRINGFAILED); + + if (partialString){ + PKIX_CHECK(PKIX_PL_Sprintf + (&certString, + plContext, + formatString, + certIssuerString, + certSubjectString), + PKIX_SPRINTFFAILED); + + *pString = certString; + goto cleanup; + } + + /* Version */ + PKIX_CHECK(PKIX_PL_Cert_GetVersion(cert, &certVersion, plContext), + PKIX_CERTGETVERSIONFAILED); + + /* SerialNumber */ + PKIX_CHECK(PKIX_PL_Cert_GetSerialNumber(cert, &certSN, plContext), + PKIX_CERTGETSERIALNUMBERFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)certSN, &certSNString, plContext), + PKIX_BIGINTTOSTRINGFAILED); + + /* Validity: NotBefore */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(cert->nssCert->validity.notBefore), + ¬BeforeString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* Validity: NotAfter */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(cert->nssCert->validity.notAfter), + ¬AfterString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* SubjectAltNames */ + PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames + (cert, &subjAltNames, plContext), + PKIX_CERTGETSUBJECTALTNAMESFAILED); + + PKIX_TOSTRING(subjAltNames, &subjAltNamesString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* AuthorityKeyIdentifier */ + PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier + (cert, &authKeyId, plContext), + PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED); + + PKIX_TOSTRING(authKeyId, &authKeyIdString, plContext, + PKIX_BYTEARRAYTOSTRINGFAILED); + + /* SubjectKeyIdentifier */ + PKIX_CHECK(PKIX_PL_Cert_GetSubjectKeyIdentifier + (cert, &subjKeyId, plContext), + PKIX_CERTGETSUBJECTKEYIDENTIFIERFAILED); + + PKIX_TOSTRING(subjKeyId, &subjKeyIdString, plContext, + PKIX_BYTEARRAYTOSTRINGFAILED); + + /* SubjectPublicKey */ + PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey + (cert, &nssPubKey, plContext), + PKIX_CERTGETSUBJECTPUBLICKEYFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)nssPubKey, &nssPubKeyString, plContext), + PKIX_PUBLICKEYTOSTRINGFAILED); + + /* CriticalExtensionOIDs */ + PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs + (cert, &critExtOIDs, plContext), + PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED); + + PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* ExtendedKeyUsages */ + PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage + (cert, &extKeyUsages, plContext), + PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); + + PKIX_TOSTRING(extKeyUsages, &extKeyUsagesString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* CertBasicConstraints */ + PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints + (cert, &basicConstraint, plContext), + PKIX_CERTGETBASICCONSTRAINTSFAILED); + + PKIX_TOSTRING(basicConstraint, &certBasicConstraintsString, plContext, + PKIX_CERTBASICCONSTRAINTSTOSTRINGFAILED); + + /* CertPolicyInfo */ + PKIX_CHECK(PKIX_PL_Cert_GetPolicyInformation + (cert, &policyInfo, plContext), + PKIX_CERTGETPOLICYINFORMATIONFAILED); + + PKIX_TOSTRING(policyInfo, &certPolicyInfoString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* Advanced Policies */ + PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappings + (cert, &certPolicyMappings, plContext), + PKIX_CERTGETPOLICYMAPPINGSFAILED); + + PKIX_TOSTRING(certPolicyMappings, &certPolicyMappingsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy + (cert, &certExplicitPolicy, plContext), + PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED); + + PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappingInhibited + (cert, &certInhibitMapping, plContext), + PKIX_CERTGETPOLICYMAPPINGINHIBITEDFAILED); + + PKIX_CHECK(PKIX_PL_Cert_GetInhibitAnyPolicy + (cert, &certInhibitAnyPolicy, plContext), + PKIX_CERTGETINHIBITANYPOLICYFAILED); + + /* Name Constraints */ + PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints + (cert, &nameConstraints, plContext), + PKIX_CERTGETNAMECONSTRAINTSFAILED); + + PKIX_TOSTRING(nameConstraints, &nameConstraintsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* Authority Information Access */ + PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess + (cert, &authorityInfoAccess, plContext), + PKIX_CERTGETAUTHORITYINFOACCESSFAILED); + + PKIX_TOSTRING(authorityInfoAccess, &authorityInfoAccessString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* Subject Information Access */ + PKIX_CHECK(PKIX_PL_Cert_GetSubjectInfoAccess + (cert, &subjectInfoAccess, plContext), + PKIX_CERTGETSUBJECTINFOACCESSFAILED); + + PKIX_TOSTRING(subjectInfoAccess, &subjectInfoAccessString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&certString, + plContext, + formatString, + certVersion + 1, + certSNString, + certIssuerString, + certSubjectString, + notBeforeString, + notAfterString, + subjAltNamesString, + authKeyIdString, + subjKeyIdString, + nssPubKeyString, + critExtOIDsString, + extKeyUsagesString, + certBasicConstraintsString, + certPolicyInfoString, + certPolicyMappingsString, + certExplicitPolicy, /* an Int32, not a String */ + certInhibitMapping, /* an Int32, not a String */ + certInhibitAnyPolicy, /* an Int32, not a String */ + nameConstraintsString, + authorityInfoAccessString, + subjectInfoAccessString, + cert->cacheFlag), /* a boolean */ + PKIX_SPRINTFFAILED); + + *pString = certString; + +cleanup: + PKIX_DECREF(certSN); + PKIX_DECREF(certSNString); + PKIX_DECREF(certIssuer); + PKIX_DECREF(certIssuerString); + PKIX_DECREF(certSubject); + PKIX_DECREF(certSubjectString); + PKIX_DECREF(notBeforeString); + PKIX_DECREF(notAfterString); + PKIX_DECREF(subjAltNames); + PKIX_DECREF(subjAltNamesString); + PKIX_DECREF(authKeyId); + PKIX_DECREF(authKeyIdString); + PKIX_DECREF(subjKeyId); + PKIX_DECREF(subjKeyIdString); + PKIX_DECREF(nssPubKey); + PKIX_DECREF(nssPubKeyString); + PKIX_DECREF(critExtOIDs); + PKIX_DECREF(critExtOIDsString); + PKIX_DECREF(extKeyUsages); + PKIX_DECREF(extKeyUsagesString); + PKIX_DECREF(basicConstraint); + PKIX_DECREF(certBasicConstraintsString); + PKIX_DECREF(policyInfo); + PKIX_DECREF(certPolicyInfoString); + PKIX_DECREF(certPolicyMappings); + PKIX_DECREF(certPolicyMappingsString); + PKIX_DECREF(nameConstraints); + PKIX_DECREF(nameConstraintsString); + PKIX_DECREF(authorityInfoAccess); + PKIX_DECREF(authorityInfoAccessString); + PKIX_DECREF(subjectInfoAccess); + PKIX_DECREF(subjectInfoAccessString); + PKIX_DECREF(formatString); + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Cert_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Cert *cert = NULL; + + PKIX_ENTER(CERT, "pkix_pl_Cert_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext), + PKIX_OBJECTNOTCERT); + + cert = (PKIX_PL_Cert*)object; + + PKIX_DECREF(cert->subject); + PKIX_DECREF(cert->issuer); + PKIX_DECREF(cert->subjAltNames); + PKIX_DECREF(cert->publicKeyAlgId); + PKIX_DECREF(cert->publicKey); + PKIX_DECREF(cert->serialNumber); + PKIX_DECREF(cert->critExtOids); + PKIX_DECREF(cert->authKeyId); + PKIX_DECREF(cert->subjKeyId); + PKIX_DECREF(cert->extKeyUsages); + PKIX_DECREF(cert->certBasicConstraints); + PKIX_DECREF(cert->certPolicyInfos); + PKIX_DECREF(cert->certPolicyMappings); + PKIX_DECREF(cert->nameConstraints); + PKIX_DECREF(cert->store); + PKIX_DECREF(cert->authorityInfoAccess); + PKIX_DECREF(cert->subjectInfoAccess); + PKIX_DECREF(cert->crldpList); + + if (cert->arenaNameConstraints){ + /* This arena was allocated for SubjectAltNames */ + PKIX_PL_NSSCALL(CERT, PORT_FreeArena, + (cert->arenaNameConstraints, PR_FALSE)); + + cert->arenaNameConstraints = NULL; + cert->nssSubjAltNames = NULL; + } + + CERT_DestroyCertificate(cert->nssCert); + cert->nssCert = NULL; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Cert_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *certString = NULL; + PKIX_PL_Cert *pkixCert = NULL; + + PKIX_ENTER(CERT, "pkix_pl_Cert_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext), + PKIX_OBJECTNOTCERT); + + pkixCert = (PKIX_PL_Cert *)object; + + PKIX_CHECK(pkix_pl_Cert_ToString_Helper + (pkixCert, PKIX_FALSE, &certString, plContext), + PKIX_CERTTOSTRINGHELPERFAILED); + + *pString = certString; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Cert_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_Cert *pkixCert = NULL; + CERTCertificate *nssCert = NULL; + unsigned char *derBytes = NULL; + PKIX_UInt32 derLength; + PKIX_UInt32 certHash; + + PKIX_ENTER(CERT, "pkix_pl_Cert_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext), + PKIX_OBJECTNOTCERT); + + pkixCert = (PKIX_PL_Cert *)object; + + nssCert = pkixCert->nssCert; + derBytes = (nssCert->derCert).data; + derLength = (nssCert->derCert).len; + + PKIX_CHECK(pkix_hash(derBytes, derLength, &certHash, plContext), + PKIX_HASHFAILED); + + *pHashcode = certHash; + +cleanup: + PKIX_RETURN(CERT); +} + + +/* + * FUNCTION: pkix_pl_Cert_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Cert_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + CERTCertificate *firstCert = NULL; + CERTCertificate *secondCert = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult; + + PKIX_ENTER(CERT, "pkix_pl_Cert_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a Cert */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CERT_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERT); + + /* + * Since we know firstObject is a Cert, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a Cert, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERT_TYPE) goto cleanup; + + firstCert = ((PKIX_PL_Cert *)firstObject)->nssCert; + secondCert = ((PKIX_PL_Cert *)secondObject)->nssCert; + + PKIX_NULLCHECK_TWO(firstCert, secondCert); + + /* CERT_CompareCerts does byte comparison on DER encodings of certs */ + PKIX_CERT_DEBUG("\t\tCalling CERT_CompareCerts).\n"); + cmpResult = CERT_CompareCerts(firstCert, secondCert); + + *pResult = cmpResult; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERT_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_Cert_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERT, "pkix_pl_Cert_RegisterSelf"); + + entry.description = "Cert"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_Cert); + entry.destructor = pkix_pl_Cert_Destroy; + entry.equalsFunction = pkix_pl_Cert_Equals; + entry.hashcodeFunction = pkix_pl_Cert_Hashcode; + entry.toStringFunction = pkix_pl_Cert_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERT_TYPE] = entry; + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_CreateWithNSSCert + * DESCRIPTION: + * + * Creates a new certificate using the CERTCertificate pointed to by "nssCert" + * and stores it at "pCert". Once created, a Cert is immutable. + * + * This function is primarily used as a convenience function for the + * performance tests that have easy access to a CERTCertificate. + * + * PARAMETERS: + * "nssCert" + * Address of CERTCertificate representing the NSS certificate. + * 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 Cert 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_Cert_CreateWithNSSCert( + CERTCertificate *nssCert, + PKIX_PL_Cert **pCert, + void *plContext) +{ + PKIX_PL_Cert *cert = NULL; + + PKIX_ENTER(CERT, "pkix_pl_Cert_CreateWithNSSCert"); + PKIX_NULLCHECK_TWO(pCert, nssCert); + + /* create a PKIX_PL_Cert object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERT_TYPE, + sizeof (PKIX_PL_Cert), + (PKIX_PL_Object **)&cert, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* populate the nssCert field */ + cert->nssCert = nssCert; + + /* initialize remaining fields */ + /* + * Fields ending with Absent are initialized to PKIX_FALSE so that the + * first time we need the value we will look for it. If we find it is + * actually absent, the flag will at that time be set to PKIX_TRUE to + * prevent searching for it later. + * Fields ending with Processed are those where a value is defined + * for the Absent case, and a value of zero is possible. When the + * flag is still true we have to look for the field, set the default + * value if necessary, and set the Processed flag to PKIX_TRUE. + */ + cert->subject = NULL; + cert->issuer = NULL; + cert->subjAltNames = NULL; + cert->subjAltNamesAbsent = PKIX_FALSE; + cert->publicKeyAlgId = NULL; + cert->publicKey = NULL; + cert->serialNumber = NULL; + cert->critExtOids = NULL; + cert->subjKeyId = NULL; + cert->subjKeyIdAbsent = PKIX_FALSE; + cert->authKeyId = NULL; + cert->authKeyIdAbsent = PKIX_FALSE; + cert->extKeyUsages = NULL; + cert->extKeyUsagesAbsent = PKIX_FALSE; + cert->certBasicConstraints = NULL; + cert->basicConstraintsAbsent = PKIX_FALSE; + cert->certPolicyInfos = NULL; + cert->policyInfoAbsent = PKIX_FALSE; + cert->policyMappingsAbsent = PKIX_FALSE; + cert->certPolicyMappings = NULL; + cert->policyConstraintsProcessed = PKIX_FALSE; + cert->policyConstraintsExplicitPolicySkipCerts = 0; + cert->policyConstraintsInhibitMappingSkipCerts = 0; + cert->inhibitAnyPolicyProcessed = PKIX_FALSE; + cert->inhibitAnySkipCerts = 0; + cert->nameConstraints = NULL; + cert->nameConstraintsAbsent = PKIX_FALSE; + cert->arenaNameConstraints = NULL; + cert->nssSubjAltNames = NULL; + cert->cacheFlag = PKIX_FALSE; + cert->store = NULL; + cert->authorityInfoAccess = NULL; + cert->subjectInfoAccess = NULL; + cert->isUserTrustAnchor = PKIX_FALSE; + cert->crldpList = NULL; + + *pCert = cert; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: pkix_pl_Cert_CreateToList + * DESCRIPTION: + * + * Creates a new certificate using the DER-encoding pointed to by "derCertItem" + * and appends it to the list pointed to by "certList". If Cert creation fails, + * the function returns with certList unchanged, but any decoding Error is + * discarded. + * + * PARAMETERS: + * "derCertItem" + * Address of SECItem containing the DER representation of a certificate. + * Must be non-NULL. + * "certList" + * Address of List to which the Cert will be appended, if successfully + * created. 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 Cert 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_Cert_CreateToList( + SECItem *derCertItem, + PKIX_List *certList, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + PKIX_PL_Cert *cert = NULL; + CERTCertDBHandle *handle; + + PKIX_ENTER(CERT, "pkix_pl_Cert_CreateToList"); + PKIX_NULLCHECK_TWO(derCertItem, certList); + + handle = CERT_GetDefaultCertDB(); + nssCert = CERT_NewTempCertificate(handle, derCertItem, + /* nickname */ NULL, + /* isPerm */ PR_FALSE, + /* copyDer */ PR_TRUE); + if (!nssCert) { + goto cleanup; + } + + PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert + (nssCert, &cert, plContext), + PKIX_CERTCREATEWITHNSSCERTFAILED); + + nssCert = NULL; + + PKIX_CHECK(PKIX_List_AppendItem + (certList, (PKIX_PL_Object *) cert, plContext), + PKIX_LISTAPPENDITEMFAILED); + +cleanup: + if (nssCert) { + CERT_DestroyCertificate(nssCert); + } + + PKIX_DECREF(cert); + PKIX_RETURN(CERT); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_Cert_Create (see comments in pkix_pl_pki.h) + * XXX We may want to cache the cert after parsing it, so it can be reused + * XXX Are the NSS/NSPR functions thread safe + */ +PKIX_Error * +PKIX_PL_Cert_Create( + PKIX_PL_ByteArray *byteArray, + PKIX_PL_Cert **pCert, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + SECItem *derCertItem = NULL; + void *derBytes = NULL; + PKIX_UInt32 derLength; + PKIX_PL_Cert *cert = NULL; + CERTCertDBHandle *handle; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_Create"); + PKIX_NULLCHECK_TWO(pCert, byteArray); + + PKIX_CHECK(PKIX_PL_ByteArray_GetPointer + (byteArray, &derBytes, plContext), + PKIX_BYTEARRAYGETPOINTERFAILED); + + PKIX_CHECK(PKIX_PL_ByteArray_GetLength + (byteArray, &derLength, plContext), + PKIX_BYTEARRAYGETLENGTHFAILED); + + derCertItem = SECITEM_AllocItem(NULL, NULL, derLength); + if (derCertItem == NULL){ + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + (void) PORT_Memcpy(derCertItem->data, derBytes, derLength); + + /* + * setting copyDER to true forces NSS to make its own copy of the DER, + * allowing us to free our copy without worrying about whether NSS + * is still using it + */ + handle = CERT_GetDefaultCertDB(); + nssCert = CERT_NewTempCertificate(handle, derCertItem, + /* nickname */ NULL, + /* isPerm */ PR_FALSE, + /* copyDer */ PR_TRUE); + if (!nssCert){ + PKIX_ERROR(PKIX_CERTDECODEDERCERTIFICATEFAILED); + } + + PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert + (nssCert, &cert, plContext), + PKIX_CERTCREATEWITHNSSCERTFAILED); + + *pCert = cert; + +cleanup: + if (derCertItem){ + SECITEM_FreeItem(derCertItem, PKIX_TRUE); + } + + if (nssCert && PKIX_ERROR_RECEIVED){ + PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyCertificate).\n"); + CERT_DestroyCertificate(nssCert); + nssCert = NULL; + } + + PKIX_FREE(derBytes); + PKIX_RETURN(CERT); +} + + +/* + * FUNCTION: PKIX_PL_Cert_CreateFromCERTCertificate + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_CreateFromCERTCertificate( + const CERTCertificate *nssCert, + PKIX_PL_Cert **pCert, + void *plContext) +{ + void *buf = NULL; + PKIX_UInt32 len; + PKIX_PL_ByteArray *byteArray = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_CreateWithNssCert"); + PKIX_NULLCHECK_TWO(pCert, nssCert); + + buf = (void*)nssCert->derCert.data; + len = nssCert->derCert.len; + + PKIX_CHECK( + PKIX_PL_ByteArray_Create(buf, len, &byteArray, plContext), + PKIX_BYTEARRAYCREATEFAILED); + + PKIX_CHECK( + PKIX_PL_Cert_Create(byteArray, pCert, plContext), + PKIX_CERTCREATEWITHNSSCERTFAILED); + +#ifdef PKIX_UNDEF + /* will be tested and used as a patch for bug 391612 */ + nssCert = CERT_DupCertificate(nssInCert); + + PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert + (nssCert, &cert, plContext), + PKIX_CERTCREATEWITHNSSCERTFAILED); +#endif /* PKIX_UNDEF */ + +cleanup: + +#ifdef PKIX_UNDEF + if (nssCert && PKIX_ERROR_RECEIVED){ + PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyCertificate).\n"); + CERT_DestroyCertificate(nssCert); + nssCert = NULL; + } +#endif /* PKIX_UNDEF */ + + PKIX_DECREF(byteArray); + PKIX_RETURN(CERT); +} + + +/* + * FUNCTION: PKIX_PL_Cert_GetVersion (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetVersion( + PKIX_PL_Cert *cert, + PKIX_UInt32 *pVersion, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + PKIX_UInt32 myVersion = 0; /* v1 */ + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetVersion"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pVersion); + + nssCert = cert->nssCert; + if (nssCert->version.len != 0) { + myVersion = *(nssCert->version.data); + } + + if (myVersion > 2){ + PKIX_ERROR(PKIX_VERSIONVALUEMUSTBEV1V2ORV3); + } + + *pVersion = myVersion; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetSerialNumber (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetSerialNumber( + PKIX_PL_Cert *cert, + PKIX_PL_BigInt **pSerialNumber, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + SECItem serialNumItem; + PKIX_PL_BigInt *serialNumber = NULL; + char *bytes = NULL; + PKIX_UInt32 length; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSerialNumber"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSerialNumber); + + if (cert->serialNumber == NULL){ + + PKIX_OBJECT_LOCK(cert); + + if (cert->serialNumber == NULL){ + + nssCert = cert->nssCert; + serialNumItem = nssCert->serialNumber; + + length = serialNumItem.len; + bytes = (char *)serialNumItem.data; + + PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes + (bytes, length, &serialNumber, plContext), + PKIX_BIGINTCREATEWITHBYTESFAILED); + + /* save a cached copy in case it is asked for again */ + cert->serialNumber = serialNumber; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->serialNumber); + *pSerialNumber = cert->serialNumber; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetSubject (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetSubject( + PKIX_PL_Cert *cert, + PKIX_PL_X500Name **pCertSubject, + void *plContext) +{ + PKIX_PL_X500Name *pkixSubject = NULL; + CERTName *subjName = NULL; + SECItem *derSubjName = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubject"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCertSubject); + + /* if we don't have a cached copy from before, we create one */ + if (cert->subject == NULL){ + + PKIX_OBJECT_LOCK(cert); + + if (cert->subject == NULL){ + + subjName = &cert->nssCert->subject; + derSubjName = &cert->nssCert->derSubject; + + /* if there is no subject name */ + if (derSubjName->data == NULL) { + + pkixSubject = NULL; + + } else { + PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName + (derSubjName, subjName, &pkixSubject, + plContext), + PKIX_X500NAMECREATEFROMCERTNAMEFAILED); + + } + /* save a cached copy in case it is asked for again */ + cert->subject = pkixSubject; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->subject); + *pCertSubject = cert->subject; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetIssuer (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetIssuer( + PKIX_PL_Cert *cert, + PKIX_PL_X500Name **pCertIssuer, + void *plContext) +{ + PKIX_PL_X500Name *pkixIssuer = NULL; + SECItem *derIssuerName = NULL; + CERTName *issuerName = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetIssuer"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCertIssuer); + + /* if we don't have a cached copy from before, we create one */ + if (cert->issuer == NULL){ + + PKIX_OBJECT_LOCK(cert); + + if (cert->issuer == NULL){ + + issuerName = &cert->nssCert->issuer; + derIssuerName = &cert->nssCert->derIssuer; + + /* if there is no subject name */ + PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName + (derIssuerName, issuerName, + &pkixIssuer, plContext), + PKIX_X500NAMECREATEFROMCERTNAMEFAILED); + + /* save a cached copy in case it is asked for again */ + cert->issuer = pkixIssuer; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->issuer); + *pCertIssuer = cert->issuer; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetSubjectAltNames (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetSubjectAltNames( + PKIX_PL_Cert *cert, + PKIX_List **pSubjectAltNames, /* list of PKIX_PL_GeneralName */ + void *plContext) +{ + PKIX_PL_GeneralName *pkixAltName = NULL; + PKIX_List *altNamesList = NULL; + + CERTGeneralName *nssOriginalAltName = NULL; + CERTGeneralName *nssTempAltName = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectAltNames"); + PKIX_NULLCHECK_TWO(cert, pSubjectAltNames); + + /* if we don't have a cached copy from before, we create one */ + if ((cert->subjAltNames == NULL) && (!cert->subjAltNamesAbsent)){ + + PKIX_OBJECT_LOCK(cert); + + if ((cert->subjAltNames == NULL) && + (!cert->subjAltNamesAbsent)){ + + PKIX_CHECK(pkix_pl_Cert_GetNssSubjectAltNames + (cert, + PKIX_TRUE, + &nssOriginalAltName, + plContext), + PKIX_CERTGETNSSSUBJECTALTNAMESFAILED); + + if (nssOriginalAltName == NULL) { + cert->subjAltNamesAbsent = PKIX_TRUE; + pSubjectAltNames = NULL; + goto cleanup; + } + + nssTempAltName = nssOriginalAltName; + + PKIX_CHECK(PKIX_List_Create(&altNamesList, plContext), + PKIX_LISTCREATEFAILED); + + do { + PKIX_CHECK(pkix_pl_GeneralName_Create + (nssTempAltName, &pkixAltName, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (altNamesList, + (PKIX_PL_Object *)pkixAltName, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(pkixAltName); + + PKIX_CERT_DEBUG + ("\t\tCalling CERT_GetNextGeneralName).\n"); + nssTempAltName = CERT_GetNextGeneralName + (nssTempAltName); + + } while (nssTempAltName != nssOriginalAltName); + + /* save a cached copy in case it is asked for again */ + cert->subjAltNames = altNamesList; + PKIX_CHECK(PKIX_List_SetImmutable + (cert->subjAltNames, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->subjAltNames); + + *pSubjectAltNames = cert->subjAltNames; + +cleanup: + PKIX_DECREF(pkixAltName); + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(altNamesList); + } + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetAllSubjectNames (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetAllSubjectNames( + PKIX_PL_Cert *cert, + PKIX_List **pAllSubjectNames, /* list of PKIX_PL_GeneralName */ + void *plContext) +{ + CERTGeneralName *nssOriginalSubjectName = NULL; + CERTGeneralName *nssTempSubjectName = NULL; + PKIX_List *allSubjectNames = NULL; + PKIX_PL_GeneralName *pkixSubjectName = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAllSubjectNames"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAllSubjectNames); + + + if (cert->nssCert->subjectName == NULL){ + /* if there is no subject DN, just get altnames */ + + PKIX_CHECK(pkix_pl_Cert_GetNssSubjectAltNames + (cert, + PKIX_FALSE, /* hasLock */ + &nssOriginalSubjectName, + plContext), + PKIX_CERTGETNSSSUBJECTALTNAMESFAILED); + + } else { /* get subject DN and altnames */ + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + /* This NSS call returns both Subject and Subject Alt Names */ + PKIX_CERT_DEBUG("\t\tCalling CERT_GetCertificateNames\n"); + nssOriginalSubjectName = + CERT_GetCertificateNames(cert->nssCert, arena); + } + + if (nssOriginalSubjectName == NULL) { + pAllSubjectNames = NULL; + goto cleanup; + } + + nssTempSubjectName = nssOriginalSubjectName; + + PKIX_CHECK(PKIX_List_Create(&allSubjectNames, plContext), + PKIX_LISTCREATEFAILED); + + do { + PKIX_CHECK(pkix_pl_GeneralName_Create + (nssTempSubjectName, &pkixSubjectName, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (allSubjectNames, + (PKIX_PL_Object *)pkixSubjectName, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(pkixSubjectName); + + PKIX_CERT_DEBUG + ("\t\tCalling CERT_GetNextGeneralName).\n"); + nssTempSubjectName = CERT_GetNextGeneralName + (nssTempSubjectName); + } while (nssTempSubjectName != nssOriginalSubjectName); + + *pAllSubjectNames = allSubjectNames; + +cleanup: + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(allSubjectNames); + } + + if (arena){ + PORT_FreeArena(arena, PR_FALSE); + } + PKIX_DECREF(pkixSubjectName); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetSubjectPublicKeyAlgId + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetSubjectPublicKeyAlgId( + PKIX_PL_Cert *cert, + PKIX_PL_OID **pSubjKeyAlgId, + void *plContext) +{ + PKIX_PL_OID *pubKeyAlgId = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectPublicKeyAlgId"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSubjKeyAlgId); + + /* if we don't have a cached copy from before, we create one */ + if (cert->publicKeyAlgId == NULL){ + PKIX_OBJECT_LOCK(cert); + if (cert->publicKeyAlgId == NULL){ + CERTCertificate *nssCert = cert->nssCert; + SECAlgorithmID *algorithm; + SECItem *algBytes; + + algorithm = &nssCert->subjectPublicKeyInfo.algorithm; + algBytes = &algorithm->algorithm; + if (!algBytes->data || !algBytes->len) { + PKIX_ERROR_FATAL(PKIX_ALGORITHMBYTESLENGTH0); + } + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (algBytes, &pubKeyAlgId, plContext), + PKIX_OIDCREATEFAILED); + + /* save a cached copy in case it is asked for again */ + cert->publicKeyAlgId = pubKeyAlgId; + pubKeyAlgId = NULL; + } + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->publicKeyAlgId); + *pSubjKeyAlgId = cert->publicKeyAlgId; + +cleanup: + PKIX_DECREF(pubKeyAlgId); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetSubjectPublicKey (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetSubjectPublicKey( + PKIX_PL_Cert *cert, + PKIX_PL_PublicKey **pPublicKey, + void *plContext) +{ + PKIX_PL_PublicKey *pkixPubKey = NULL; + SECStatus rv; + + CERTSubjectPublicKeyInfo *from = NULL; + CERTSubjectPublicKeyInfo *to = NULL; + SECItem *fromItem = NULL; + SECItem *toItem = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectPublicKey"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPublicKey); + + /* if we don't have a cached copy from before, we create one */ + if (cert->publicKey == NULL){ + + PKIX_OBJECT_LOCK(cert); + + if (cert->publicKey == NULL){ + + /* create a PKIX_PL_PublicKey object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_PUBLICKEY_TYPE, + sizeof (PKIX_PL_PublicKey), + (PKIX_PL_Object **)&pkixPubKey, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* initialize fields */ + pkixPubKey->nssSPKI = NULL; + + /* populate the SPKI field */ + PKIX_CHECK(PKIX_PL_Malloc + (sizeof (CERTSubjectPublicKeyInfo), + (void **)&pkixPubKey->nssSPKI, + plContext), + PKIX_MALLOCFAILED); + + to = pkixPubKey->nssSPKI; + from = &cert->nssCert->subjectPublicKeyInfo; + + PKIX_NULLCHECK_TWO(to, from); + + PKIX_CERT_DEBUG + ("\t\tCalling SECOID_CopyAlgorithmID).\n"); + rv = SECOID_CopyAlgorithmID + (NULL, &to->algorithm, &from->algorithm); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_SECOIDCOPYALGORITHMIDFAILED); + } + + /* + * NSS stores the length of subjectPublicKey in bits. + * Therefore, we use that length converted to bytes + * using ((length+7)>>3) before calling PORT_Memcpy + * in order to avoid "read from uninitialized memory" + * errors. + */ + + toItem = &to->subjectPublicKey; + fromItem = &from->subjectPublicKey; + + PKIX_NULLCHECK_TWO(toItem, fromItem); + + toItem->type = fromItem->type; + + toItem->data = + (unsigned char*) PORT_ZAlloc(fromItem->len); + if (!toItem->data){ + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + (void) PORT_Memcpy(toItem->data, + fromItem->data, + (fromItem->len + 7)>>3); + toItem->len = fromItem->len; + + /* save a cached copy in case it is asked for again */ + cert->publicKey = pkixPubKey; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->publicKey); + *pPublicKey = cert->publicKey; + +cleanup: + + if (PKIX_ERROR_RECEIVED && pkixPubKey){ + PKIX_DECREF(pkixPubKey); + cert->publicKey = NULL; + } + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetCriticalExtensionOIDs + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetCriticalExtensionOIDs( + PKIX_PL_Cert *cert, + PKIX_List **pList, /* list of PKIX_PL_OID */ + void *plContext) +{ + PKIX_List *oidsList = NULL; + CERTCertExtension **extensions = NULL; + CERTCertificate *nssCert = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCriticalExtensionOIDs"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pList); + + /* if we don't have a cached copy from before, we create one */ + if (cert->critExtOids == NULL) { + + PKIX_OBJECT_LOCK(cert); + + if (cert->critExtOids == NULL) { + + nssCert = cert->nssCert; + + /* + * ASN.1 for Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + * + */ + + extensions = nssCert->extensions; + + PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs + (extensions, &oidsList, plContext), + PKIX_GETCRITICALEXTENSIONOIDSFAILED); + + /* save a cached copy in case it is asked for again */ + cert->critExtOids = oidsList; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + /* We should return a copy of the List since this list changes */ + PKIX_DUPLICATE(cert->critExtOids, pList, plContext, + PKIX_OBJECTDUPLICATELISTFAILED); + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetAuthorityKeyIdentifier + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetAuthorityKeyIdentifier( + PKIX_PL_Cert *cert, + PKIX_PL_ByteArray **pAuthKeyId, + void *plContext) +{ + PKIX_PL_ByteArray *authKeyId = NULL; + CERTCertificate *nssCert = NULL; + CERTAuthKeyID *authKeyIdExtension = NULL; + PLArenaPool *arena = NULL; + SECItem retItem; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAuthorityKeyIdentifier"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAuthKeyId); + + /* if we don't have a cached copy from before, we create one */ + if ((cert->authKeyId == NULL) && (!cert->authKeyIdAbsent)){ + + PKIX_OBJECT_LOCK(cert); + + if ((cert->authKeyId == NULL) && (!cert->authKeyIdAbsent)){ + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + nssCert = cert->nssCert; + + authKeyIdExtension = + CERT_FindAuthKeyIDExten(arena, nssCert); + if (authKeyIdExtension == NULL){ + cert->authKeyIdAbsent = PKIX_TRUE; + *pAuthKeyId = NULL; + goto cleanup; + } + + retItem = authKeyIdExtension->keyID; + + if (retItem.len == 0){ + cert->authKeyIdAbsent = PKIX_TRUE; + *pAuthKeyId = NULL; + goto cleanup; + } + + PKIX_CHECK(PKIX_PL_ByteArray_Create + (retItem.data, + retItem.len, + &authKeyId, + plContext), + PKIX_BYTEARRAYCREATEFAILED); + + /* save a cached copy in case it is asked for again */ + cert->authKeyId = authKeyId; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->authKeyId); + *pAuthKeyId = cert->authKeyId; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + if (arena){ + PORT_FreeArena(arena, PR_FALSE); + } + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetSubjectKeyIdentifier + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetSubjectKeyIdentifier( + PKIX_PL_Cert *cert, + PKIX_PL_ByteArray **pSubjKeyId, + void *plContext) +{ + PKIX_PL_ByteArray *subjKeyId = NULL; + CERTCertificate *nssCert = NULL; + SECItem *retItem = NULL; + SECStatus status; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectKeyIdentifier"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSubjKeyId); + + /* if we don't have a cached copy from before, we create one */ + if ((cert->subjKeyId == NULL) && (!cert->subjKeyIdAbsent)){ + + PKIX_OBJECT_LOCK(cert); + + if ((cert->subjKeyId == NULL) && (!cert->subjKeyIdAbsent)){ + + retItem = SECITEM_AllocItem(NULL, NULL, 0); + if (retItem == NULL){ + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + nssCert = cert->nssCert; + + status = CERT_FindSubjectKeyIDExtension + (nssCert, retItem); + if (status != SECSuccess) { + cert->subjKeyIdAbsent = PKIX_TRUE; + *pSubjKeyId = NULL; + goto cleanup; + } + + PKIX_CHECK(PKIX_PL_ByteArray_Create + (retItem->data, + retItem->len, + &subjKeyId, + plContext), + PKIX_BYTEARRAYCREATEFAILED); + + /* save a cached copy in case it is asked for again */ + cert->subjKeyId = subjKeyId; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->subjKeyId); + *pSubjKeyId = cert->subjKeyId; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + if (retItem){ + SECITEM_FreeItem(retItem, PKIX_TRUE); + } + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetExtendedKeyUsage (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetExtendedKeyUsage( + PKIX_PL_Cert *cert, + PKIX_List **pKeyUsage, /* list of PKIX_PL_OID */ + void *plContext) +{ + CERTOidSequence *extKeyUsage = NULL; + CERTCertificate *nssCert = NULL; + PKIX_PL_OID *pkixOID = NULL; + PKIX_List *oidsList = NULL; + SECItem **oids = NULL; + SECItem encodedExtKeyUsage; + SECStatus rv; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetExtendedKeyUsage"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pKeyUsage); + + /* if we don't have a cached copy from before, we create one */ + if ((cert->extKeyUsages == NULL) && (!cert->extKeyUsagesAbsent)){ + + PKIX_OBJECT_LOCK(cert); + + if ((cert->extKeyUsages == NULL) && + (!cert->extKeyUsagesAbsent)){ + + nssCert = cert->nssCert; + + rv = CERT_FindCertExtension + (nssCert, SEC_OID_X509_EXT_KEY_USAGE, + &encodedExtKeyUsage); + if (rv != SECSuccess){ + cert->extKeyUsagesAbsent = PKIX_TRUE; + *pKeyUsage = NULL; + goto cleanup; + } + + extKeyUsage = + CERT_DecodeOidSequence(&encodedExtKeyUsage); + if (extKeyUsage == NULL){ + PKIX_ERROR(PKIX_CERTDECODEOIDSEQUENCEFAILED); + } + + PORT_Free(encodedExtKeyUsage.data); + + oids = extKeyUsage->oids; + + if (!oids){ + /* no extended key usage extensions found */ + cert->extKeyUsagesAbsent = PKIX_TRUE; + *pKeyUsage = NULL; + goto cleanup; + } + + PKIX_CHECK(PKIX_List_Create(&oidsList, plContext), + PKIX_LISTCREATEFAILED); + + while (*oids){ + SECItem *oid = *oids++; + + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (oid, &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (oidsList, + (PKIX_PL_Object *)pkixOID, + plContext), + PKIX_LISTAPPENDITEMFAILED); + PKIX_DECREF(pkixOID); + } + + PKIX_CHECK(PKIX_List_SetImmutable + (oidsList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + /* save a cached copy in case it is asked for again */ + cert->extKeyUsages = oidsList; + oidsList = NULL; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->extKeyUsages); + *pKeyUsage = cert->extKeyUsages; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + + PKIX_DECREF(pkixOID); + PKIX_DECREF(oidsList); + CERT_DestroyOidSequence(extKeyUsage); + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetBasicConstraints + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetBasicConstraints( + PKIX_PL_Cert *cert, + PKIX_PL_CertBasicConstraints **pBasicConstraints, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + CERTBasicConstraints nssBasicConstraint; + SECStatus rv; + PKIX_PL_CertBasicConstraints *basic; + PKIX_Int32 pathLen = 0; + PKIX_Boolean isCA = PKIX_FALSE; + enum { + realBC, synthBC, absentBC + } constraintSource = absentBC; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetBasicConstraints"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pBasicConstraints); + + /* if we don't have a cached copy from before, we create one */ + if ((cert->certBasicConstraints == NULL) && + (!cert->basicConstraintsAbsent)) { + + PKIX_OBJECT_LOCK(cert); + + if ((cert->certBasicConstraints == NULL) && + (!cert->basicConstraintsAbsent)) { + + nssCert = cert->nssCert; + + PKIX_CERT_DEBUG( + "\t\tCalling Cert_FindBasicConstraintExten\n"); + rv = CERT_FindBasicConstraintExten + (nssCert, &nssBasicConstraint); + if (rv == SECSuccess) { + constraintSource = realBC; + } + + if (constraintSource == absentBC) { + /* can we deduce it's a CA and create a + synthetic constraint? + */ + CERTCertTrust trust; + rv = CERT_GetCertTrust(nssCert, &trust); + if (rv == SECSuccess) { + int anyWantedFlag = CERTDB_TRUSTED_CA | CERTDB_VALID_CA; + if ((trust.sslFlags & anyWantedFlag) + || (trust.emailFlags & anyWantedFlag) + || (trust.objectSigningFlags & anyWantedFlag)) { + + constraintSource = synthBC; + } + } + } + + if (constraintSource == absentBC) { + cert->basicConstraintsAbsent = PKIX_TRUE; + *pBasicConstraints = NULL; + goto cleanup; + } + } + + if (constraintSource == synthBC) { + isCA = PKIX_TRUE; + pathLen = PKIX_UNLIMITED_PATH_CONSTRAINT; + } else { + isCA = (nssBasicConstraint.isCA)?PKIX_TRUE:PKIX_FALSE; + + /* The pathLen has meaning only for CAs */ + if (isCA) { + if (CERT_UNLIMITED_PATH_CONSTRAINT == + nssBasicConstraint.pathLenConstraint) { + pathLen = PKIX_UNLIMITED_PATH_CONSTRAINT; + } else { + pathLen = nssBasicConstraint.pathLenConstraint; + } + } + } + + PKIX_CHECK(pkix_pl_CertBasicConstraints_Create + (isCA, pathLen, &basic, plContext), + PKIX_CERTBASICCONSTRAINTSCREATEFAILED); + + /* save a cached copy in case it is asked for again */ + cert->certBasicConstraints = basic; + } + + PKIX_INCREF(cert->certBasicConstraints); + *pBasicConstraints = cert->certBasicConstraints; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetPolicyInformation + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetPolicyInformation( + PKIX_PL_Cert *cert, + PKIX_List **pPolicyInfo, + void *plContext) +{ + PKIX_List *policyList = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyInformation"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPolicyInfo); + + /* if we don't have a cached copy from before, we create one */ + if ((cert->certPolicyInfos == NULL) && + (!cert->policyInfoAbsent)) { + + PKIX_OBJECT_LOCK(cert); + + if ((cert->certPolicyInfos == NULL) && + (!cert->policyInfoAbsent)) { + + PKIX_CHECK(pkix_pl_Cert_DecodePolicyInfo + (cert->nssCert, &policyList, plContext), + PKIX_CERTDECODEPOLICYINFOFAILED); + + if (!policyList) { + cert->policyInfoAbsent = PKIX_TRUE; + *pPolicyInfo = NULL; + goto cleanup; + } + } + + PKIX_OBJECT_UNLOCK(cert); + + /* save a cached copy in case it is asked for again */ + cert->certPolicyInfos = policyList; + policyList = NULL; + } + + PKIX_INCREF(cert->certPolicyInfos); + *pPolicyInfo = cert->certPolicyInfos; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + + PKIX_DECREF(policyList); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetPolicyMappings (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetPolicyMappings( + PKIX_PL_Cert *cert, + PKIX_List **pPolicyMappings, /* list of PKIX_PL_CertPolicyMap */ + void *plContext) +{ + PKIX_List *policyMappings = NULL; /* list of PKIX_PL_CertPolicyMap */ + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyMappings"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPolicyMappings); + + /* if we don't have a cached copy from before, we create one */ + if (!(cert->certPolicyMappings) && !(cert->policyMappingsAbsent)) { + + PKIX_OBJECT_LOCK(cert); + + if (!(cert->certPolicyMappings) && + !(cert->policyMappingsAbsent)) { + + PKIX_CHECK(pkix_pl_Cert_DecodePolicyMapping + (cert->nssCert, &policyMappings, plContext), + PKIX_CERTDECODEPOLICYMAPPINGFAILED); + + if (!policyMappings) { + cert->policyMappingsAbsent = PKIX_TRUE; + *pPolicyMappings = NULL; + goto cleanup; + } + } + + PKIX_OBJECT_UNLOCK(cert); + + /* save a cached copy in case it is asked for again */ + cert->certPolicyMappings = policyMappings; + policyMappings = NULL; + } + + PKIX_INCREF(cert->certPolicyMappings); + *pPolicyMappings = cert->certPolicyMappings; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + + PKIX_DECREF(policyMappings); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetRequireExplicitPolicy + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetRequireExplicitPolicy( + PKIX_PL_Cert *cert, + PKIX_Int32 *pSkipCerts, + void *plContext) +{ + PKIX_Int32 explicitPolicySkipCerts = 0; + PKIX_Int32 inhibitMappingSkipCerts = 0; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetRequireExplicitPolicy"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts); + + if (!(cert->policyConstraintsProcessed)) { + PKIX_OBJECT_LOCK(cert); + + if (!(cert->policyConstraintsProcessed)) { + + /* + * If we can't process it now, we probably will be + * unable to process it later. Set the default value. + */ + cert->policyConstraintsProcessed = PKIX_TRUE; + cert->policyConstraintsExplicitPolicySkipCerts = -1; + cert->policyConstraintsInhibitMappingSkipCerts = -1; + + PKIX_CHECK(pkix_pl_Cert_DecodePolicyConstraints + (cert->nssCert, + &explicitPolicySkipCerts, + &inhibitMappingSkipCerts, + plContext), + PKIX_CERTDECODEPOLICYCONSTRAINTSFAILED); + + cert->policyConstraintsExplicitPolicySkipCerts = + explicitPolicySkipCerts; + cert->policyConstraintsInhibitMappingSkipCerts = + inhibitMappingSkipCerts; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + *pSkipCerts = cert->policyConstraintsExplicitPolicySkipCerts; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetPolicyMappingInhibited + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetPolicyMappingInhibited( + PKIX_PL_Cert *cert, + PKIX_Int32 *pSkipCerts, + void *plContext) +{ + PKIX_Int32 explicitPolicySkipCerts = 0; + PKIX_Int32 inhibitMappingSkipCerts = 0; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyMappingInhibited"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts); + + if (!(cert->policyConstraintsProcessed)) { + PKIX_OBJECT_LOCK(cert); + + if (!(cert->policyConstraintsProcessed)) { + + /* + * If we can't process it now, we probably will be + * unable to process it later. Set the default value. + */ + cert->policyConstraintsProcessed = PKIX_TRUE; + cert->policyConstraintsExplicitPolicySkipCerts = -1; + cert->policyConstraintsInhibitMappingSkipCerts = -1; + + PKIX_CHECK(pkix_pl_Cert_DecodePolicyConstraints + (cert->nssCert, + &explicitPolicySkipCerts, + &inhibitMappingSkipCerts, + plContext), + PKIX_CERTDECODEPOLICYCONSTRAINTSFAILED); + + cert->policyConstraintsExplicitPolicySkipCerts = + explicitPolicySkipCerts; + cert->policyConstraintsInhibitMappingSkipCerts = + inhibitMappingSkipCerts; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + *pSkipCerts = cert->policyConstraintsInhibitMappingSkipCerts; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetInhibitAnyPolicy (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetInhibitAnyPolicy( + PKIX_PL_Cert *cert, + PKIX_Int32 *pSkipCerts, + void *plContext) +{ + PKIX_Int32 skipCerts = 0; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetInhibitAnyPolicy"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts); + + if (!(cert->inhibitAnyPolicyProcessed)) { + + PKIX_OBJECT_LOCK(cert); + + if (!(cert->inhibitAnyPolicyProcessed)) { + + /* + * If we can't process it now, we probably will be + * unable to process it later. Set the default value. + */ + cert->inhibitAnyPolicyProcessed = PKIX_TRUE; + cert->inhibitAnySkipCerts = -1; + + PKIX_CHECK(pkix_pl_Cert_DecodeInhibitAnyPolicy + (cert->nssCert, &skipCerts, plContext), + PKIX_CERTDECODEINHIBITANYPOLICYFAILED); + + cert->inhibitAnySkipCerts = skipCerts; + } + + PKIX_OBJECT_UNLOCK(cert); + } + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + *pSkipCerts = cert->inhibitAnySkipCerts; + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_AreCertPoliciesCritical + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_AreCertPoliciesCritical( + PKIX_PL_Cert *cert, + PKIX_Boolean *pCritical, + void *plContext) +{ + PKIX_Boolean criticality = PKIX_FALSE; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_AreCertPoliciesCritical"); + PKIX_NULLCHECK_TWO(cert, pCritical); + + PKIX_CHECK(pkix_pl_Cert_IsExtensionCritical( + cert, + SEC_OID_X509_CERTIFICATE_POLICIES, + &criticality, + plContext), + PKIX_CERTISEXTENSIONCRITICALFAILED); + + *pCritical = criticality; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_VerifySignature (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_VerifySignature( + PKIX_PL_Cert *cert, + PKIX_PL_PublicKey *pubKey, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + SECKEYPublicKey *nssPubKey = NULL; + CERTSignedData *tbsCert = NULL; + PKIX_PL_Cert *cachedCert = NULL; + PKIX_Error *verifySig = NULL; + PKIX_Error *cachedSig = NULL; + PKIX_Error *checkSig = NULL; + SECStatus status; + PKIX_Boolean certEqual = PKIX_FALSE; + PKIX_Boolean certInHash = PKIX_FALSE; + PKIX_Boolean checkCertSig = PKIX_TRUE; + void* wincx = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifySignature"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pubKey); + + /* if the cert check flag is off, skip the check */ + checkSig = pkix_pl_NssContext_GetCertSignatureCheck( + (PKIX_PL_NssContext *)plContext, &checkCertSig); + if ((checkCertSig == PKIX_FALSE) && (checkSig == NULL)) { + goto cleanup; + } + + verifySig = PKIX_PL_HashTable_Lookup + (cachedCertSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object **) &cachedCert, + plContext); + + if (cachedCert != NULL && verifySig == NULL) { + /* Cached Signature Table lookup succeed */ + PKIX_EQUALS(cert, cachedCert, &certEqual, plContext, + PKIX_OBJECTEQUALSFAILED); + if (certEqual == PKIX_TRUE) { + goto cleanup; + } + /* Different PubKey may hash to same value, skip add */ + certInHash = PKIX_TRUE; + } + + nssCert = cert->nssCert; + tbsCert = &nssCert->signatureWrap; + + PKIX_CERT_DEBUG("\t\tCalling SECKEY_ExtractPublicKey).\n"); + nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI); + if (!nssPubKey){ + PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED); + } + + PKIX_CERT_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey).\n"); + + PKIX_CHECK(pkix_pl_NssContext_GetWincx + ((PKIX_PL_NssContext *)plContext, &wincx), + PKIX_NSSCONTEXTGETWINCXFAILED); + + status = CERT_VerifySignedDataWithPublicKey(tbsCert, nssPubKey, wincx); + + if (status != SECSuccess) { + if (PORT_GetError() != SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + } + PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY); + } + + if (certInHash == PKIX_FALSE) { + cachedSig = PKIX_PL_HashTable_Add + (cachedCertSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object *) cert, + plContext); + + if (cachedSig != NULL) { + PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n"); + } + } + +cleanup: + if (nssPubKey){ + PKIX_CERT_DEBUG("\t\tCalling SECKEY_DestroyPublicKey).\n"); + SECKEY_DestroyPublicKey(nssPubKey); + } + + PKIX_DECREF(cachedCert); + PKIX_DECREF(checkSig); + PKIX_DECREF(verifySig); + PKIX_DECREF(cachedSig); + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_CheckValidity (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_CheckValidity( + PKIX_PL_Cert *cert, + PKIX_PL_Date *date, + void *plContext) +{ + SECCertTimeValidity val; + PRTime timeToCheck; + PKIX_Boolean allowOverride; + SECCertificateUsage requiredUsages; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_CheckValidity"); + PKIX_NULLCHECK_ONE(cert); + + /* if the caller supplies a date, we use it; else, use current time */ + if (date != NULL){ + PKIX_CHECK(pkix_pl_Date_GetPRTime + (date, &timeToCheck, plContext), + PKIX_DATEGETPRTIMEFAILED); + } else { + timeToCheck = PR_Now(); + } + + requiredUsages = ((PKIX_PL_NssContext*)plContext)->certificateUsage; + allowOverride = + (PRBool)((requiredUsages & certificateUsageSSLServer) || + (requiredUsages & certificateUsageSSLServerWithStepUp) || + (requiredUsages & certificateUsageIPsec)); + val = CERT_CheckCertValidTimes(cert->nssCert, timeToCheck, allowOverride); + if (val != secCertTimeValid){ + PKIX_ERROR(PKIX_CERTCHECKCERTVALIDTIMESFAILED); + } + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetValidityNotAfter (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetValidityNotAfter( + PKIX_PL_Cert *cert, + PKIX_PL_Date **pDate, + void *plContext) +{ + PRTime prtime; + SECStatus rv = SECFailure; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetValidityNotAfter"); + PKIX_NULLCHECK_TWO(cert, pDate); + + PKIX_DATE_DEBUG("\t\tCalling DER_DecodeTimeChoice).\n"); + rv = DER_DecodeTimeChoice(&prtime, &(cert->nssCert->validity.notAfter)); + if (rv != SECSuccess){ + PKIX_ERROR(PKIX_DERDECODETIMECHOICEFAILED); + } + + PKIX_CHECK(pkix_pl_Date_CreateFromPRTime + (prtime, pDate, plContext), + PKIX_DATECREATEFROMPRTIMEFAILED); + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_VerifyCertAndKeyType (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_VerifyCertAndKeyType( + PKIX_PL_Cert *cert, + PKIX_Boolean isChainCert, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *basicConstraints = NULL; + SECCertificateUsage certificateUsage; + SECCertUsage certUsage = 0; + unsigned int requiredKeyUsage; + unsigned int requiredCertType; + unsigned int certType; + SECStatus rv = SECSuccess; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifyCertType"); + PKIX_NULLCHECK_TWO(cert, plContext); + + 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++; } + + /* check key usage and netscape cert type */ + cert_GetCertType(cert->nssCert); + certType = cert->nssCert->nsCertType; + if (isChainCert || + (certUsage != certUsageVerifyCA && certUsage != certUsageAnyCA)) { + rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, isChainCert, + &requiredKeyUsage, + &requiredCertType); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_UNSUPPORTEDCERTUSAGE); + } + } else { + /* use this key usage and cert type for certUsageAnyCA and + * certUsageVerifyCA. */ + requiredKeyUsage = KU_KEY_CERT_SIGN; + requiredCertType = NS_CERT_TYPE_CA; + } + if (CERT_CheckKeyUsage(cert->nssCert, requiredKeyUsage) != SECSuccess) { + PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED); + } + if (!(certType & requiredCertType)) { + PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED); + } +cleanup: + PKIX_DECREF(basicConstraints); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_VerifyKeyUsage (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_VerifyKeyUsage( + PKIX_PL_Cert *cert, + PKIX_UInt32 keyUsage, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + PKIX_UInt32 nssKeyUsage = 0; + SECStatus status; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifyKeyUsage"); + PKIX_NULLCHECK_TWO(cert, cert->nssCert); + + nssCert = cert->nssCert; + + /* if cert doesn't have keyUsage extension, all keyUsages are valid */ + if (!nssCert->keyUsagePresent){ + goto cleanup; + } + + if (keyUsage & PKIX_DIGITAL_SIGNATURE){ + nssKeyUsage = nssKeyUsage | KU_DIGITAL_SIGNATURE; + } + + if (keyUsage & PKIX_NON_REPUDIATION){ + nssKeyUsage = nssKeyUsage | KU_NON_REPUDIATION; + } + + if (keyUsage & PKIX_KEY_ENCIPHERMENT){ + nssKeyUsage = nssKeyUsage | KU_KEY_ENCIPHERMENT; + } + + if (keyUsage & PKIX_DATA_ENCIPHERMENT){ + nssKeyUsage = nssKeyUsage | KU_DATA_ENCIPHERMENT; + } + + if (keyUsage & PKIX_KEY_AGREEMENT){ + nssKeyUsage = nssKeyUsage | KU_KEY_AGREEMENT; + } + + if (keyUsage & PKIX_KEY_CERT_SIGN){ + nssKeyUsage = nssKeyUsage | KU_KEY_CERT_SIGN; + } + + if (keyUsage & PKIX_CRL_SIGN){ + nssKeyUsage = nssKeyUsage | KU_CRL_SIGN; + } + + if (keyUsage & PKIX_ENCIPHER_ONLY){ + nssKeyUsage = nssKeyUsage | 0x01; + } + + if (keyUsage & PKIX_DECIPHER_ONLY){ + /* XXX we should support this once it is fixed in NSS */ + PKIX_ERROR(PKIX_DECIPHERONLYKEYUSAGENOTSUPPORTED); + } + + status = CERT_CheckKeyUsage(nssCert, nssKeyUsage); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED); + } + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetNameConstraints + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetNameConstraints( + PKIX_PL_Cert *cert, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetNameConstraints"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pNameConstraints); + + /* if we don't have a cached copy from before, we create one */ + if (cert->nameConstraints == NULL && !cert->nameConstraintsAbsent) { + + PKIX_OBJECT_LOCK(cert); + + if (cert->nameConstraints == NULL && + !cert->nameConstraintsAbsent) { + + PKIX_CHECK(pkix_pl_CertNameConstraints_Create + (cert->nssCert, &nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEFAILED); + + if (nameConstraints == NULL) { + cert->nameConstraintsAbsent = PKIX_TRUE; + } + + cert->nameConstraints = nameConstraints; + } + + PKIX_OBJECT_UNLOCK(cert); + + } + + PKIX_INCREF(cert->nameConstraints); + + *pNameConstraints = cert->nameConstraints; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_CheckNameConstraints + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_CheckNameConstraints( + PKIX_PL_Cert *cert, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean treatCommonNameAsDNSName, + void *plContext) +{ + PKIX_Boolean checkPass = PKIX_TRUE; + CERTGeneralName *nssSubjectNames = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_CheckNameConstraints"); + PKIX_NULLCHECK_ONE(cert); + + if (nameConstraints != NULL) { + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + /* only check common Name if the usage requires it */ + if (treatCommonNameAsDNSName) { + SECCertificateUsage certificateUsage; + certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage; + if ((certificateUsage != certificateUsageSSLServer) && + (certificateUsage != certificateUsageIPsec)) { + treatCommonNameAsDNSName = PKIX_FALSE; + } + } + + /* This NSS call returns Subject Alt Names. If + * treatCommonNameAsDNSName is true, it also returns the + * Subject Common Name + */ + PKIX_CERT_DEBUG + ("\t\tCalling CERT_GetConstrainedCertificateNames\n"); + nssSubjectNames = CERT_GetConstrainedCertificateNames + (cert->nssCert, arena, treatCommonNameAsDNSName); + + PKIX_CHECK(pkix_pl_CertNameConstraints_CheckNameSpaceNssNames + (nssSubjectNames, + nameConstraints, + &checkPass, + plContext), + PKIX_CERTNAMECONSTRAINTSCHECKNAMESPACENSSNAMESFAILED); + + if (checkPass != PKIX_TRUE) { + PKIX_ERROR(PKIX_CERTFAILEDNAMECONSTRAINTSCHECKING); + } + } + +cleanup: + if (arena){ + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_MergeNameConstraints + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_MergeNameConstraints( + PKIX_PL_CertNameConstraints *firstNC, + PKIX_PL_CertNameConstraints *secondNC, + PKIX_PL_CertNameConstraints **pResultNC, + void *plContext) +{ + PKIX_PL_CertNameConstraints *mergedNC = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_MergeNameConstraints"); + PKIX_NULLCHECK_TWO(firstNC, pResultNC); + + if (secondNC == NULL) { + + PKIX_INCREF(firstNC); + *pResultNC = firstNC; + + goto cleanup; + } + + PKIX_CHECK(pkix_pl_CertNameConstraints_Merge + (firstNC, secondNC, &mergedNC, plContext), + PKIX_CERTNAMECONSTRAINTSMERGEFAILED); + + *pResultNC = mergedNC; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * Find out the state of the NSS trust bits for the requested usage. + * Returns SECFailure if the cert is explicitly distrusted. + * Returns SECSuccess if the cert can be used to form a chain (normal case), + * or it is explicitly trusted. The trusted bool is set to true if it is + * explicitly trusted. + */ +static SECStatus +pkix_pl_Cert_GetTrusted(void *plContext, + PKIX_PL_Cert *cert, + PKIX_Boolean *trusted, + PKIX_Boolean isCA) +{ + SECStatus rv; + CERTCertificate *nssCert = NULL; + SECCertUsage certUsage = 0; + SECCertificateUsage certificateUsage; + SECTrustType trustType; + unsigned int trustFlags; + unsigned int requiredFlags; + CERTCertTrust trust; + + *trusted = PKIX_FALSE; + + /* no key usage information */ + if (plContext == NULL) { + return SECSuccess; + } + + 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++; } + + nssCert = cert->nssCert; + + if (!isCA) { + PRBool prTrusted; + unsigned int failedFlags; + rv = cert_CheckLeafTrust(nssCert, certUsage, + &failedFlags, &prTrusted); + *trusted = (PKIX_Boolean) prTrusted; + return rv; + } + rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, + &trustType); + if (rv != SECSuccess) { + return SECSuccess; + } + + rv = CERT_GetCertTrust(nssCert, &trust); + if (rv != SECSuccess) { + return SECSuccess; + } + trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType); + /* normally trustTypeNone usages accept any of the given trust bits + * being on as acceptable. If any are distrusted (and none are trusted), + * then we will also distrust the cert */ + if ((trustFlags == 0) && (trustType == trustTypeNone)) { + trustFlags = trust.sslFlags | trust.emailFlags | + trust.objectSigningFlags; + } + if ((trustFlags & requiredFlags) == requiredFlags) { + *trusted = PKIX_TRUE; + return SECSuccess; + } + if ((trustFlags & CERTDB_TERMINAL_RECORD) && + ((trustFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED)) == 0)) { + return SECFailure; + } + return SECSuccess; +} + +/* + * FUNCTION: PKIX_PL_Cert_IsCertTrusted + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_IsCertTrusted( + PKIX_PL_Cert *cert, + PKIX_PL_TrustAnchorMode trustAnchorMode, + PKIX_Boolean *pTrusted, + void *plContext) +{ + PKIX_CertStore_CheckTrustCallback trustCallback = NULL; + PKIX_Boolean trusted = PKIX_FALSE; + SECStatus rv = SECFailure; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_IsCertTrusted"); + PKIX_NULLCHECK_TWO(cert, pTrusted); + + /* Call GetTrusted first to see if we are going to distrust the + * certificate */ + rv = pkix_pl_Cert_GetTrusted(plContext, cert, &trusted, PKIX_TRUE); + if (rv != SECSuccess) { + /* Failure means the cert is explicitly distrusted, + * let the next level know not to use it. */ + *pTrusted = PKIX_FALSE; + PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED); + } + + if (trustAnchorMode == PKIX_PL_TrustAnchorMode_Exclusive || + (trustAnchorMode == PKIX_PL_TrustAnchorMode_Additive && + cert->isUserTrustAnchor)) { + /* Use the trust anchor's |trusted| value */ + *pTrusted = cert->isUserTrustAnchor; + goto cleanup; + } + + /* no key usage information or store is not trusted */ + if (plContext == NULL || cert->store == NULL) { + *pTrusted = PKIX_FALSE; + goto cleanup; + } + + PKIX_CHECK(PKIX_CertStore_GetTrustCallback + (cert->store, &trustCallback, plContext), + PKIX_CERTSTOREGETTRUSTCALLBACKFAILED); + + PKIX_CHECK_ONLY_FATAL(trustCallback + (cert->store, cert, &trusted, plContext), + PKIX_CHECKTRUSTCALLBACKFAILED); + + /* allow trust store to override if we can trust the trust + * bits */ + if (PKIX_ERROR_RECEIVED || (trusted == PKIX_FALSE)) { + *pTrusted = PKIX_FALSE; + goto cleanup; + } + + *pTrusted = trusted; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_IsLeafCertTrusted + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_IsLeafCertTrusted( + PKIX_PL_Cert *cert, + PKIX_Boolean *pTrusted, + void *plContext) +{ + SECStatus rv; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_IsLeafCertTrusted"); + PKIX_NULLCHECK_TWO(cert, pTrusted); + + *pTrusted = PKIX_FALSE; + + rv = pkix_pl_Cert_GetTrusted(plContext, cert, pTrusted, PKIX_FALSE); + if (rv != SECSuccess) { + /* Failure means the cert is explicitly distrusted, + * let the next level know not to use it. */ + *pTrusted = PKIX_FALSE; + PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED); + } + +cleanup: + PKIX_RETURN(CERT); +} + +/* FUNCTION: PKIX_PL_Cert_SetAsTrustAnchor */ +PKIX_Error* +PKIX_PL_Cert_SetAsTrustAnchor(PKIX_PL_Cert *cert, + void *plContext) +{ + PKIX_ENTER(CERT, "PKIX_PL_Cert_SetAsTrustAnchor"); + PKIX_NULLCHECK_ONE(cert); + + cert->isUserTrustAnchor = PKIX_TRUE; + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetCacheFlag (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetCacheFlag( + PKIX_PL_Cert *cert, + PKIX_Boolean *pCacheFlag, + void *plContext) +{ + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCacheFlag"); + PKIX_NULLCHECK_TWO(cert, pCacheFlag); + + *pCacheFlag = cert->cacheFlag; + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_SetCacheFlag (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_SetCacheFlag( + PKIX_PL_Cert *cert, + PKIX_Boolean cacheFlag, + void *plContext) +{ + PKIX_ENTER(CERT, "PKIX_PL_Cert_SetCacheFlag"); + PKIX_NULLCHECK_ONE(cert); + + cert->cacheFlag = cacheFlag; + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetTrustCertStore (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetTrustCertStore( + PKIX_PL_Cert *cert, + PKIX_CertStore **pTrustCertStore, + void *plContext) +{ + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetTrustCertStore"); + PKIX_NULLCHECK_TWO(cert, pTrustCertStore); + + PKIX_INCREF(cert->store); + *pTrustCertStore = cert->store; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_SetTrustCertStore (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_SetTrustCertStore( + PKIX_PL_Cert *cert, + PKIX_CertStore *trustCertStore, + void *plContext) +{ + PKIX_ENTER(CERT, "PKIX_PL_Cert_SetTrustCertStore"); + PKIX_NULLCHECK_TWO(cert, trustCertStore); + + PKIX_INCREF(trustCertStore); + cert->store = trustCertStore; + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetAuthorityInfoAccess + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetAuthorityInfoAccess( + PKIX_PL_Cert *cert, + PKIX_List **pAiaList, /* of PKIX_PL_InfoAccess */ + void *plContext) +{ + PKIX_List *aiaList = NULL; /* of PKIX_PL_InfoAccess */ + SECItem *encodedAIA = NULL; + CERTAuthInfoAccess **aia = NULL; + PLArenaPool *arena = NULL; + SECStatus rv; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAuthorityInfoAccess"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAiaList); + + /* if we don't have a cached copy from before, we create one */ + if (cert->authorityInfoAccess == NULL) { + + PKIX_OBJECT_LOCK(cert); + + if (cert->authorityInfoAccess == NULL) { + + PKIX_PL_NSSCALLRV(CERT, encodedAIA, SECITEM_AllocItem, + (NULL, NULL, 0)); + + if (encodedAIA == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension, + (cert->nssCert, + SEC_OID_X509_AUTH_INFO_ACCESS, + encodedAIA)); + + if (rv == SECFailure) { + goto cleanup; + } + + PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena, + (DER_DEFAULT_CHUNKSIZE)); + + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_PL_NSSCALLRV + (CERT, aia, CERT_DecodeAuthInfoAccessExtension, + (arena, encodedAIA)); + + PKIX_CHECK(pkix_pl_InfoAccess_CreateList + (aia, &aiaList, plContext), + PKIX_INFOACCESSCREATELISTFAILED); + + cert->authorityInfoAccess = aiaList; + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->authorityInfoAccess); + + *pAiaList = cert->authorityInfoAccess; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + + if (encodedAIA != NULL) { + SECITEM_FreeItem(encodedAIA, PR_TRUE); + } + + PKIX_RETURN(CERT); +} + +/* XXX Following defines belongs to NSS */ +static const unsigned char siaOIDString[] = {0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x0b}; +#define OI(x) { siDEROID, (unsigned char *)x, sizeof x } + +/* + * FUNCTION: PKIX_PL_Cert_GetSubjectInfoAccess + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetSubjectInfoAccess( + PKIX_PL_Cert *cert, + PKIX_List **pSiaList, /* of PKIX_PL_InfoAccess */ + void *plContext) +{ + PKIX_List *siaList; /* of PKIX_PL_InfoAccess */ + SECItem siaOID = OI(siaOIDString); + SECItem *encodedSubjInfoAccess = NULL; + CERTAuthInfoAccess **subjInfoAccess = NULL; + PLArenaPool *arena = NULL; + SECStatus rv; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectInfoAccess"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSiaList); + + /* XXX + * Codes to deal with SubjectInfoAccess OID should be moved to + * NSS soon. I implemented them here so we don't touch NSS + * source tree, from JP's suggestion. + */ + + /* if we don't have a cached copy from before, we create one */ + if (cert->subjectInfoAccess == NULL) { + + PKIX_OBJECT_LOCK(cert); + + if (cert->subjectInfoAccess == NULL) { + + encodedSubjInfoAccess = SECITEM_AllocItem(NULL, NULL, 0); + if (encodedSubjInfoAccess == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CERT_DEBUG + ("\t\tCalling CERT_FindCertExtensionByOID).\n"); + rv = CERT_FindCertExtensionByOID + (cert->nssCert, &siaOID, encodedSubjInfoAccess); + + if (rv == SECFailure) { + goto cleanup; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + /* XXX + * Decode Subject Information Access - + * since its type is the same as Authority Information + * Access, reuse the call. NSS- change name to avoid + * confusion. + */ + PKIX_CERT_DEBUG + ("\t\tCalling CERT_DecodeAuthInfoAccessExtension).\n"); + subjInfoAccess = CERT_DecodeAuthInfoAccessExtension + (arena, encodedSubjInfoAccess); + + PKIX_CHECK(pkix_pl_InfoAccess_CreateList + (subjInfoAccess, &siaList, plContext), + PKIX_INFOACCESSCREATELISTFAILED); + + cert->subjectInfoAccess = siaList; + + } + + PKIX_OBJECT_UNLOCK(cert); + } + + PKIX_INCREF(cert->subjectInfoAccess); + *pSiaList = cert->subjectInfoAccess; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + + if (encodedSubjInfoAccess != NULL) { + SECITEM_FreeItem(encodedSubjInfoAccess, PR_TRUE); + } + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetCrlDp + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetCrlDp( + PKIX_PL_Cert *cert, + PKIX_List **pDpList, + void *plContext) +{ + PKIX_UInt32 dpIndex = 0; + pkix_pl_CrlDp *dp = NULL; + CERTCrlDistributionPoints *dpoints = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCrlDp"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pDpList); + + /* if we don't have a cached copy from before, we create one */ + if (cert->crldpList == NULL) { + PKIX_OBJECT_LOCK(cert); + if (cert->crldpList != NULL) { + goto cleanup; + } + PKIX_CHECK(PKIX_List_Create(&cert->crldpList, plContext), + PKIX_LISTCREATEFAILED); + dpoints = CERT_FindCRLDistributionPoints(cert->nssCert); + if (!dpoints || !dpoints->distPoints) { + goto cleanup; + } + for (;dpoints->distPoints[dpIndex];dpIndex++) { + PKIX_CHECK( + pkix_pl_CrlDp_Create(dpoints->distPoints[dpIndex], + &cert->nssCert->issuer, + &dp, plContext), + PKIX_CRLDPCREATEFAILED); + /* Create crldp list in reverse order in attempt to get + * to the whole crl first. */ + PKIX_CHECK( + PKIX_List_InsertItem(cert->crldpList, 0, + (PKIX_PL_Object*)dp, + plContext), + PKIX_LISTAPPENDITEMFAILED); + PKIX_DECREF(dp); + } + } +cleanup: + PKIX_INCREF(cert->crldpList); + *pDpList = cert->crldpList; + + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_DECREF(dp); + + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetCERTCertificate + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetCERTCertificate( + PKIX_PL_Cert *cert, + CERTCertificate **pnssCert, + void *plContext) +{ + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetNssCert"); + PKIX_NULLCHECK_TWO(cert, pnssCert); + + *pnssCert = CERT_DupCertificate(cert->nssCert); + + PKIX_RETURN(CERT); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h new file mode 100644 index 0000000000..56fe64228d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h @@ -0,0 +1,107 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_cert.h + * + * Certificate Object Definitions + * + */ + +#ifndef _PKIX_PL_CERT_H +#define _PKIX_PL_CERT_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_CertStruct { + CERTCertificate *nssCert; /* Must be the first field. The + * cert_NSSCertFromPKIXCert function in + * lib/certhigh/certvfypkix.c depends on + * this. */ + CERTGeneralName *nssSubjAltNames; + PLArenaPool *arenaNameConstraints; + PKIX_PL_X500Name *issuer; + PKIX_PL_X500Name *subject; + PKIX_List *subjAltNames; + PKIX_Boolean subjAltNamesAbsent; + PKIX_PL_OID *publicKeyAlgId; + PKIX_PL_PublicKey *publicKey; + PKIX_PL_BigInt *serialNumber; + PKIX_List *critExtOids; + PKIX_PL_ByteArray *subjKeyId; + PKIX_Boolean subjKeyIdAbsent; + PKIX_PL_ByteArray *authKeyId; + PKIX_Boolean authKeyIdAbsent; + PKIX_List *extKeyUsages; + PKIX_Boolean extKeyUsagesAbsent; + PKIX_PL_CertBasicConstraints *certBasicConstraints; + PKIX_Boolean basicConstraintsAbsent; + PKIX_List *certPolicyInfos; + PKIX_Boolean policyInfoAbsent; + PKIX_Boolean policyMappingsAbsent; + PKIX_List *certPolicyMappings; /* List of PKIX_PL_CertPolicyMap */ + PKIX_Boolean policyConstraintsProcessed; + PKIX_Int32 policyConstraintsExplicitPolicySkipCerts; + PKIX_Int32 policyConstraintsInhibitMappingSkipCerts; + PKIX_Boolean inhibitAnyPolicyProcessed; + PKIX_Int32 inhibitAnySkipCerts; + PKIX_PL_CertNameConstraints *nameConstraints; + PKIX_Boolean nameConstraintsAbsent; + PKIX_Boolean cacheFlag; + PKIX_CertStore *store; + PKIX_List *authorityInfoAccess; /* list of PKIX_PL_InfoAccess */ + PKIX_List *subjectInfoAccess; /* list of PKIX_PL_InfoAccess */ + PKIX_Boolean isUserTrustAnchor; + PKIX_List *crldpList; /* list of CRL DPs based on der in nssCert arena. + * Destruction is needed for pkix object and + * not for undelying der as it is a part + * nssCert arena. */ +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_Cert_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_Cert_CreateWithNSSCert( + CERTCertificate *nssCert, + PKIX_PL_Cert **pCert, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_CreateToList( + SECItem *derCertItem, + PKIX_List *certList, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_CheckSubjectAltNameConstraints( + PKIX_PL_Cert *cert, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean matchAll, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_ToString_Helper( + PKIX_PL_Cert *cert, + PKIX_Boolean partialString, + PKIX_PL_String **pString, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_CheckExtendedKeyUsage( + PKIX_PL_Cert *cert, + PKIX_UInt32 requiredExtendedKeyUsages, + PKIX_Boolean *pPass, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CERT_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c new file mode 100644 index 0000000000..a44ac65900 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c @@ -0,0 +1,371 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_certpolicyinfo.c + * + * CertPolicyInfo Type Functions + * + */ + +#include "pkix_pl_certpolicyinfo.h" + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Create + * DESCRIPTION: + * + * Creates a new CertPolicyInfo Object using the OID pointed to by "oid" and + * the List of CertPolicyQualifiers pointed to by "qualifiers", and stores it + * at "pObject". If a non-NULL list is provided, the caller is expected to + * have already set it to be immutable. The caller may provide an empty List, + * but a NULL List is preferable so a user does not need to call + * List_GetLength to get the number of qualifiers. + * + * PARAMETERS + * "oid" + * OID of the desired PolicyInfo ID; must be non-NULL + * "qualifiers" + * List of CertPolicyQualifiers; may be NULL or empty + * "pObject" + * 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_CertPolicyInfo_Create( + PKIX_PL_OID *oid, + PKIX_List *qualifiers, + PKIX_PL_CertPolicyInfo **pObject, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *policyInfo = NULL; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Create"); + + PKIX_NULLCHECK_TWO(oid, pObject); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTPOLICYINFO_TYPE, + sizeof (PKIX_PL_CertPolicyInfo), + (PKIX_PL_Object **)&policyInfo, + plContext), + PKIX_COULDNOTCREATECERTPOLICYINFOOBJECT); + + PKIX_INCREF(oid); + policyInfo->cpID = oid; + + PKIX_INCREF(qualifiers); + policyInfo->policyQualifiers = qualifiers; + + *pObject = policyInfo; + policyInfo = NULL; + +cleanup: + PKIX_DECREF(policyInfo); + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *certPI = NULL; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYINFO); + + certPI = (PKIX_PL_CertPolicyInfo*)object; + + PKIX_DECREF(certPI->cpID); + PKIX_DECREF(certPI->policyQualifiers); + +cleanup: + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *certPI = NULL; + PKIX_PL_String *oidString = NULL; + PKIX_PL_String *listString = NULL; + PKIX_PL_String *format = NULL; + PKIX_PL_String *outString = NULL; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_ToString"); + + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYINFO); + + certPI = (PKIX_PL_CertPolicyInfo *)object; + + PKIX_NULLCHECK_ONE(certPI->cpID); + + PKIX_TOSTRING + (certPI->cpID, + &oidString, + plContext, + PKIX_OIDTOSTRINGFAILED); + + PKIX_TOSTRING + (certPI->policyQualifiers, + &listString, + plContext, + PKIX_LISTTOSTRINGFAILED); + + /* Put them together in the form OID[Qualifiers] */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "%s[%s]", 0, &format, plContext), + PKIX_ERRORINSTRINGCREATE); + + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, plContext, format, oidString, listString), + PKIX_ERRORINSPRINTF); + + *pString = outString; + +cleanup: + + PKIX_DECREF(oidString); + PKIX_DECREF(listString); + PKIX_DECREF(format); + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *certPI = NULL; + PKIX_UInt32 oidHash = 0; + PKIX_UInt32 listHash = 0; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Hashcode"); + + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYINFO); + + certPI = (PKIX_PL_CertPolicyInfo *)object; + + PKIX_NULLCHECK_ONE(certPI->cpID); + + PKIX_HASHCODE + (certPI->cpID, + &oidHash, + plContext, + PKIX_ERRORINOIDHASHCODE); + + PKIX_HASHCODE + (certPI->policyQualifiers, + &listHash, + plContext, + PKIX_ERRORINLISTHASHCODE); + + *pHashcode = (31 * oidHash) + listHash; + +cleanup: + + PKIX_RETURN(CERTPOLICYINFO); +} + + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *firstCPI = NULL; + PKIX_PL_CertPolicyInfo *secondCPI = NULL; + PKIX_UInt32 secondType = 0; + PKIX_Boolean compare = PKIX_FALSE; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertPolicyInfo */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTPOLICYINFO); + + /* + * Since we know firstObject is a CertPolicyInfo, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertPolicyInfo, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTPOLICYINFO_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCPI = (PKIX_PL_CertPolicyInfo *)firstObject; + secondCPI = (PKIX_PL_CertPolicyInfo *)secondObject; + + /* + * Compare the value of the OID components + */ + + PKIX_NULLCHECK_TWO(firstCPI->cpID, secondCPI->cpID); + + PKIX_EQUALS + (firstCPI->cpID, + secondCPI->cpID, + &compare, + plContext, + PKIX_OIDEQUALSFAILED); + + /* + * If the OIDs did not match, we don't need to + * compare the Lists. If the OIDs did match, + * the return value is the value of the + * List comparison. + */ + if (compare) { + PKIX_EQUALS + (firstCPI->policyQualifiers, + secondCPI->policyQualifiers, + &compare, + plContext, + PKIX_LISTEQUALSFAILED); + } + + *pResult = compare; + +cleanup: + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTPOLICYINFO_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_CertPolicyInfo_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_RegisterSelf"); + + entry.description = "CertPolicyInfo"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyInfo); + entry.destructor = pkix_pl_CertPolicyInfo_Destroy; + entry.equalsFunction = pkix_pl_CertPolicyInfo_Equals; + entry.hashcodeFunction = pkix_pl_CertPolicyInfo_Hashcode; + entry.toStringFunction = pkix_pl_CertPolicyInfo_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTPOLICYINFO_TYPE] = entry; + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* --Public-CertPolicyInfo-Functions------------------------- */ + +/* + * FUNCTION: PKIX_PL_CertPolicyInfo_GetPolicyId + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyInfo_GetPolicyId( + PKIX_PL_CertPolicyInfo *policyInfo, + PKIX_PL_OID **pPolicyId, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYINFO, "PKIX_PL_CertPolicyInfo_GetPolicyId"); + + PKIX_NULLCHECK_TWO(policyInfo, pPolicyId); + + PKIX_INCREF(policyInfo->cpID); + + *pPolicyId = policyInfo->cpID; + +cleanup: + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: PKIX_PL_CertPolicyInfo_GetPolQualifiers + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyInfo_GetPolQualifiers( + PKIX_PL_CertPolicyInfo *policyInfo, + PKIX_List **pQuals, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYINFO, "PKIX_PL_CertPolicyInfo_GetPolQualifiers"); + + PKIX_NULLCHECK_TWO(policyInfo, pQuals); + + PKIX_INCREF(policyInfo->policyQualifiers); + + /* + * This List is created in PKIX_PL_Cert_DecodePolicyInfo + * and is set immutable immediately after being created. + */ + *pQuals = policyInfo->policyQualifiers; + +cleanup: + PKIX_RETURN(CERTPOLICYINFO); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h new file mode 100644 index 0000000000..5c324e6cd2 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_certpolicyinfo.h + * + * PolicyInfo Type Definitions + * + */ + +#ifndef _PKIX_PL_POLICYINFO_H +#define _PKIX_PL_POLICYINFO_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure reflects the contents of the policy info extension as + * described in Section 4.2.1.5 of RFC3280. + * + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * PolicyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + * + */ +struct PKIX_PL_CertPolicyInfoStruct { + PKIX_PL_OID *cpID; + PKIX_List *policyQualifiers; /* LIST of PKIX_PL_CertPolicyQualifier */ +}; + +PKIX_Error * +pkix_pl_CertPolicyInfo_Create( + PKIX_PL_OID *oid, + PKIX_List *qualifiers, + PKIX_PL_CertPolicyInfo **pObject, + void *plContext); + +PKIX_Error * +pkix_pl_CertPolicyInfo_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_POLICYINFO_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c new file mode 100644 index 0000000000..08b1ca9df1 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c @@ -0,0 +1,386 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_certpolicymap.c + * + * CertPolicyMap Type Functions + * + */ + +#include "pkix_pl_certpolicymap.h" + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Create + * DESCRIPTION: + * + * Creates a new CertPolicyMap Object pairing the OID given by + * "issuerDomainPolicy" with the OID given by "subjectDomainPolicy", and + * stores the result at "pCertPolicyMap". + * + * PARAMETERS + * "issuerDomainPolicy" + * Address of the OID of the IssuerDomainPolicy. Must be non-NULL. + * "subjectDomainPolicy" + * Address of the OID of the SubjectDomainPolicy. Must be non-NULL. + * "pCertPolicyMap" + * Address where CertPolicyMap 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 CertPolicyMap 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_CertPolicyMap_Create( + PKIX_PL_OID *issuerDomainPolicy, + PKIX_PL_OID *subjectDomainPolicy, + PKIX_PL_CertPolicyMap **pCertPolicyMap, + void *plContext) +{ + PKIX_PL_CertPolicyMap *policyMap = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Create"); + + PKIX_NULLCHECK_THREE + (issuerDomainPolicy, subjectDomainPolicy, pCertPolicyMap); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTPOLICYMAP_TYPE, + sizeof (PKIX_PL_CertPolicyMap), + (PKIX_PL_Object **)&policyMap, + plContext), + PKIX_COULDNOTCREATECERTPOLICYMAPOBJECT); + + PKIX_INCREF(issuerDomainPolicy); + policyMap->issuerDomainPolicy = issuerDomainPolicy; + + PKIX_INCREF(subjectDomainPolicy); + policyMap->subjectDomainPolicy = subjectDomainPolicy; + + *pCertPolicyMap = policyMap; + policyMap = NULL; + +cleanup: + PKIX_DECREF(policyMap); + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertPolicyMap *certMap = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYMAP); + + certMap = (PKIX_PL_CertPolicyMap*)object; + + PKIX_DECREF(certMap->issuerDomainPolicy); + PKIX_DECREF(certMap->subjectDomainPolicy); + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_CertPolicyMap *certMap = NULL; + PKIX_PL_String *format = NULL; + PKIX_PL_String *outString = NULL; + PKIX_PL_String *issuerString = NULL; + PKIX_PL_String *subjectString = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_ToString"); + + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYMAP); + + certMap = (PKIX_PL_CertPolicyMap *)object; + + PKIX_TOSTRING + (certMap->issuerDomainPolicy, + &issuerString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING + (certMap->subjectDomainPolicy, + &subjectString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + /* Put them together in the form issuerPolicy=>subjectPolicy */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "%s=>%s", 0, &format, plContext), + PKIX_ERRORINSTRINGCREATE); + + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, plContext, format, issuerString, subjectString), + PKIX_ERRORINSPRINTF); + + *pString = outString; + +cleanup: + PKIX_DECREF(format); + PKIX_DECREF(issuerString); + PKIX_DECREF(subjectString); + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_UInt32 issuerHash = 0; + PKIX_UInt32 subjectHash = 0; + PKIX_PL_CertPolicyMap *certMap = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Hashcode"); + + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYMAP); + + certMap = (PKIX_PL_CertPolicyMap *)object; + + PKIX_HASHCODE + (certMap->issuerDomainPolicy, + &issuerHash, + plContext, + PKIX_OBJECTHASHCODEFAILED); + + PKIX_HASHCODE + (certMap->subjectDomainPolicy, + &subjectHash, + plContext, + PKIX_OBJECTHASHCODEFAILED); + + *pHashcode = issuerHash*31 + subjectHash; + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertPolicyMap *firstCertMap = NULL; + PKIX_PL_CertPolicyMap *secondCertMap = NULL; + PKIX_UInt32 secondType = 0; + PKIX_Boolean compare = PKIX_FALSE; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertPolicyMap */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTPOLICYMAP); + + /* + * Since we know firstObject is a CertPolicyMap, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertPolicyMap, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTPOLICYMAP_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCertMap = (PKIX_PL_CertPolicyMap *)firstObject; + secondCertMap = (PKIX_PL_CertPolicyMap *)secondObject; + + PKIX_EQUALS + (firstCertMap->issuerDomainPolicy, + secondCertMap->issuerDomainPolicy, + &compare, + plContext, + PKIX_OBJECTEQUALSFAILED); + + if (compare) { + PKIX_EQUALS + (firstCertMap->subjectDomainPolicy, + secondCertMap->subjectDomainPolicy, + &compare, + plContext, + PKIX_OBJECTEQUALSFAILED); + } + + *pResult = compare; + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Duplicate + * (see comments for PKIX_PL_Duplicate_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Duplicate( + PKIX_PL_Object *object, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_PL_CertPolicyMap *original = NULL; + PKIX_PL_CertPolicyMap *copy = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Duplicate"); + + PKIX_NULLCHECK_TWO(object, pNewObject); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTARGUMENTNOTPOLICYMAP); + + original = (PKIX_PL_CertPolicyMap *)object; + + PKIX_CHECK(pkix_pl_CertPolicyMap_Create + (original->issuerDomainPolicy, + original->subjectDomainPolicy, + ©, + plContext), + PKIX_CERTPOLICYMAPCREATEFAILED); + + *pNewObject = (PKIX_PL_Object *)copy; + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTPOLICYMAP_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_CertPolicyMap_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_RegisterSelf"); + + entry.description = "CertPolicyMap"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyMap); + entry.destructor = pkix_pl_CertPolicyMap_Destroy; + entry.equalsFunction = pkix_pl_CertPolicyMap_Equals; + entry.hashcodeFunction = pkix_pl_CertPolicyMap_Hashcode; + entry.toStringFunction = pkix_pl_CertPolicyMap_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_pl_CertPolicyMap_Duplicate; + + systemClasses[PKIX_CERTPOLICYMAP_TYPE] = entry; + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* --Public-CertPolicyMap-Functions------------------------- */ + +/* + * FUNCTION: PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy( + PKIX_PL_CertPolicyMap *policyMapping, + PKIX_PL_OID **pIssuerDomainPolicy, + void *plContext) +{ + PKIX_ENTER + (CERTPOLICYMAP, "PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy"); + + PKIX_NULLCHECK_TWO(policyMapping, pIssuerDomainPolicy); + + PKIX_INCREF(policyMapping->issuerDomainPolicy); + *pIssuerDomainPolicy = policyMapping->issuerDomainPolicy; + +cleanup: + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy( + PKIX_PL_CertPolicyMap *policyMapping, + PKIX_PL_OID **pSubjectDomainPolicy, + void *plContext) +{ + PKIX_ENTER + (CERTPOLICYMAP, "PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy"); + + PKIX_NULLCHECK_TWO(policyMapping, pSubjectDomainPolicy); + + PKIX_INCREF(policyMapping->subjectDomainPolicy); + *pSubjectDomainPolicy = policyMapping->subjectDomainPolicy; + +cleanup: + PKIX_RETURN(CERTPOLICYMAP); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h new file mode 100644 index 0000000000..a03bce2c8c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_certpolicymap.h + * + * CertPolicyMap Object Definitions + * + */ + +#ifndef _PKIX_PL_CERTPOLICYMAP_H +#define _PKIX_PL_CERTPOLICYMAP_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure reflects the contents of the policy mapping extension as + * described in Section 4.2.1.6 of RFC3280. + * + * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { + * issuerDomainPolicy CertPolicyId, + * subjectDomainPolicy CertPolicyId } + * + */ +struct PKIX_PL_CertPolicyMapStruct { + PKIX_PL_OID *issuerDomainPolicy; + PKIX_PL_OID *subjectDomainPolicy; +}; + +PKIX_Error * +pkix_pl_CertPolicyMap_Create( + PKIX_PL_OID *issuerDomainPolicy, + PKIX_PL_OID *subjectDomainPolicy, + PKIX_PL_CertPolicyMap **pObject, + void *plContext); + +PKIX_Error * +pkix_pl_CertPolicyMap_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CERTPOLICYMAP_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c new file mode 100644 index 0000000000..b57623d269 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c @@ -0,0 +1,365 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_certpolicyqualifier.c + * + * CertPolicyQualifier Type Functions + * + */ + +#include "pkix_pl_certpolicyqualifier.h" + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Create + * DESCRIPTION: + * + * Creates a CertPolicyQualifier object with the OID given by "oid" + * and the ByteArray given by "qualifier", and stores it at "pObject". + * + * PARAMETERS + * "oid" + * Address of OID of the desired policyQualifierId; must be non-NULL + * "qualifier" + * Address of ByteArray with the desired value of the qualifier; + * must be non-NULL + * "pObject" + * 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_CertPolicyQualifier_Create( + PKIX_PL_OID *oid, + PKIX_PL_ByteArray *qualifier, + PKIX_PL_CertPolicyQualifier **pObject, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *qual = NULL; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Create"); + + PKIX_NULLCHECK_THREE(oid, qualifier, pObject); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTPOLICYQUALIFIER_TYPE, + sizeof (PKIX_PL_CertPolicyQualifier), + (PKIX_PL_Object **)&qual, + plContext), + PKIX_COULDNOTCREATECERTPOLICYQUALIFIEROBJECT); + + PKIX_INCREF(oid); + qual->policyQualifierId = oid; + + PKIX_INCREF(qualifier); + qual->qualifier = qualifier; + + *pObject = qual; + qual = NULL; + +cleanup: + PKIX_DECREF(qual); + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *certPQ = NULL; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYQUALIFIER); + + certPQ = (PKIX_PL_CertPolicyQualifier*)object; + + PKIX_DECREF(certPQ->policyQualifierId); + PKIX_DECREF(certPQ->qualifier); + +cleanup: + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *certPQ = NULL; + char *asciiFormat = "%s:%s"; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *pqIDString = NULL; + PKIX_PL_String *pqValString = NULL; + PKIX_PL_String *outString = NULL; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_ToString"); + + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYQUALIFIER); + + certPQ = (PKIX_PL_CertPolicyQualifier *)object; + + /* + * The policyQualifierId is required. If there is no qualifier, + * we should have a ByteArray of zero length. + */ + PKIX_NULLCHECK_TWO(certPQ->policyQualifierId, certPQ->qualifier); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_TOSTRING(certPQ->policyQualifierId, &pqIDString, plContext, + PKIX_OIDTOSTRINGFAILED); + + PKIX_CHECK(pkix_pl_ByteArray_ToHexString + (certPQ->qualifier, &pqValString, plContext), + PKIX_BYTEARRAYTOHEXSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, plContext, formatString, pqIDString, pqValString), + PKIX_SPRINTFFAILED); + + *pString = outString; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(pqIDString); + PKIX_DECREF(pqValString); + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *certPQ = NULL; + PKIX_UInt32 cpidHash = 0; + PKIX_UInt32 cpqHash = 0; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYQUALIFIER); + + certPQ = (PKIX_PL_CertPolicyQualifier *)object; + + PKIX_NULLCHECK_TWO(certPQ->policyQualifierId, certPQ->qualifier); + + PKIX_HASHCODE(certPQ->policyQualifierId, &cpidHash, plContext, + PKIX_ERRORINOIDHASHCODE); + + PKIX_HASHCODE(certPQ->qualifier, &cpqHash, plContext, + PKIX_ERRORINBYTEARRAYHASHCODE); + + *pHashcode = cpidHash*31 + cpqHash; + +cleanup: + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *firstCPQ = NULL; + PKIX_PL_CertPolicyQualifier *secondCPQ = NULL; + PKIX_UInt32 secondType = 0; + PKIX_Boolean compare = PKIX_FALSE; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertPolicyQualifier */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTPOLICYQUALIFIER); + + /* + * Since we know firstObject is a CertPolicyQualifier, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertPolicyQualifier, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTPOLICYQUALIFIER_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCPQ = (PKIX_PL_CertPolicyQualifier *)firstObject; + secondCPQ = (PKIX_PL_CertPolicyQualifier *)secondObject; + + /* + * Compare the value of the OID components + */ + + PKIX_NULLCHECK_TWO + (firstCPQ->policyQualifierId, secondCPQ->policyQualifierId); + + PKIX_EQUALS + (firstCPQ->policyQualifierId, + secondCPQ->policyQualifierId, + &compare, + plContext, + PKIX_OIDEQUALSFAILED); + + /* + * If the OIDs did not match, we don't need to + * compare the ByteArrays. If the OIDs did match, + * the return value is the value of the + * ByteArray comparison. + */ + if (compare) { + PKIX_NULLCHECK_TWO(firstCPQ->qualifier, secondCPQ->qualifier); + + PKIX_EQUALS + (firstCPQ->qualifier, + secondCPQ->qualifier, + &compare, + plContext, + PKIX_BYTEARRAYEQUALSFAILED); + } + + *pResult = compare; + +cleanup: + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTPOLICYQUALIFIER_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_CertPolicyQualifier_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTPOLICYQUALIFIER, + "pkix_pl_CertPolicyQualifier_RegisterSelf"); + + entry.description = "CertPolicyQualifier"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyQualifier); + entry.destructor = pkix_pl_CertPolicyQualifier_Destroy; + entry.equalsFunction = pkix_pl_CertPolicyQualifier_Equals; + entry.hashcodeFunction = pkix_pl_CertPolicyQualifier_Hashcode; + entry.toStringFunction = pkix_pl_CertPolicyQualifier_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTPOLICYQUALIFIER_TYPE] = entry; + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* --Public-CertPolicyQualifier-Functions------------------------- */ + +/* + * FUNCTION: PKIX_PL_PolicyQualifier_GetPolicyQualifierId + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PolicyQualifier_GetPolicyQualifierId( + PKIX_PL_CertPolicyQualifier *policyQualifierInfo, + PKIX_PL_OID **pPolicyQualifierId, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYQUALIFIER, + "PKIX_PL_PolicyQualifier_GetPolicyQualifierId"); + + PKIX_NULLCHECK_TWO(policyQualifierInfo, pPolicyQualifierId); + + PKIX_INCREF(policyQualifierInfo->policyQualifierId); + + *pPolicyQualifierId = policyQualifierInfo->policyQualifierId; + +cleanup: + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: PKIX_PL_PolicyQualifier_GetQualifier + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PolicyQualifier_GetQualifier( + PKIX_PL_CertPolicyQualifier *policyQualifierInfo, + PKIX_PL_ByteArray **pQualifier, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYQUALIFIER, "PKIX_PL_PolicyQualifier_GetQualifier"); + + PKIX_NULLCHECK_TWO(policyQualifierInfo, pQualifier); + + PKIX_INCREF(policyQualifierInfo->qualifier); + + *pQualifier = policyQualifierInfo->qualifier; + +cleanup: + PKIX_RETURN(CERTPOLICYQUALIFIER); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h new file mode 100644 index 0000000000..4c6c8a21ba --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_certpolicyqualifier.h + * + * PolicyQualifier Type Definitions + * + */ + +#ifndef _PKIX_PL_POLICYQUALIFIER_H +#define _PKIX_PL_POLICYQUALIFIER_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure reflects the contents of the policy qualifier extension as + * described in Section 4.2.1.5 of RFC3280. + * + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * + * PolicyQualifierId ::= + * OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice) + * + */ +struct PKIX_PL_CertPolicyQualifierStruct { + PKIX_PL_OID *policyQualifierId; + PKIX_PL_ByteArray *qualifier; +}; + +PKIX_Error * +pkix_pl_CertPolicyQualifier_Create( + PKIX_PL_OID *oid, + PKIX_PL_ByteArray *qualifierArray, + PKIX_PL_CertPolicyQualifier **pObject, + void *plContext); + +PKIX_Error * +pkix_pl_CertPolicyQualifier_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_POLICYQUALIFIER_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c new file mode 100644 index 0000000000..b83db357ac --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c @@ -0,0 +1,1068 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_crl.c + * + * CRL Function Definitions + * + */ + +#include "pkix_pl_crl.h" +#include "certxutl.h" + +extern PKIX_PL_HashTable *cachedCrlSigTable; + +/* --Private-CRL-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_CRL_GetVersion + * DESCRIPTION: + * + * Retrieves the version of the CRL pointed to by "crl" and stores it at + * "pVersion". The version number will either be 0 or 1 (corresponding to + * v1 or v2, respectively). + * + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * PARAMETERS: + * "crl" + * Address of CRL whose version is to be stored. Must be non-NULL. + * "pVersion" + * Address where a version 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 CRL 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_CRL_GetVersion( + PKIX_PL_CRL *crl, + PKIX_UInt32 *pVersion, + void *plContext) +{ + PKIX_UInt32 myVersion; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetVersion"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pVersion); + + PKIX_NULLCHECK_ONE(crl->nssSignedCrl->crl.version.data); + + myVersion = *(crl->nssSignedCrl->crl.version.data); + + if (myVersion > 1) { + PKIX_ERROR(PKIX_VERSIONVALUEMUSTBEV1ORV2); + } + + *pVersion = myVersion; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_GetCRLNumber (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetCRLNumber( + PKIX_PL_CRL *crl, + PKIX_PL_BigInt **pCrlNumber, + void *plContext) +{ + PKIX_PL_BigInt *crlNumber = NULL; + SECItem nssCrlNumber; + PLArenaPool *arena = NULL; + SECStatus status; + PKIX_UInt32 length = 0; + char *bytes = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCRLNumber"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlNumber); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + if (!crl->crlNumberAbsent && crl->crlNumber == NULL) { + + PKIX_OBJECT_LOCK(crl); + + if (!crl->crlNumberAbsent && crl->crlNumber == NULL) { + + nssCrlNumber.type = 0; + nssCrlNumber.len = 0; + nssCrlNumber.data = NULL; + + PKIX_CRL_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CRL_DEBUG("\t\tCalling CERT_FindCRLNumberExten\n"); + status = CERT_FindCRLNumberExten + (arena, &crl->nssSignedCrl->crl, &nssCrlNumber); + + if (status == SECSuccess) { + /* Get data in bytes then convert to bigint */ + length = nssCrlNumber.len; + bytes = (char *)nssCrlNumber.data; + + PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes + (bytes, length, &crlNumber, plContext), + PKIX_BIGINTCREATEWITHBYTESFAILED); + + /* arena release does the job + PKIX_CRL_DEBUG("\t\tCalling SECITEM_FreeItem\n"); + SECITEM_FreeItem(&nssCrlNumber, PKIX_FALSE); + */ + crl->crlNumber = crlNumber; + + } else { + + crl->crlNumberAbsent = PKIX_TRUE; + } + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->crlNumber); + + *pCrlNumber = crl->crlNumber; + +cleanup: + + if (arena){ + PKIX_CRL_DEBUG("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_GetSignatureAlgId + * + * DESCRIPTION: + * Retrieves a pointer to the OID that represents the signature algorithm of + * the CRL pointed to by "crl" and stores it at "pSignatureAlgId". + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * PARAMETERS: + * "crl" + * Address of CRL whose signature algorithm OID is to be stored. + * Must be non-NULL. + * "pSignatureAlgId" + * 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 CRL 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_CRL_GetSignatureAlgId( + PKIX_PL_CRL *crl, + PKIX_PL_OID **pSignatureAlgId, + void *plContext) +{ + PKIX_PL_OID *signatureAlgId = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetSignatureAlgId"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pSignatureAlgId); + + /* if we don't have a cached copy from before, we create one */ + if (crl->signatureAlgId == NULL){ + PKIX_OBJECT_LOCK(crl); + if (crl->signatureAlgId == NULL){ + CERTCrl *nssCrl = &(crl->nssSignedCrl->crl); + SECAlgorithmID *algorithm = &nssCrl->signatureAlg; + SECItem *algBytes = &algorithm->algorithm; + + if (!algBytes->data || !algBytes->len) { + PKIX_ERROR(PKIX_OIDBYTESLENGTH0); + } + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (algBytes, &signatureAlgId, plContext), + PKIX_OIDCREATEFAILED); + + /* save a cached copy in case it is asked for again */ + crl->signatureAlgId = signatureAlgId; + signatureAlgId = NULL; + } + PKIX_OBJECT_UNLOCK(crl); + } + PKIX_INCREF(crl->signatureAlgId); + *pSignatureAlgId = crl->signatureAlgId; +cleanup: + PKIX_DECREF(signatureAlgId); + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_GetCRLEntries + * DESCRIPTION: + * + * Retrieves a pointer to the List of CRLEntries found in the CRL pointed to + * by "crl" and stores it at "pCRLEntries". If there are no CRLEntries, + * this functions stores NULL at "pCRLEntries". + * + * PARAMETERS: + * "crl" + * Address of CRL whose CRL Entries are to be retrieved. Must be non-NULL. + * "pCRLEntries" + * 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 CRL 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_CRL_GetCRLEntries( + PKIX_PL_CRL *crl, + PKIX_List **pCrlEntries, + void *plContext) +{ + PKIX_List *entryList = NULL; + CERTCrl *nssCrl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetCRLEntries"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlEntries); + + /* if we don't have a cached copy from before, we create one */ + if (crl->crlEntryList == NULL) { + + PKIX_OBJECT_LOCK(crl); + + if (crl->crlEntryList == NULL){ + + nssCrl = &(crl->nssSignedCrl->crl); + + PKIX_CHECK(pkix_pl_CRLEntry_Create + (nssCrl->entries, &entryList, plContext), + PKIX_CRLENTRYCREATEFAILED); + + PKIX_CHECK(PKIX_List_SetImmutable + (entryList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + crl->crlEntryList = entryList; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->crlEntryList); + + *pCrlEntries = crl->crlEntryList; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL*)object; + + PKIX_CRL_DEBUG("\t\tCalling CERT_DestroyCrl\n"); + if (crl->nssSignedCrl) { + CERT_DestroyCrl(crl->nssSignedCrl); + } + if (crl->adoptedDerCrl) { + SECITEM_FreeItem(crl->adoptedDerCrl, PR_TRUE); + } + crl->nssSignedCrl = NULL; + crl->adoptedDerCrl = NULL; + crl->crlNumberAbsent = PKIX_FALSE; + + PKIX_DECREF(crl->issuer); + PKIX_DECREF(crl->signatureAlgId); + PKIX_DECREF(crl->crlNumber); + PKIX_DECREF(crl->crlEntryList); + PKIX_DECREF(crl->critExtOids); + if (crl->derGenName) { + SECITEM_FreeItem(crl->derGenName, PR_TRUE); + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the CRL pointed + * to by "crl" and stores it at "pString". + * + * PARAMETERS + * "crl" + * Address of CRL whose string representation is desired. + * Must be non-NULL. + * "pString" + * 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 CRL 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_CRL_ToString_Helper( + PKIX_PL_CRL *crl, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiFormat = NULL; + PKIX_UInt32 crlVersion = 0; + PKIX_PL_X500Name *crlIssuer = NULL; + PKIX_PL_OID *nssSignatureAlgId = NULL; + PKIX_PL_BigInt *crlNumber = NULL; + PKIX_List *crlEntryList = NULL; + PKIX_List *critExtOIDs = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *crlIssuerString = NULL; + PKIX_PL_String *lastUpdateString = NULL; + PKIX_PL_String *nextUpdateString = NULL; + PKIX_PL_String *nssSignatureAlgIdString = NULL; + PKIX_PL_String *crlNumberString = NULL; + PKIX_PL_String *crlEntryListString = NULL; + PKIX_PL_String *critExtOIDsString = NULL; + PKIX_PL_String *crlString = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_ToString_Helper"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pString); + + asciiFormat = + "[\n" + "\tVersion: v%d\n" + "\tIssuer: %s\n" + "\tUpdate: [Last: %s\n" + "\t Next: %s]\n" + "\tSignatureAlgId: %s\n" + "\tCRL Number : %s\n" + "\n" + "\tEntry List: %s\n" + "\n" + "\tCritExtOIDs: %s\n" + "]\n"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + /* Version */ + PKIX_CHECK(pkix_pl_CRL_GetVersion(crl, &crlVersion, plContext), + PKIX_CRLGETVERSIONFAILED); + + /* Issuer */ + PKIX_CHECK(PKIX_PL_CRL_GetIssuer(crl, &crlIssuer, plContext), + PKIX_CRLGETISSUERFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)crlIssuer, &crlIssuerString, plContext), + PKIX_X500NAMETOSTRINGFAILED); + + /* This update - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crl->nssSignedCrl->crl.lastUpdate), + &lastUpdateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* Next update - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crl->nssSignedCrl->crl.nextUpdate), + &nextUpdateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* Signature Algorithm Id */ + PKIX_CHECK(pkix_pl_CRL_GetSignatureAlgId + (crl, &nssSignatureAlgId, plContext), + PKIX_CRLGETSIGNATUREALGIDFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)nssSignatureAlgId, + &nssSignatureAlgIdString, + plContext), + PKIX_OIDTOSTRINGFAILED); + + /* CRL Number */ + PKIX_CHECK(PKIX_PL_CRL_GetCRLNumber + (crl, &crlNumber, plContext), + PKIX_CRLGETCRLNUMBERFAILED); + + PKIX_TOSTRING(crlNumber, &crlNumberString, plContext, + PKIX_BIGINTTOSTRINGFAILED); + + /* CRL Entries */ + PKIX_CHECK(pkix_pl_CRL_GetCRLEntries(crl, &crlEntryList, plContext), + PKIX_CRLGETCRLENTRIESFAILED); + + PKIX_TOSTRING(crlEntryList, &crlEntryListString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* CriticalExtensionOIDs */ + PKIX_CHECK(PKIX_PL_CRL_GetCriticalExtensionOIDs + (crl, &critExtOIDs, plContext), + PKIX_CRLGETCRITICALEXTENSIONOIDSFAILED); + + PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&crlString, + plContext, + formatString, + crlVersion + 1, + crlIssuerString, + lastUpdateString, + nextUpdateString, + nssSignatureAlgIdString, + crlNumberString, + crlEntryListString, + critExtOIDsString), + PKIX_SPRINTFFAILED); + + *pString = crlString; + +cleanup: + + PKIX_DECREF(crlIssuer); + PKIX_DECREF(nssSignatureAlgId); + PKIX_DECREF(crlNumber); + PKIX_DECREF(crlEntryList); + PKIX_DECREF(critExtOIDs); + PKIX_DECREF(crlIssuerString); + PKIX_DECREF(lastUpdateString); + PKIX_DECREF(nextUpdateString); + PKIX_DECREF(nssSignatureAlgIdString); + PKIX_DECREF(crlNumberString); + PKIX_DECREF(crlEntryListString); + PKIX_DECREF(critExtOIDsString); + PKIX_DECREF(formatString); + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *crlString = NULL; + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL *) object; + + PKIX_CHECK(pkix_pl_CRL_ToString_Helper(crl, &crlString, plContext), + PKIX_CRLTOSTRINGHELPERFAILED); + + *pString = crlString; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + PKIX_UInt32 certHash; + SECItem *crlDer = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL *)object; + if (crl->adoptedDerCrl) { + crlDer = crl->adoptedDerCrl; + } else if (crl->nssSignedCrl && crl->nssSignedCrl->derCrl) { + crlDer = crl->nssSignedCrl->derCrl; + } + if (!crlDer || !crlDer->data) { + PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER); + } + + PKIX_CHECK(pkix_hash(crlDer->data, crlDer->len, + &certHash, plContext), + PKIX_ERRORINHASH); + + *pHashcode = certHash; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CRL *firstCrl = NULL; + PKIX_PL_CRL *secondCrl = NULL; + SECItem *crlDerOne = NULL, *crlDerTwo = NULL; + PKIX_UInt32 secondType; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CRL */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRL_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCRL); + + firstCrl = (PKIX_PL_CRL *)firstObject; + secondCrl = (PKIX_PL_CRL *)secondObject; + + /* + * Since we know firstObject is a CRL, if both references are + * identical, they must be equal + */ + if (firstCrl == secondCrl){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondCrl isn't a CRL, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + ((PKIX_PL_Object *)secondCrl, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CRL_TYPE) goto cleanup; + + if (firstCrl->adoptedDerCrl) { + crlDerOne = firstCrl->adoptedDerCrl; + } else if (firstCrl->nssSignedCrl && firstCrl->nssSignedCrl->derCrl) { + crlDerOne = firstCrl->nssSignedCrl->derCrl; + } + + if (secondCrl->adoptedDerCrl) { + crlDerTwo = secondCrl->adoptedDerCrl; + } else if (secondCrl->nssSignedCrl && secondCrl->nssSignedCrl->derCrl) { + crlDerTwo = secondCrl->nssSignedCrl->derCrl; + } + + if (SECITEM_CompareItem(crlDerOne, crlDerTwo) == SECEqual) { + *pResult = PKIX_TRUE; + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_CRL_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_CRL_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_CRL_TYPE]; + + PKIX_ENTER(CRL, "pkix_pl_CRL_RegisterSelf"); + + entry->description = "CRL"; + entry->typeObjectSize = sizeof(PKIX_PL_CRL); + entry->destructor = pkix_pl_CRL_Destroy; + entry->equalsFunction = pkix_pl_CRL_Equals; + entry->hashcodeFunction = pkix_pl_CRL_Hashcode; + entry->toStringFunction = pkix_pl_CRL_ToString; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_VerifyUpdateTime (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_VerifyUpdateTime( + PKIX_PL_CRL *crl, + PKIX_PL_Date *date, + PKIX_Boolean *pResult, + void *plContext) +{ + PRTime timeToCheck; + PRTime nextUpdate; + PRTime lastUpdate; + SECStatus status; + CERTCrl *nssCrl = NULL; + SECItem *nextUpdateDer = NULL; + PKIX_Boolean haveNextUpdate = PR_FALSE; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifyUpdateTime"); + PKIX_NULLCHECK_FOUR(crl, crl->nssSignedCrl, date, pResult); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + nssCrl = &(crl->nssSignedCrl->crl); + timeToCheck = date->nssTime; + + /* nextUpdate can be NULL. Checking before using it */ + nextUpdateDer = &nssCrl->nextUpdate; + if (nextUpdateDer->data && nextUpdateDer->len) { + haveNextUpdate = PR_TRUE; + status = DER_DecodeTimeChoice(&nextUpdate, nextUpdateDer); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORNEXTUPDATEFAILED); + } + } + + status = DER_DecodeTimeChoice(&lastUpdate, &(nssCrl->lastUpdate)); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORLASTUPDATEFAILED); + } + + if (!haveNextUpdate || nextUpdate < timeToCheck) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + if (lastUpdate <= timeToCheck) { + *pResult = PKIX_TRUE; + } else { + *pResult = PKIX_FALSE; + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_CreateWithSignedCRL + * DESCRIPTION: + * + * Creates a new CRL using the CERTSignedCrl pointed to by "nssSignedCrl" + * and stores it at "pCRL". If the decoding of the CERTSignedCrl fails, + * a PKIX_Error is returned. + * + * PARAMETERS: + * "nssSignedCrl" + * Address of CERTSignedCrl. Must be non-NULL. + * "adoptedDerCrl" + * SECItem ponter that if not NULL is indicating that memory used + * for der should be adopted by crl that is about to be created. + * "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 CRL 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_CRL_CreateWithSignedCRL( + CERTSignedCrl *nssSignedCrl, + SECItem *adoptedDerCrl, + SECItem *derGenName, + PKIX_PL_CRL **pCrl, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_CreateWithSignedCRL"); + PKIX_NULLCHECK_ONE(pCrl); + + /* create a PKIX_PL_CRL object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CRL_TYPE, + sizeof (PKIX_PL_CRL), + (PKIX_PL_Object **)&crl, + plContext), + PKIX_COULDNOTCREATECRLOBJECT); + + /* populate the nssSignedCrl field */ + crl->nssSignedCrl = nssSignedCrl; + crl->adoptedDerCrl = adoptedDerCrl; + crl->issuer = NULL; + crl->signatureAlgId = NULL; + crl->crlNumber = NULL; + crl->crlNumberAbsent = PKIX_FALSE; + crl->crlEntryList = NULL; + crl->critExtOids = NULL; + if (derGenName) { + crl->derGenName = + SECITEM_DupItem(derGenName); + if (!crl->derGenName) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + } + + *pCrl = crl; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(crl); + } + + PKIX_RETURN(CRL); +} + +/* --Public-CRL-Functions------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_CRL_Create (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_Create( + PKIX_PL_ByteArray *byteArray, + PKIX_PL_CRL **pCrl, + void *plContext) +{ + CERTSignedCrl *nssSignedCrl = NULL; + SECItem derItem, *derCrl = NULL; + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_Create"); + PKIX_NULLCHECK_TWO(byteArray, pCrl); + + if (byteArray->length == 0){ + PKIX_ERROR(PKIX_ZEROLENGTHBYTEARRAYFORCRLENCODING); + } + derItem.type = siBuffer; + derItem.data = byteArray->array; + derItem.len = byteArray->length; + derCrl = SECITEM_DupItem(&derItem); + if (!derCrl) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + nssSignedCrl = + CERT_DecodeDERCrlWithFlags(NULL, derCrl, SEC_CRL_TYPE, + CRL_DECODE_DONT_COPY_DER | + CRL_DECODE_SKIP_ENTRIES); + if (!nssSignedCrl) { + PKIX_ERROR(PKIX_CERTDECODEDERCRLFAILED); + } + PKIX_CHECK( + pkix_pl_CRL_CreateWithSignedCRL(nssSignedCrl, derCrl, NULL, + &crl, plContext), + PKIX_CRLCREATEWITHSIGNEDCRLFAILED); + nssSignedCrl = NULL; + derCrl = NULL; + *pCrl = crl; + +cleanup: + if (derCrl) { + SECITEM_FreeItem(derCrl, PR_TRUE); + } + if (nssSignedCrl) { + SEC_DestroyCrl(nssSignedCrl); + } + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_GetIssuer (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetIssuer( + PKIX_PL_CRL *crl, + PKIX_PL_X500Name **pCRLIssuer, + void *plContext) +{ + PKIX_PL_String *crlString = NULL; + PKIX_PL_X500Name *issuer = NULL; + SECItem *derIssuerName = NULL; + CERTName *issuerName = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetIssuer"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCRLIssuer); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + /* if we don't have a cached copy from before, we create one */ + if (crl->issuer == NULL){ + + PKIX_OBJECT_LOCK(crl); + + if (crl->issuer == NULL) { + + issuerName = &crl->nssSignedCrl->crl.name; + derIssuerName = &crl->nssSignedCrl->crl.derName; + + PKIX_CHECK( + PKIX_PL_X500Name_CreateFromCERTName(derIssuerName, + issuerName, + &issuer, + plContext), + PKIX_X500NAMECREATEFROMCERTNAMEFAILED); + + /* save a cached copy in case it is asked for again */ + crl->issuer = issuer; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->issuer); + + *pCRLIssuer = crl->issuer; + +cleanup: + + PKIX_DECREF(crlString); + + PKIX_RETURN(CRL); +} + + +/* + * FUNCTION: PKIX_PL_CRL_GetCriticalExtensionOIDs + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetCriticalExtensionOIDs( + PKIX_PL_CRL *crl, + PKIX_List **pExtensions, /* list of PKIX_PL_OID */ + void *plContext) +{ + PKIX_List *oidsList = NULL; + CERTCertExtension **extensions = NULL; + CERTCrl *nssSignedCrl = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCriticalExtensionOIDs"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pExtensions); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + /* if we don't have a cached copy from before, we create one */ + if (crl->critExtOids == NULL) { + + PKIX_OBJECT_LOCK(crl); + + nssSignedCrl = &(crl->nssSignedCrl->crl); + extensions = nssSignedCrl->extensions; + + if (crl->critExtOids == NULL) { + + PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs + (extensions, &oidsList, plContext), + PKIX_GETCRITICALEXTENSIONOIDSFAILED); + + crl->critExtOids = oidsList; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + /* We should return a copy of the List since this list changes */ + PKIX_DUPLICATE(crl->critExtOids, pExtensions, plContext, + PKIX_OBJECTDUPLICATELISTFAILED); + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_VerifySignature (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_VerifySignature( + PKIX_PL_CRL *crl, + PKIX_PL_PublicKey *pubKey, + void *plContext) +{ + PKIX_PL_CRL *cachedCrl = NULL; + PKIX_Error *verifySig = NULL; + PKIX_Error *cachedSig = NULL; + PKIX_Boolean crlEqual = PKIX_FALSE; + PKIX_Boolean crlInHash= PKIX_FALSE; + CERTSignedCrl *nssSignedCrl = NULL; + SECKEYPublicKey *nssPubKey = NULL; + CERTSignedData *tbsCrl = NULL; + void* wincx = NULL; + SECStatus status; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifySignature"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pubKey); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + verifySig = PKIX_PL_HashTable_Lookup + (cachedCrlSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object **) &cachedCrl, + plContext); + + if (cachedCrl != NULL && verifySig == NULL) { + /* Cached Signature Table lookup succeed */ + PKIX_EQUALS(crl, cachedCrl, &crlEqual, plContext, + PKIX_OBJECTEQUALSFAILED); + if (crlEqual == PKIX_TRUE) { + goto cleanup; + } + /* Different PubKey may hash to same value, skip add */ + crlInHash = PKIX_TRUE; + } + + nssSignedCrl = crl->nssSignedCrl; + tbsCrl = &nssSignedCrl->signatureWrap; + + PKIX_CRL_DEBUG("\t\tCalling SECKEY_ExtractPublicKey\n"); + nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI); + if (!nssPubKey){ + PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED); + } + + PKIX_CHECK(pkix_pl_NssContext_GetWincx + ((PKIX_PL_NssContext *)plContext, &wincx), + PKIX_NSSCONTEXTGETWINCXFAILED); + + PKIX_CRL_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey\n"); + status = CERT_VerifySignedDataWithPublicKey(tbsCrl, nssPubKey, wincx); + + if (status != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY); + } + + if (crlInHash == PKIX_FALSE) { + cachedSig = PKIX_PL_HashTable_Add + (cachedCrlSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object *) crl, + plContext); + + if (cachedSig != NULL) { + PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n"); + } + } + +cleanup: + + if (nssPubKey){ + PKIX_CRL_DEBUG("\t\tCalling SECKEY_DestroyPublicKey\n"); + SECKEY_DestroyPublicKey(nssPubKey); + nssPubKey = NULL; + } + + PKIX_DECREF(cachedCrl); + PKIX_DECREF(verifySig); + PKIX_DECREF(cachedSig); + + PKIX_RETURN(CRL); +} + +PKIX_Error* +PKIX_PL_CRL_ReleaseDerCrl(PKIX_PL_CRL *crl, + SECItem **derCrl, + void *plContext) +{ + PKIX_ENTER(CRL, "PKIX_PL_CRL_ReleaseDerCrl"); + *derCrl = crl->adoptedDerCrl; + crl->adoptedDerCrl = NULL; + + PKIX_RETURN(CRL); +} + +PKIX_Error* +PKIX_PL_CRL_AdoptDerCrl(PKIX_PL_CRL *crl, + SECItem *derCrl, + void *plContext) +{ + PKIX_ENTER(CRL, "PKIX_PL_CRL_AquireDerCrl"); + if (crl->adoptedDerCrl) { + PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER); + } + crl->adoptedDerCrl = derCrl; +cleanup: + PKIX_RETURN(CRL); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h new file mode 100644 index 0000000000..a45059ea0d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_crl.h + * + * CRL Object Type Definitions + * + */ + +#ifndef _PKIX_PL_CRL_H +#define _PKIX_PL_CRL_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_CRLStruct { + CERTSignedCrl *nssSignedCrl; + PKIX_PL_X500Name *issuer; + PKIX_PL_OID *signatureAlgId; + PKIX_PL_BigInt *crlNumber; + PKIX_Boolean crlNumberAbsent; + PKIX_List *crlEntryList; /* list of PKIX_PL_CRLEntry */ + PKIX_List *critExtOids; + SECItem *adoptedDerCrl; + SECItem *derGenName; /* der of general name which was used + * to download the crl. */ +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_CRL_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_CRL_CreateWithSignedCRL(CERTSignedCrl *nssSignedCrl, + SECItem *derCrl, + SECItem *derGenName, + PKIX_PL_CRL **pCrl, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CRL_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c new file mode 100644 index 0000000000..4f29de2849 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c @@ -0,0 +1,151 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_crldp.c + * + * Crl DP Object Functions + * + */ + +#include "pkix_pl_crldp.h" + +static PKIX_Error * +pkix_pl_CrlDp_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_pl_CrlDp *crldp = NULL; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a default CRL checker state */ + PKIX_CHECK( + pkix_CheckType(object, PKIX_CRLDP_TYPE, plContext), + PKIX_OBJECTNOTCRLCHECKER); + + crldp = (pkix_pl_CrlDp *)object; + if (crldp->distPointType == relativeDistinguishedName) { + CERT_DestroyName(crldp->name.issuerName); + crldp->name.issuerName = NULL; + } + crldp->nssdp = NULL; +cleanup: + PKIX_RETURN(CRLCHECKER); +} + +/* + * FUNCTION: pkix_pl_CrlDp_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_CRLDP_TYPE and its related functions + * with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * + * 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_CrlDp_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry* entry = &systemClasses[PKIX_CRLDP_TYPE]; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf"); + + entry->description = "CrlDistPoint"; + entry->typeObjectSize = sizeof(pkix_pl_CrlDp); + entry->destructor = pkix_pl_CrlDp_Destroy; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(CRLCHECKER); +} + + + +PKIX_Error * +pkix_pl_CrlDp_Create( + const CRLDistributionPoint *dp, + const CERTName *certIssuerName, + pkix_pl_CrlDp **pPkixDP, + void *plContext) +{ + PLArenaPool *rdnArena = NULL; + CERTName *issuerNameCopy = NULL; + pkix_pl_CrlDp *dpl = NULL; + + /* Need to save the following info to update crl cache: + * - reasons if partitioned(but can not return revocation check + * success if not all crl are downloaded) + * - issuer name if different from issuer of the cert + * - url to upload a crl if needed. + * */ + PKIX_ENTER(CRLDP, "pkix_pl_CrlDp_Create"); + PKIX_NULLCHECK_ONE(dp); + + PKIX_CHECK( + PKIX_PL_Object_Alloc(PKIX_CRLDP_TYPE, + sizeof (pkix_pl_CrlDp), + (PKIX_PL_Object **)&dpl, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + dpl->nssdp = dp; + dpl->isPartitionedByReasonCode = PKIX_FALSE; + if (dp->reasons.data) { + dpl->isPartitionedByReasonCode = PKIX_TRUE; + } + if (dp->distPointType == generalName) { + dpl->distPointType = generalName; + dpl->name.fullName = dp->distPoint.fullName; + } else { + SECStatus rv; + const CERTName *issuerName = NULL; + const CERTRDN *relName = &dp->distPoint.relativeName; + + if (dp->crlIssuer) { + if (dp->crlIssuer->l.next) { + /* Violate RFC 5280: in this case crlIssuer + * should have only one name and should be + * a distinguish name. */ + PKIX_ERROR(PKIX_NOTCONFORMINGCRLDP); + } + issuerName = &dp->crlIssuer->name.directoryName; + } else { + issuerName = certIssuerName; + } + rdnArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!rdnArena) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + issuerNameCopy = (CERTName *)PORT_ArenaZNew(rdnArena, CERTName); + if (!issuerNameCopy) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + rv = CERT_CopyName(rdnArena, issuerNameCopy, (CERTName*)issuerName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + rv = CERT_AddRDN(issuerNameCopy, (CERTRDN*)relName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + dpl->distPointType = relativeDistinguishedName; + dpl->name.issuerName = issuerNameCopy; + rdnArena = NULL; + } + *pPkixDP = dpl; + dpl = NULL; + +cleanup: + if (rdnArena) { + PORT_FreeArena(rdnArena, PR_FALSE); + } + PKIX_DECREF(dpl); + + PKIX_RETURN(CRLDP); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h new file mode 100644 index 0000000000..49cd9d2cdf --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_crldp.h + * + * Crp DP Object Definitions + * + */ +#include "pkix_pl_common.h" + +#ifndef _PKIX_PL_CRLDP_H +#define _PKIX_PL_CRLDP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* CRLDP object can not be used without holding a reference + * to the pkix certificate they belong to. The memory for dp der + * object is allocated on nssCert certificate - a member of + * PKIX_PL_Cert struct. */ +typedef struct pkix_pl_CrlDpStruct { + /* reference to decoded crldp that allocated on nssCert arena. */ + const CRLDistributionPoint *nssdp; + DistributionPointTypes distPointType; + union { + CERTGeneralName *fullName; + /* if dp is a relative name, the issuerName is a merged value + * of crlIssuer and a relative name. Must be destroyed by CrlDp + * destructor. */ + CERTName *issuerName; + } name; + PKIX_Boolean isPartitionedByReasonCode; +} pkix_pl_CrlDp; + + +PKIX_Error * +pkix_pl_CrlDp_RegisterSelf(void *plContext); + +/* Parses CRLDistributionPoint structure and creaetes + * pkix_pl_CrlDp object. */ +PKIX_Error * +pkix_pl_CrlDp_Create(const CRLDistributionPoint *dp, + const CERTName *certIssuerName, + pkix_pl_CrlDp **pPkixDP, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CRLDP_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c new file mode 100644 index 0000000000..e2b3e02688 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c @@ -0,0 +1,880 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_crlentry.c + * + * CRLENTRY Function Definitions + * + */ + +#include "pkix_pl_crlentry.h" + +/* --Private-CRLEntry-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_CRLEntry_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CRLEntry *crlEntry = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext), + PKIX_OBJECTNOTCRLENTRY); + + crlEntry = (PKIX_PL_CRLEntry*)object; + + /* crlEntry->nssCrlEntry is freed by NSS when freeing CRL */ + crlEntry->userReasonCode = 0; + crlEntry->userReasonCodeAbsent = PKIX_FALSE; + crlEntry->nssCrlEntry = NULL; + PKIX_DECREF(crlEntry->serialNumber); + PKIX_DECREF(crlEntry->critExtOids); + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_ToString_Helper + * + * DESCRIPTION: + * Helper function that creates a string representation of the CRLEntry + * pointed to by "crlEntry" and stores it at "pString". + * + * PARAMETERS + * "crlEntry" + * Address of CRLEntry whose string representation is desired. + * Must be non-NULL. + * "pString" + * 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 CRLEntry 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_CRLEntry_ToString_Helper( + PKIX_PL_CRLEntry *crlEntry, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiFormat = NULL; + PKIX_List *critExtOIDs = NULL; + PKIX_PL_String *crlEntryString = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *crlSerialNumberString = NULL; + PKIX_PL_String *crlRevocationDateString = NULL; + PKIX_PL_String *critExtOIDsString = NULL; + PKIX_Int32 reasonCode = 0; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_ToString_Helper"); + PKIX_NULLCHECK_FOUR + (crlEntry, + crlEntry->serialNumber, + crlEntry->nssCrlEntry, + pString); + + asciiFormat = + "\n\t[\n" + "\tSerialNumber: %s\n" + "\tReasonCode: %d\n" + "\tRevocationDate: %s\n" + "\tCritExtOIDs: %s\n" + "\t]\n\t"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + /* SerialNumber */ + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)crlEntry->serialNumber, + &crlSerialNumberString, + plContext), + PKIX_BIGINTTOSTRINGHELPERFAILED); + + /* RevocationDate - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crlEntry->nssCrlEntry->revocationDate), + &crlRevocationDateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* CriticalExtensionOIDs */ + PKIX_CHECK(PKIX_PL_CRLEntry_GetCriticalExtensionOIDs + (crlEntry, &critExtOIDs, plContext), + PKIX_CRLENTRYGETCRITICALEXTENSIONOIDSFAILED); + + PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* Revocation Reason Code */ + PKIX_CHECK(PKIX_PL_CRLEntry_GetCRLEntryReasonCode + (crlEntry, &reasonCode, plContext), + PKIX_CRLENTRYGETCRLENTRYREASONCODEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&crlEntryString, + plContext, + formatString, + crlSerialNumberString, + reasonCode, + crlRevocationDateString, + critExtOIDsString), + PKIX_SPRINTFFAILED); + + *pString = crlEntryString; + +cleanup: + + PKIX_DECREF(critExtOIDs); + PKIX_DECREF(crlSerialNumberString); + PKIX_DECREF(crlRevocationDateString); + PKIX_DECREF(critExtOIDsString); + PKIX_DECREF(formatString); + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *crlEntryString = NULL; + PKIX_PL_CRLEntry *crlEntry = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext), + PKIX_OBJECTNOTCRLENTRY); + + crlEntry = (PKIX_PL_CRLEntry *) object; + + PKIX_CHECK(pkix_pl_CRLEntry_ToString_Helper + (crlEntry, &crlEntryString, plContext), + PKIX_CRLENTRYTOSTRINGHELPERFAILED); + + *pString = crlEntryString; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Extensions_Hashcode + * DESCRIPTION: + * + * For each CRL Entry extension stored at NSS structure CERTCertExtension, + * get its derbyte data and do the hash. + * + * PARAMETERS + * "extensions" + * Address of arrray of CERTCertExtension whose hash value is desired. + * Must be non-NULL. + * "pHashValue" + * Address where the final hash value is returned. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditional Thread Safe + * Though the value of extensions once created is not supposed to change, + * it may be de-allocated while we are accessing it. But since we are + * validating the object, it is unlikely we or someone is de-allocating + * at the moment. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OID 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_CRLEntry_Extensions_Hashcode( + CERTCertExtension **extensions, + PKIX_UInt32 *pHashValue, + void *plContext) +{ + CERTCertExtension *extension = NULL; + PLArenaPool *arena = NULL; + PKIX_UInt32 extHash = 0; + PKIX_UInt32 hashValue = 0; + SECItem *derBytes = NULL; + SECItem *resultSecItem = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Extensions_Hashcode"); + PKIX_NULLCHECK_TWO(extensions, pHashValue); + + if (extensions) { + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + while (*extensions) { + + extension = *extensions++; + + PKIX_NULLCHECK_ONE(extension); + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n"); + derBytes = PORT_ArenaZNew(arena, SECItem); + if (derBytes == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PKIX_CRLENTRY_DEBUG + ("\t\tCalling SEC_ASN1EncodeItem\n"); + resultSecItem = SEC_ASN1EncodeItem + (arena, + derBytes, + extension, + CERT_CertExtensionTemplate); + + if (resultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + PKIX_CHECK(pkix_hash + (derBytes->data, + derBytes->len, + &extHash, + plContext), + PKIX_HASHFAILED); + + hashValue += (extHash << 7); + + } + } + + *pHashValue = hashValue; + +cleanup: + + if (arena){ + /* Note that freeing the arena also frees derBytes */ + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_FreeArena\n"); + PORT_FreeArena(arena, PR_FALSE); + arena = NULL; + } + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + SECItem *nssDate = NULL; + PKIX_PL_CRLEntry *crlEntry = NULL; + PKIX_UInt32 crlEntryHash; + PKIX_UInt32 hashValue; + PKIX_Int32 reasonCode = 0; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext), + PKIX_OBJECTNOTCRLENTRY); + + crlEntry = (PKIX_PL_CRLEntry *)object; + + PKIX_NULLCHECK_ONE(crlEntry->nssCrlEntry); + nssDate = &(crlEntry->nssCrlEntry->revocationDate); + + PKIX_NULLCHECK_ONE(nssDate->data); + + PKIX_CHECK(pkix_hash + ((const unsigned char *)nssDate->data, + nssDate->len, + &crlEntryHash, + plContext), + PKIX_ERRORGETTINGHASHCODE); + + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *)crlEntry->serialNumber, + &hashValue, + plContext), + PKIX_OBJECTHASHCODEFAILED); + + crlEntryHash += (hashValue << 7); + + hashValue = 0; + + if (crlEntry->nssCrlEntry->extensions) { + + PKIX_CHECK(pkix_pl_CRLEntry_Extensions_Hashcode + (crlEntry->nssCrlEntry->extensions, &hashValue, plContext), + PKIX_CRLENTRYEXTENSIONSHASHCODEFAILED); + } + + crlEntryHash += (hashValue << 7); + + PKIX_CHECK(PKIX_PL_CRLEntry_GetCRLEntryReasonCode + (crlEntry, &reasonCode, plContext), + PKIX_CRLENTRYGETCRLENTRYREASONCODEFAILED); + + crlEntryHash += (reasonCode + 777) << 3; + + *pHashcode = crlEntryHash; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLENTRY_Extensions_Equals + * DESCRIPTION: + * + * Compare each extension's DERbyte data in "firstExtensions" with extension + * in "secondExtensions" in sequential order and store the result in + * "pResult". + * + * PARAMETERS + * "firstExtensions" + * Address of first NSS structure CERTCertExtension to be compared. + * Must be non-NULL. + * "secondExtensions" + * Address of second NSS structure CERTCertExtension to be compared. + * Must be non-NULL. + * "pResult" + * Address where the comparison result is returned. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * Though the value of extensions once created is not supposed to change, + * it may be de-allocated while we are accessing it. But since we are + * validating the object, it is unlikely we or someone is de-allocating + * at the moment. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OID 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_CRLEntry_Extensions_Equals( + CERTCertExtension **extensions1, + CERTCertExtension **extensions2, + PKIX_Boolean *pResult, + void *plContext) +{ + CERTCertExtension **firstExtensions; + CERTCertExtension **secondExtensions; + CERTCertExtension *firstExtension = NULL; + CERTCertExtension *secondExtension = NULL; + PLArenaPool *arena = NULL; + PKIX_Boolean cmpResult = PKIX_FALSE; + SECItem *firstDerBytes = NULL; + SECItem *secondDerBytes = NULL; + SECItem *firstResultSecItem = NULL; + SECItem *secondResultSecItem = NULL; + PKIX_UInt32 firstNumExt = 0; + PKIX_UInt32 secondNumExt = 0; + SECComparison secResult; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Extensions_Equals"); + PKIX_NULLCHECK_THREE(extensions1, extensions2, pResult); + + firstExtensions = extensions1; + secondExtensions = extensions2; + + if (firstExtensions) { + while (*firstExtensions) { + firstExtension = *firstExtensions++; + firstNumExt++; + } + } + + if (secondExtensions) { + while (*secondExtensions) { + secondExtension = *secondExtensions++; + secondNumExt++; + } + } + + if (firstNumExt != secondNumExt) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + if (firstNumExt == 0 && secondNumExt == 0) { + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* now have equal number, but non-zero extension items to compare */ + + firstExtensions = extensions1; + secondExtensions = extensions2; + + cmpResult = PKIX_TRUE; + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE*2); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + while (firstNumExt--) { + + firstExtension = *firstExtensions++; + secondExtension = *secondExtensions++; + + PKIX_NULLCHECK_TWO(firstExtension, secondExtension); + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n"); + firstDerBytes = PORT_ArenaZNew(arena, SECItem); + if (firstDerBytes == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n"); + secondDerBytes = PORT_ArenaZNew(arena, SECItem); + if (secondDerBytes == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PKIX_CRLENTRY_DEBUG + ("\t\tCalling SEC_ASN1EncodeItem\n"); + firstResultSecItem = SEC_ASN1EncodeItem + (arena, + firstDerBytes, + firstExtension, + CERT_CertExtensionTemplate); + + if (firstResultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + PKIX_CRLENTRY_DEBUG + ("\t\tCalling SEC_ASN1EncodeItem\n"); + secondResultSecItem = SEC_ASN1EncodeItem + (arena, + secondDerBytes, + secondExtension, + CERT_CertExtensionTemplate); + + if (secondResultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n"); + secResult = SECITEM_CompareItem + (firstResultSecItem, secondResultSecItem); + + if (secResult != SECEqual) { + cmpResult = PKIX_FALSE; + break; + } + + } + + *pResult = cmpResult; + +cleanup: + + if (arena){ + /* Note that freeing the arena also frees derBytes */ + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_FreeArena\n"); + PORT_FreeArena(arena, PR_FALSE); + arena = NULL; + } + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CRLEntry *firstCrlEntry = NULL; + PKIX_PL_CRLEntry *secondCrlEntry = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult = PKIX_FALSE; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CRLEntry */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRLENTRY_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCRLENTRY); + + firstCrlEntry = (PKIX_PL_CRLEntry *)firstObject; + secondCrlEntry = (PKIX_PL_CRLEntry *)secondObject; + + PKIX_NULLCHECK_TWO + (firstCrlEntry->nssCrlEntry, secondCrlEntry->nssCrlEntry); + + /* + * Since we know firstObject is a CRLEntry, if both references are + * identical, they must be equal + */ + if (firstCrlEntry == secondCrlEntry){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondCrlEntry isn't a CRL Entry, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + ((PKIX_PL_Object *)secondCrlEntry, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CRLENTRY_TYPE) goto cleanup; + + /* Compare userSerialNumber */ + PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n"); + if (SECITEM_CompareItem( + &(((PKIX_PL_CRLEntry *)firstCrlEntry)->nssCrlEntry->serialNumber), + &(((PKIX_PL_CRLEntry *)secondCrlEntry)->nssCrlEntry->serialNumber)) + != SECEqual) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + /* Compare revocationDate */ + PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n"); + if (SECITEM_CompareItem + (&(((PKIX_PL_CRLEntry *)firstCrlEntry)->nssCrlEntry-> + revocationDate), + &(((PKIX_PL_CRLEntry *)secondCrlEntry)->nssCrlEntry-> + revocationDate)) + != SECEqual) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + /* Compare Critical Extension List */ + PKIX_CHECK(pkix_pl_CRLEntry_Extensions_Equals + (firstCrlEntry->nssCrlEntry->extensions, + secondCrlEntry->nssCrlEntry->extensions, + &cmpResult, + plContext), + PKIX_CRLENTRYEXTENSIONSEQUALSFAILED); + + if (cmpResult != PKIX_TRUE){ + *pResult = PKIX_FALSE; + goto cleanup; + } + + cmpResult = (firstCrlEntry->userReasonCode == + secondCrlEntry->userReasonCode); + + *pResult = cmpResult; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CRLEntry_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_CRLEntry_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_RegisterSelf"); + + entry.description = "CRLEntry"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CRLEntry); + entry.destructor = pkix_pl_CRLEntry_Destroy; + entry.equalsFunction = pkix_pl_CRLEntry_Equals; + entry.hashcodeFunction = pkix_pl_CRLEntry_Hashcode; + entry.toStringFunction = pkix_pl_CRLEntry_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CRLENTRY_TYPE] = entry; + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_CreateEntry + * DESCRIPTION: + * + * Creates a new CRLEntry using the CertCrlEntry pointed to by "nssCrlEntry" + * and stores it at "pCrlEntry". Once created, a CRLEntry is immutable. + * + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * + * PARAMETERS: + * "nssCrlEntry" + * Address of CERTCrlEntry representing an NSS CRL entry. + * Must be non-NULL. + * "pCrlEntry" + * 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 CRLEntry 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_CRLEntry_CreateEntry( + CERTCrlEntry *nssCrlEntry, /* entry data to be created from */ + PKIX_PL_CRLEntry **pCrlEntry, + void *plContext) +{ + PKIX_PL_CRLEntry *crlEntry = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_CreateEntry"); + PKIX_NULLCHECK_TWO(nssCrlEntry, pCrlEntry); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CRLENTRY_TYPE, + sizeof (PKIX_PL_CRLEntry), + (PKIX_PL_Object **)&crlEntry, + plContext), + PKIX_COULDNOTCREATECRLENTRYOBJECT); + + crlEntry->nssCrlEntry = nssCrlEntry; + crlEntry->serialNumber = NULL; + crlEntry->critExtOids = NULL; + crlEntry->userReasonCode = 0; + crlEntry->userReasonCodeAbsent = PKIX_FALSE; + + *pCrlEntry = crlEntry; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Create + * DESCRIPTION: + * + * Creates a List of CRLEntries using the array of CERTCrlEntries pointed to + * by "nssCrlEntries" and stores it at "pCrlEntryList". If "nssCrlEntries" is + * NULL, this function stores an empty List at "pCrlEntryList". + * } + * PARAMETERS: + * "nssCrlEntries" + * Address of array of CERTCrlEntries representing NSS CRL entries. + * Can be NULL if CRL has no NSS CRL entries. + * "pCrlEntryList" + * 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 CRLEntry 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_CRLEntry_Create( + CERTCrlEntry **nssCrlEntries, /* head of entry list */ + PKIX_List **pCrlEntryList, + void *plContext) +{ + PKIX_List *entryList = NULL; + PKIX_PL_CRLEntry *crlEntry = NULL; + CERTCrlEntry **entries = NULL; + SECItem serialNumberItem; + PKIX_PL_BigInt *serialNumber; + char *bytes = NULL; + PKIX_UInt32 length; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Create"); + PKIX_NULLCHECK_ONE(pCrlEntryList); + + entries = nssCrlEntries; + + PKIX_CHECK(PKIX_List_Create(&entryList, plContext), + PKIX_LISTCREATEFAILED); + + if (entries) { + while (*entries){ + PKIX_CHECK(pkix_pl_CRLEntry_CreateEntry + (*entries, &crlEntry, plContext), + PKIX_COULDNOTCREATECRLENTRYOBJECT); + + /* Get Serial Number */ + serialNumberItem = (*entries)->serialNumber; + length = serialNumberItem.len; + bytes = (char *)serialNumberItem.data; + + PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes + (bytes, length, &serialNumber, plContext), + PKIX_BIGINTCREATEWITHBYTESFAILED); + + crlEntry->serialNumber = serialNumber; + crlEntry->nssCrlEntry = *entries; + + PKIX_CHECK(PKIX_List_AppendItem + (entryList, (PKIX_PL_Object *)crlEntry, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(crlEntry); + + entries++; + } + } + + *pCrlEntryList = entryList; + +cleanup: + PKIX_DECREF(crlEntry); + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(entryList); + } + + PKIX_RETURN(CRLENTRY); +} + +/* --Public-CRLENTRY-Functions------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_CRLEntry_GetCRLEntryReasonCode + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRLEntry_GetCRLEntryReasonCode ( + PKIX_PL_CRLEntry *crlEntry, + PKIX_Int32 *pReason, + void *plContext) +{ + SECStatus status; + CERTCRLEntryReasonCode nssReasonCode; + + PKIX_ENTER(CRLENTRY, "PKIX_PL_CRLEntry_GetCRLEntryReasonCode"); + PKIX_NULLCHECK_TWO(crlEntry, pReason); + + if (!crlEntry->userReasonCodeAbsent && crlEntry->userReasonCode == 0) { + + PKIX_OBJECT_LOCK(crlEntry); + + if (!crlEntry->userReasonCodeAbsent && + crlEntry->userReasonCode == 0) { + + /* reason code has not been cached in */ + PKIX_CRLENTRY_DEBUG("\t\tCERT_FindCRLEntryReasonExten.\n"); + status = CERT_FindCRLEntryReasonExten + (crlEntry->nssCrlEntry, &nssReasonCode); + + if (status == SECSuccess) { + crlEntry->userReasonCode = (PKIX_Int32) nssReasonCode; + } else { + crlEntry->userReasonCodeAbsent = PKIX_TRUE; + } + } + + PKIX_OBJECT_UNLOCK(crlEntry); + + } + + *pReason = crlEntry->userReasonCode; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: PKIX_PL_CRLEntry_GetCriticalExtensionOIDs + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRLEntry_GetCriticalExtensionOIDs ( + PKIX_PL_CRLEntry *crlEntry, + PKIX_List **pList, /* list of PKIX_PL_OID */ + void *plContext) +{ + PKIX_List *oidsList = NULL; + CERTCertExtension **extensions; + + PKIX_ENTER(CRLENTRY, "PKIX_PL_CRLEntry_GetCriticalExtensionOIDs"); + PKIX_NULLCHECK_THREE(crlEntry, crlEntry->nssCrlEntry, pList); + + /* if we don't have a cached copy from before, we create one */ + if (crlEntry->critExtOids == NULL) { + + PKIX_OBJECT_LOCK(crlEntry); + + if (crlEntry->critExtOids == NULL) { + + extensions = crlEntry->nssCrlEntry->extensions; + + PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs + (extensions, &oidsList, plContext), + PKIX_GETCRITICALEXTENSIONOIDSFAILED); + + crlEntry->critExtOids = oidsList; + } + + PKIX_OBJECT_UNLOCK(crlEntry); + + } + + /* We should return a copy of the List since this list changes */ + PKIX_DUPLICATE(crlEntry->critExtOids, pList, plContext, + PKIX_OBJECTDUPLICATELISTFAILED); + +cleanup: + + PKIX_RETURN(CRLENTRY); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h new file mode 100644 index 0000000000..9cdb6bc927 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_crlentry.h + * + * CRL Entry Type Object Definitions + * + */ + +#ifndef _PKIX_PL_CRLENTRY_H +#define _PKIX_PL_CRLENTRY_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PKIX_PL_CRL_REASONCODE_NOTSET (-1) + +struct PKIX_PL_CRLEntryStruct { + CERTCrlEntry *nssCrlEntry; + PKIX_PL_BigInt *serialNumber; + PKIX_List *critExtOids; + PKIX_Int32 userReasonCode; + PKIX_Boolean userReasonCodeAbsent; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_CRLEntry_RegisterSelf(void *plContext); + +/* following functions are called by CRL only hence not public */ + +PKIX_Error * +pkix_pl_CRLEntry_Create( + CERTCrlEntry **nssCrlEntry, /* head of entry list */ + PKIX_List **pCrlEntryList, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CRLENTRY_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c new file mode 100644 index 0000000000..4b5016bd01 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c @@ -0,0 +1,466 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_date.c + * + * Date Object Definitions + * + */ + +#include "pkix_pl_date.h" + +/* --Private-Date-Functions------------------------------------- */ +/* + * FUNCTION: pkix_pl_Date_GetPRTime + * DESCRIPTION: + * + * Translates into a PRTime the Date embodied by the Date object pointed to + * by "date", and stores it at "pPRTime". + * + * PARAMETERS + * "date" + * Address of Date whose PRTime representation is desired. Must be + * non-NULL. + * "pPRTime" + * Address where PRTime value 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 Date 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_Date_GetPRTime( + PKIX_PL_Date *date, + PRTime *pPRTime, + void *plContext) +{ + PKIX_ENTER(DATE, "PKIX_PL_Date_GetPRTime"); + PKIX_NULLCHECK_TWO(date, pPRTime); + + *pPRTime = date->nssTime; + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_CreateFromPRTime + * DESCRIPTION: + * + * Creates a new Date from the PRTime whose value is "prtime", and stores the + * result at "pDate". + * + * PARAMETERS + * "prtime" + * The PRTime value to be embodied in the new Date object. + * "pDate" + * 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 Date 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_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + + PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); + PKIX_NULLCHECK_ONE(pDate); + + /* create a PKIX_PL_Date object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_DATE_TYPE, + sizeof (PKIX_PL_Date), + (PKIX_PL_Object **)&date, + plContext), + PKIX_COULDNOTCREATEOBJECT); + /* populate the nssTime field */ + date->nssTime = prtime; + *pDate = date; +cleanup: + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the SECItem pointed + * to by "nssTime" (which represents a date) and stores it at "pString". + * + * PARAMETERS + * "nssTime" + * Address of SECItem whose string representation is desired. + * Must be non-NULL. + * "pString" + * 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 Date 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_Date_ToString_Helper( + SECItem *nssTime, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiDate = NULL; + + PKIX_ENTER(DATE, "pkix_pl_Date_ToString_Helper"); + PKIX_NULLCHECK_TWO(nssTime, pString); + + switch (nssTime->type) { + case siUTCTime: + PKIX_PL_NSSCALLRV + (DATE, asciiDate, DER_UTCDayToAscii, (nssTime)); + if (!asciiDate){ + PKIX_ERROR(PKIX_DERUTCTIMETOASCIIFAILED); + } + break; + case siGeneralizedTime: + /* + * we don't currently have any way to create GeneralizedTime. + * this code is only here so that it will be in place when + * we do have the capability to create GeneralizedTime. + */ + PKIX_PL_NSSCALLRV + (DATE, asciiDate, DER_GeneralizedDayToAscii, (nssTime)); + if (!asciiDate){ + PKIX_ERROR(PKIX_DERGENERALIZEDDAYTOASCIIFAILED); + } + break; + default: + PKIX_ERROR(PKIX_UNRECOGNIZEDTIMETYPE); + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, asciiDate, 0, pString, plContext), + PKIX_STRINGCREATEFAILED); + +cleanup: + PR_Free(asciiDate); + + PKIX_RETURN(DATE); +} + + +/* + * FUNCTION: pkix_pl_Date_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_ENTER(DATE, "pkix_pl_Date_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), + PKIX_OBJECTNOTDATE); +cleanup: + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + SECItem nssTime = {siBuffer, NULL, 0}; + SECStatus rv; + + PKIX_ENTER(DATE, "pkix_pl_Date_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), + PKIX_OBJECTNOTDATE); + + date = (PKIX_PL_Date *)object; + rv = DER_EncodeTimeChoice(NULL, &nssTime, date->nssTime); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_DERENCODETIMECHOICEFAILED); + } + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&nssTime, pString, plContext), + PKIX_DATETOSTRINGHELPERFAILED); +cleanup: + if (nssTime.data) { + SECITEM_FreeItem(&nssTime, PR_FALSE); + } + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + PKIX_UInt32 dateHash; + + PKIX_ENTER(DATE, "pkix_pl_Date_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), + PKIX_OBJECTNOTDATE); + + date = (PKIX_PL_Date *)object; + + PKIX_CHECK(pkix_hash + ((const unsigned char *)&date->nssTime, + sizeof(date->nssTime), + &dateHash, + plContext), + PKIX_HASHFAILED); + + *pHashcode = dateHash; + +cleanup: + + PKIX_RETURN(DATE); + +} + +/* + * FUNCTION: pkix_pl_Date_Comparator + * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Comparator( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PRTime firstTime; + PRTime secondTime; + SECComparison cmpResult; + + PKIX_ENTER(DATE, "pkix_pl_Date_Comparator"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + PKIX_CHECK(pkix_CheckTypes + (firstObject, secondObject, PKIX_DATE_TYPE, plContext), + PKIX_ARGUMENTSNOTDATES); + + firstTime = ((PKIX_PL_Date *)firstObject)->nssTime; + secondTime = ((PKIX_PL_Date *)secondObject)->nssTime; + + if (firstTime == secondTime) + cmpResult = SECEqual; + else if (firstTime < secondTime) + cmpResult = SECLessThan; + else + cmpResult = SECGreaterThan; + + *pResult = cmpResult; + +cleanup: + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_ENTER(DATE, "pkix_pl_Date_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a Date */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_DATE_TYPE, plContext), + PKIX_FIRSTOBJECTNOTDATE); + + /* + * Since we know firstObject is a Date, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + *pResult = PKIX_FALSE; + pkixErrorResult = + pkix_pl_Date_Comparator(firstObject, secondObject, + pResult, plContext); + if (pkixErrorResult) { + PKIX_DECREF(pkixErrorResult); + } + +cleanup: + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_RegisterSelf + * DESCRIPTION: + * Registers PKIX_DATE_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_Date_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry* entry = &systemClasses[PKIX_DATE_TYPE]; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf"); + + entry->description = "Date"; + entry->typeObjectSize = sizeof(PKIX_PL_Date); + entry->destructor = pkix_pl_Date_Destroy; + entry->equalsFunction = pkix_pl_Date_Equals; + entry->hashcodeFunction = pkix_pl_Date_Hashcode; + entry->toStringFunction = pkix_pl_Date_ToString; + entry->comparator = pkix_pl_Date_Comparator; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(DATE); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_Date_Create_UTCTime (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Date_Create_UTCTime( + PKIX_PL_String *stringRep, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + char *asciiString = NULL; + PKIX_UInt32 escAsciiLength; + SECStatus rv; + PRTime time; + + PKIX_ENTER(DATE, "PKIX_PL_Date_Create_UTCTime"); + PKIX_NULLCHECK_ONE(pDate); + + if (stringRep == NULL){ + PKIX_DATE_DEBUG("\t\tCalling PR_Now).\n"); + time = PR_Now(); + } else { + /* convert the input PKIX_PL_String to PKIX_ESCASCII */ + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stringRep, + PKIX_ESCASCII, + (void **)&asciiString, + &escAsciiLength, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_DATE_DEBUG("\t\tCalling DER_AsciiToTime).\n"); + /* DER_AsciiToTime only supports UTCTime (2-digit years) */ + rv = DER_AsciiToTime(&time, asciiString); + if (rv != SECSuccess){ + PKIX_ERROR(PKIX_DERASCIITOTIMEFAILED); + } + } + + /* create a PKIX_PL_Date object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_DATE_TYPE, + sizeof (PKIX_PL_Date), + (PKIX_PL_Object **)&date, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* populate the nssTime field */ + date->nssTime = time; + *pDate = date; + +cleanup: + PKIX_FREE(asciiString); + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: PKIX_PL_Date_Create_CurrentOffBySeconds + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Date_Create_CurrentOffBySeconds( + PKIX_Int32 secondsOffset, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + PRTime time; + + PKIX_ENTER(DATE, "PKIX_PL_Date_Create_CurrentOffBySeconds"); + PKIX_NULLCHECK_ONE(pDate); + + time = PR_Now() + PR_SecondsToInterval(secondsOffset); + /* create a PKIX_PL_Date object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_DATE_TYPE, + sizeof (PKIX_PL_Date), + (PKIX_PL_Object **)&date, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* populate the nssTime field */ + date->nssTime = time; + *pDate = date; + +cleanup: + PKIX_RETURN(DATE); +} + +PKIX_Error * +PKIX_PL_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); + PKIX_CHECK( + pkix_pl_Date_CreateFromPRTime(prtime, pDate, plContext), + PKIX_DATECREATEFROMPRTIMEFAILED); + +cleanup: + PKIX_RETURN(DATE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h new file mode 100644 index 0000000000..415597580a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h @@ -0,0 +1,55 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_date.h + * + * Date Object Definitions + * + */ + +#ifndef _PKIX_PL_DATE_H +#define _PKIX_PL_DATE_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_DateStruct{ + PRTime nssTime; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_Date_ToString_Helper( + SECItem *nssTime, + PKIX_PL_String **pString, + void *plContext); + +PKIX_Error *pkix_pl_Date_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_Date_GetPRTime( + PKIX_PL_Date *date, + PRTime *pPRTime, + void *plContext); + +PKIX_Error * +pkix_pl_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext); + +PKIX_Error * +PKIX_PL_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_DATE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c new file mode 100644 index 0000000000..9e9a74c783 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c @@ -0,0 +1,873 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_generalname.c + * + * GeneralName Object Definitions + * + */ + +#include "pkix_pl_generalname.h" + +/* --Private-GeneralName-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_GeneralName_GetNssGeneralName + * DESCRIPTION: + * + * Retrieves the NSS representation of the PKIX_PL_GeneralName pointed by + * "genName" and stores it at "pNssGenName". The NSS data type CERTGeneralName + * is stored in this object when the object was created. + * + * PARAMETERS: + * "genName" + * Address of PKIX_PL_GeneralName. Must be non-NULL. + * "pNssGenName" + * Address where CERTGeneralName 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 GeneralName 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_GeneralName_GetNssGeneralName( + PKIX_PL_GeneralName *genName, + CERTGeneralName **pNssGenName, + void *plContext) +{ + CERTGeneralName *nssGenName = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_GetNssGeneralName"); + PKIX_NULLCHECK_THREE(genName, pNssGenName, genName->nssGeneralNameList); + + nssGenName = genName->nssGeneralNameList->name; + + *pNssGenName = nssGenName; + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_OtherName_Create + * DESCRIPTION: + * + * Creates new OtherName which represents the CERTGeneralName pointed to by + * "nssAltName" and stores it at "pOtherName". + * + * PARAMETERS: + * "nssAltName" + * Address of CERTGeneralName. Must be non-NULL. + * "pOtherName" + * 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 GeneralName 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_OtherName_Create( + CERTGeneralName *nssAltName, + OtherName **pOtherName, + void *plContext) +{ + OtherName *otherName = NULL; + SECItem secItemName; + SECItem secItemOID; + SECStatus rv; + + PKIX_ENTER(GENERALNAME, "pkix_pl_OtherName_Create"); + PKIX_NULLCHECK_TWO(nssAltName, pOtherName); + + PKIX_CHECK(PKIX_PL_Malloc + (sizeof (OtherName), (void **)&otherName, plContext), + PKIX_MALLOCFAILED); + + /* make a copy of the name field */ + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CopyItem).\n"); + rv = SECITEM_CopyItem + (NULL, &otherName->name, &nssAltName->name.OthName.name); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + /* make a copy of the oid field */ + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CopyItem).\n"); + rv = SECITEM_CopyItem + (NULL, &otherName->oid, &nssAltName->name.OthName.oid); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + *pOtherName = otherName; + +cleanup: + + if (otherName && PKIX_ERROR_RECEIVED){ + secItemName = otherName->name; + secItemOID = otherName->oid; + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemName, PR_FALSE); + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemOID, PR_FALSE); + + PKIX_FREE(otherName); + otherName = NULL; + } + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_DirectoryName_Create + * DESCRIPTION: + * + * Creates a new X500Name which represents the directoryName component of the + * CERTGeneralName pointed to by "nssAltName" and stores it at "pX500Name". + * + * PARAMETERS: + * "nssAltName" + * Address of CERTGeneralName. Must be non-NULL. + * "pX500Name" + * 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 GeneralName 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_DirectoryName_Create( + CERTGeneralName *nssAltName, + PKIX_PL_X500Name **pX500Name, + void *plContext) +{ + PKIX_PL_X500Name *pkixDN = NULL; + CERTName *dirName = NULL; + PKIX_PL_String *pkixDNString = NULL; + char *utf8String = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_DirectoryName_Create"); + PKIX_NULLCHECK_TWO(nssAltName, pX500Name); + + dirName = &nssAltName->name.directoryName; + + PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName(NULL, dirName, + &pkixDN, plContext), + PKIX_X500NAMECREATEFROMCERTNAMEFAILED); + + *pX500Name = pkixDN; + +cleanup: + + PR_Free(utf8String); + PKIX_DECREF(pkixDNString); + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_Create + * DESCRIPTION: + * + * Creates new GeneralName which represents the CERTGeneralName pointed to by + * "nssAltName" and stores it at "pGenName". + * + * PARAMETERS: + * "nssAltName" + * Address of CERTGeneralName. Must be non-NULL. + * "pGenName" + * 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 GeneralName 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_GeneralName_Create( + CERTGeneralName *nssAltName, + PKIX_PL_GeneralName **pGenName, + void *plContext) +{ + PKIX_PL_GeneralName *genName = NULL; + PKIX_PL_X500Name *pkixDN = NULL; + PKIX_PL_OID *pkixOID = NULL; + OtherName *otherName = NULL; + CERTGeneralNameList *nssGenNameList = NULL; + CERTGeneralNameType nameType; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Create"); + PKIX_NULLCHECK_TWO(nssAltName, pGenName); + + /* create a PKIX_PL_GeneralName object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_GENERALNAME_TYPE, + sizeof (PKIX_PL_GeneralName), + (PKIX_PL_Object **)&genName, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + nameType = nssAltName->type; + + /* + * We use CERT_CreateGeneralNameList to create just one CERTGeneralName + * item for memory allocation reason. If we want to just create one + * item, we have to use the calling path CERT_NewGeneralName, then + * CERT_CopyOneGeneralName. With this calling path, if we pass + * the arena argument as NULL, in CERT_CopyOneGeneralName's subsequent + * call to CERT_CopyName, it assumes arena should be valid, hence + * segmentation error (not sure this is a NSS bug, certainly it is + * not consistent). But on the other hand, we don't want to keep an + * arena record here explicitely for every PKIX_PL_GeneralName. + * So I concluded it is better to use CERT_CreateGeneralNameList, + * which keeps an arena pointer in its data structure and also masks + * out details calls from this libpkix level. + */ + + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n"); + nssGenNameList = CERT_CreateGeneralNameList(nssAltName); + + if (nssGenNameList == NULL) { + PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED); + } + + genName->nssGeneralNameList = nssGenNameList; + + /* initialize fields */ + genName->type = nameType; + genName->directoryName = NULL; + genName->OthName = NULL; + genName->other = NULL; + genName->oid = NULL; + + switch (nameType){ + case certOtherName: + + PKIX_CHECK(pkix_pl_OtherName_Create + (nssAltName, &otherName, plContext), + PKIX_OTHERNAMECREATEFAILED); + + genName->OthName = otherName; + break; + + case certDirectoryName: + + PKIX_CHECK(pkix_pl_DirectoryName_Create + (nssAltName, &pkixDN, plContext), + PKIX_DIRECTORYNAMECREATEFAILED); + + genName->directoryName = pkixDN; + break; + case certRegisterID: + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem(&nssAltName->name.other, + &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + + genName->oid = pkixOID; + break; + case certDNSName: + case certEDIPartyName: + case certIPAddress: + case certRFC822Name: + case certX400Address: + case certURI: + genName->other = SECITEM_DupItem(&nssAltName->name.other); + if (!genName->other) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + break; + default: + PKIX_ERROR(PKIX_NAMETYPENOTSUPPORTED); + } + + *pGenName = genName; + genName = NULL; + +cleanup: + PKIX_DECREF(genName); + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the GeneralName + * pointed to by "name" and stores it at "pString" Different mechanisms are + * used to create the string, depending on the type of the GeneralName. + * + * PARAMETERS + * "name" + * Address of GeneralName whose string representation is desired. + * Must be non-NULL. + * "pString" + * 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 GeneralName 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_GeneralName_ToString_Helper( + PKIX_PL_GeneralName *name, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_X500Name *pkixDN = NULL; + PKIX_PL_OID *pkixOID = NULL; + char *x400AsciiName = NULL; + char *ediPartyName = NULL; + char *asciiName = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_ToString_Helper"); + PKIX_NULLCHECK_TWO(name, pString); + + switch (name->type) { + case certRFC822Name: + case certDNSName: + case certURI: + /* + * Note that we can't use PKIX_ESCASCII here because + * name->other->data is not guaranteed to be null-terminated. + */ + + PKIX_NULLCHECK_ONE(name->other); + + PKIX_CHECK(PKIX_PL_String_Create(PKIX_UTF8, + (name->other)->data, + (name->other)->len, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certEDIPartyName: + /* XXX print out the actual bytes */ + ediPartyName = "EDIPartyName: <DER-encoded value>"; + PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII, + ediPartyName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certX400Address: + /* XXX print out the actual bytes */ + x400AsciiName = "X400Address: <DER-encoded value>"; + PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII, + x400AsciiName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certIPAddress: + PKIX_CHECK(pkix_pl_ipAddrBytes2Ascii + (name->other, &asciiName, plContext), + PKIX_IPADDRBYTES2ASCIIFAILED); + + PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII, + asciiName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certOtherName: + PKIX_NULLCHECK_ONE(name->OthName); + + /* we only print type-id - don't know how to print value */ + /* XXX print out the bytes of the value */ + PKIX_CHECK(pkix_pl_oidBytes2Ascii + (&name->OthName->oid, &asciiName, plContext), + PKIX_OIDBYTES2ASCIIFAILED); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certRegisterID: + pkixOID = name->oid; + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)pkixOID, pString, plContext), + PKIX_OIDTOSTRINGFAILED); + break; + case certDirectoryName: + pkixDN = name->directoryName; + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)pkixDN, pString, plContext), + PKIX_X500NAMETOSTRINGFAILED); + break; + default: + PKIX_ERROR + (PKIX_TOSTRINGFORTHISGENERALNAMETYPENOTSUPPORTED); + } + +cleanup: + + PKIX_FREE(asciiName); + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_GeneralName *name = NULL; + SECItem secItemName; + SECItem secItemOID; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext), + PKIX_OBJECTNOTGENERALNAME); + + name = (PKIX_PL_GeneralName *)object; + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(name->other, PR_TRUE); + name->other = NULL; + + if (name->OthName){ + secItemName = name->OthName->name; + secItemOID = name->OthName->oid; + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemName, PR_FALSE); + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemOID, PR_FALSE); + + PKIX_FREE(name->OthName); + name->OthName = NULL; + } + + if (name->nssGeneralNameList != NULL) { + PKIX_GENERALNAME_DEBUG + ("\t\tCalling CERT_DestroyGeneralNameList).\n"); + CERT_DestroyGeneralNameList(name->nssGeneralNameList); + } + + PKIX_DECREF(name->directoryName); + PKIX_DECREF(name->oid); + +cleanup: + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *nameString = NULL; + PKIX_PL_GeneralName *name = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext), + PKIX_OBJECTNOTGENERALNAME); + + name = (PKIX_PL_GeneralName *)object; + + PKIX_CHECK(pkix_pl_GeneralName_ToString_Helper + (name, &nameString, plContext), + PKIX_GENERALNAMETOSTRINGHELPERFAILED); + + *pString = nameString; + +cleanup: + + + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 firstHash, secondHash, nameHash; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext), + PKIX_OBJECTNOTGENERALNAME); + + name = (PKIX_PL_GeneralName *)object; + + switch (name->type) { + case certRFC822Name: + case certDNSName: + case certX400Address: + case certEDIPartyName: + case certURI: + case certIPAddress: + PKIX_NULLCHECK_ONE(name->other); + PKIX_CHECK(pkix_hash + ((const unsigned char *) + name->other->data, + name->other->len, + &nameHash, + plContext), + PKIX_HASHFAILED); + break; + case certRegisterID: + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *)name->oid, + &nameHash, + plContext), + PKIX_OIDHASHCODEFAILED); + break; + case certOtherName: + PKIX_NULLCHECK_ONE(name->OthName); + PKIX_CHECK(pkix_hash + ((const unsigned char *) + name->OthName->oid.data, + name->OthName->oid.len, + &firstHash, + plContext), + PKIX_HASHFAILED); + + PKIX_CHECK(pkix_hash + ((const unsigned char *) + name->OthName->name.data, + name->OthName->name.len, + &secondHash, + plContext), + PKIX_HASHFAILED); + + nameHash = firstHash + secondHash; + break; + case certDirectoryName: + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *) + name->directoryName, + &nameHash, + plContext), + PKIX_X500NAMEHASHCODEFAILED); + break; + } + + *pHashcode = nameHash; + +cleanup: + + PKIX_RETURN(GENERALNAME); + +} + +/* + * FUNCTION: pkix_pl_GeneralName_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_GeneralName *firstName = NULL; + PKIX_PL_GeneralName *secondName = NULL; + PKIX_UInt32 secondType; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a GeneralName */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_GENERALNAME_TYPE, plContext), + PKIX_FIRSTOBJECTNOTGENERALNAME); + + /* + * Since we know firstObject is a GeneralName, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a GeneralName, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_GENERALNAME_TYPE){ + goto cleanup; + } + + firstName = (PKIX_PL_GeneralName *)firstObject; + secondName = (PKIX_PL_GeneralName *)secondObject; + + if (firstName->type != secondName->type){ + goto cleanup; + } + + switch (firstName->type) { + case certRFC822Name: + case certDNSName: + case certX400Address: + case certEDIPartyName: + case certURI: + case certIPAddress: + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); + if (SECITEM_CompareItem(firstName->other, + secondName->other) != SECEqual) { + goto cleanup; + } + break; + case certRegisterID: + PKIX_CHECK(PKIX_PL_Object_Equals + ((PKIX_PL_Object *)firstName->oid, + (PKIX_PL_Object *)secondName->oid, + pResult, + plContext), + PKIX_OIDEQUALSFAILED); + goto cleanup; + case certOtherName: + PKIX_NULLCHECK_TWO(firstName->OthName, secondName->OthName); + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); + if (SECITEM_CompareItem(&firstName->OthName->oid, + &secondName->OthName->oid) + != SECEqual || + SECITEM_CompareItem(&firstName->OthName->name, + &secondName->OthName->name) + != SECEqual) { + goto cleanup; + } + break; + case certDirectoryName: + PKIX_CHECK(PKIX_PL_Object_Equals + ((PKIX_PL_Object *)firstName->directoryName, + (PKIX_PL_Object *)secondName->directoryName, + pResult, + plContext), + PKIX_X500NAMEEQUALSFAILED); + goto cleanup; + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_RegisterSelf + * DESCRIPTION: + * Registers PKIX_GENERALNAME_TYPE and 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_GeneralName_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_RegisterSelf"); + + entry.description = "GeneralName"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_GeneralName); + entry.destructor = pkix_pl_GeneralName_Destroy; + entry.equalsFunction = pkix_pl_GeneralName_Equals; + entry.hashcodeFunction = pkix_pl_GeneralName_Hashcode; + entry.toStringFunction = pkix_pl_GeneralName_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_GENERALNAME_TYPE] = entry; + + PKIX_RETURN(GENERALNAME); +} + +/* --Public-Functions------------------------------------------------------- */ + +#ifdef BUILD_LIBPKIX_TESTS +/* + * FUNCTION: PKIX_PL_GeneralName_Create (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_GeneralName_Create( + PKIX_UInt32 nameType, + PKIX_PL_String *stringRep, + PKIX_PL_GeneralName **pGName, + void *plContext) +{ + PKIX_PL_X500Name *pkixDN = NULL; + PKIX_PL_OID *pkixOID = NULL; + SECItem *secItem = NULL; + char *asciiString = NULL; + PKIX_UInt32 length = 0; + PKIX_PL_GeneralName *genName = NULL; + CERTGeneralName *nssGenName = NULL; + CERTGeneralNameList *nssGenNameList = NULL; + CERTName *nssCertName = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(GENERALNAME, "PKIX_PL_GeneralName_Create"); + PKIX_NULLCHECK_TWO(pGName, stringRep); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stringRep, + PKIX_ESCASCII, + (void **)&asciiString, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + /* Create a temporary CERTGeneralName */ + PKIX_GENERALNAME_DEBUG("\t\tCalling PL_strlen).\n"); + length = PL_strlen(asciiString); + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_AllocItem).\n"); + secItem = SECITEM_AllocItem(NULL, NULL, length); + PKIX_GENERALNAME_DEBUG("\t\tCalling PORT_Memcpy).\n"); + (void) PORT_Memcpy(secItem->data, asciiString, length); + PKIX_CERT_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_NewGeneralName).\n"); + nssGenName = CERT_NewGeneralName(arena, nameType); + if (nssGenName == NULL) { + PKIX_ERROR(PKIX_ALLOCATENEWCERTGENERALNAMEFAILED); + } + + switch (nameType) { + case certRFC822Name: + case certDNSName: + case certURI: + nssGenName->name.other = *secItem; + break; + + case certDirectoryName: + + PKIX_CHECK(PKIX_PL_X500Name_Create + (stringRep, &pkixDN, plContext), + PKIX_X500NAMECREATEFAILED); + + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_AsciiToName).\n"); + nssCertName = CERT_AsciiToName(asciiString); + nssGenName->name.directoryName = *nssCertName; + break; + + case certRegisterID: + PKIX_CHECK(PKIX_PL_OID_Create + (asciiString, &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + nssGenName->name.other = *secItem; + break; + default: + /* including IPAddress, EDIPartyName, OtherName, X400Address */ + PKIX_ERROR(PKIX_UNABLETOCREATEGENERALNAMEOFTHISTYPE); + } + + /* create a PKIX_PL_GeneralName object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_GENERALNAME_TYPE, + sizeof (PKIX_PL_GeneralName), + (PKIX_PL_Object **)&genName, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* create a CERTGeneralNameList */ + nssGenName->type = nameType; + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n"); + nssGenNameList = CERT_CreateGeneralNameList(nssGenName); + if (nssGenNameList == NULL) { + PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED); + } + genName->nssGeneralNameList = nssGenNameList; + + /* initialize fields */ + genName->type = nameType; + genName->directoryName = pkixDN; + genName->OthName = NULL; + genName->other = secItem; + genName->oid = pkixOID; + + *pGName = genName; +cleanup: + + PKIX_FREE(asciiString); + + if (nssCertName != NULL) { + PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyName).\n"); + CERT_DestroyName(nssCertName); + } + + if (arena){ /* will free nssGenName */ + PKIX_CERT_DEBUG("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(pkixDN); + PKIX_DECREF(pkixOID); + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + if (secItem){ + SECITEM_FreeItem(secItem, PR_TRUE); + secItem = NULL; + } + } + + PKIX_RETURN(GENERALNAME); +} + +#endif /* BUILD_LIBPKIX_TESTS */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h new file mode 100644 index 0000000000..3cb5264d51 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_generalname.h + * + * GeneralName Object Definitions + * + */ + +#ifndef _PKIX_PL_GENERALNAME_H +#define _PKIX_PL_GENERALNAME_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_GeneralNameStruct{ + CERTGeneralNameList *nssGeneralNameList; + CERTGeneralNameType type; + PKIX_PL_X500Name *directoryName; + PKIX_PL_OID *oid; + OtherName *OthName; + SECItem *other; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_GeneralName_Create( + CERTGeneralName *nssAltName, + PKIX_PL_GeneralName **pGenName, + void *plContext); + +PKIX_Error * +pkix_pl_GeneralName_GetNssGeneralName( + PKIX_PL_GeneralName *genName, + CERTGeneralName **pNssGenName, + void *plContext); + +PKIX_Error *pkix_pl_GeneralName_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_GENERALNAME_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c new file mode 100644 index 0000000000..09b54a2be3 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c @@ -0,0 +1,874 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_infoaccess.c + * + * InfoAccess Object Definitions + * + */ + +#include "pkix_pl_infoaccess.h" + +/* --Private-InfoAccess-Functions----------------------------------*/ + +/* + * FUNCTION: pkix_pl_InfoAccess_Create + * DESCRIPTION: + * + * This function creates an InfoAccess from the method provided in "method" and + * the GeneralName provided in "generalName" and stores the result at + * "pInfoAccess". + * + * PARAMETERS + * "method" + * The UInt32 value to be stored as the method field of the InfoAccess. + * "gName" + * The GeneralName to be stored as the gName field of the InfoAccess. + * Must be non-NULL. + * "pInfoAccess" + * 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 a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_InfoAccess_Create( + PKIX_UInt32 method, + PKIX_PL_GeneralName *gName, + PKIX_PL_InfoAccess **pInfoAccess, + void *plContext) +{ + + PKIX_PL_InfoAccess *infoAccess = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Create"); + PKIX_NULLCHECK_TWO(gName, pInfoAccess); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_INFOACCESS_TYPE, + sizeof (PKIX_PL_InfoAccess), + (PKIX_PL_Object **)&infoAccess, + plContext), + PKIX_COULDNOTCREATEINFOACCESSOBJECT); + + infoAccess->method = method; + + PKIX_INCREF(gName); + infoAccess->location = gName; + + *pInfoAccess = infoAccess; + infoAccess = NULL; + +cleanup: + PKIX_DECREF(infoAccess); + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_InfoAccess *infoAccess = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_INFOACCESS_TYPE, plContext), + PKIX_OBJECTNOTANINFOACCESS); + + infoAccess = (PKIX_PL_InfoAccess *)object; + + PKIX_DECREF(infoAccess->location); + +cleanup: + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_InfoAccess *infoAccess; + PKIX_PL_String *infoAccessString = NULL; + char *asciiFormat = NULL; + char *asciiMethod = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *methodString = NULL; + PKIX_PL_String *locationString = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_INFOACCESS_TYPE, plContext), + PKIX_OBJECTNOTINFOACCESS); + + infoAccess = (PKIX_PL_InfoAccess *)object; + + asciiFormat = + "[" + "method:%s, " + "location:%s" + "]"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + switch(infoAccess->method) { + case PKIX_INFOACCESS_CA_ISSUERS: + asciiMethod = "caIssuers"; + break; + case PKIX_INFOACCESS_OCSP: + asciiMethod = "ocsp"; + break; + case PKIX_INFOACCESS_TIMESTAMPING: + asciiMethod = "timestamping"; + break; + case PKIX_INFOACCESS_CA_REPOSITORY: + asciiMethod = "caRepository"; + break; + default: + asciiMethod = "unknown"; + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiMethod, + 0, + &methodString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_TOSTRING(infoAccess->location, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&infoAccessString, + plContext, + formatString, + methodString, + locationString), + PKIX_SPRINTFFAILED); + + *pString = infoAccessString; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(methodString); + PKIX_DECREF(locationString); + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_InfoAccess *infoAccess = NULL; + PKIX_UInt32 infoAccessHash; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_INFOACCESS_TYPE, plContext), + PKIX_OBJECTNOTINFOACCESS); + + infoAccess = (PKIX_PL_InfoAccess *)object; + + PKIX_HASHCODE(infoAccess->location, &infoAccessHash, plContext, + PKIX_OBJECTHASHCODEFAILED); + + infoAccessHash += (infoAccess->method << 7); + + *pHashcode = infoAccessHash; + +cleanup: + + PKIX_RETURN(INFOACCESS); + +} + +/* + * FUNCTION: pkix_pl_InfoAccess_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_InfoAccess *firstInfoAccess = NULL; + PKIX_PL_InfoAccess *secondInfoAccess = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a InfoAccess */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_INFOACCESS_TYPE, plContext), + PKIX_FIRSTOBJECTNOTINFOACCESS); + + /* + * Since we know firstObject is a InfoAccess, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a InfoAccess, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_INFOACCESS_TYPE) goto cleanup; + + firstInfoAccess = (PKIX_PL_InfoAccess *)firstObject; + secondInfoAccess = (PKIX_PL_InfoAccess *)secondObject; + + *pResult = PKIX_FALSE; + + if (firstInfoAccess->method != secondInfoAccess->method) { + goto cleanup; + } + + PKIX_EQUALS(firstInfoAccess, secondInfoAccess, &cmpResult, plContext, + PKIX_OBJECTEQUALSFAILED); + + *pResult = cmpResult; + +cleanup: + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_RegisterSelf + * DESCRIPTION: + * Registers PKIX_INFOACCESS_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_InfoAccess_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(INFOACCESS, + "pkix_pl_InfoAccess_RegisterSelf"); + + entry.description = "InfoAccess"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_InfoAccess); + entry.destructor = pkix_pl_InfoAccess_Destroy; + entry.equalsFunction = pkix_pl_InfoAccess_Equals; + entry.hashcodeFunction = pkix_pl_InfoAccess_Hashcode; + entry.toStringFunction = pkix_pl_InfoAccess_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_INFOACCESS_TYPE] = entry; + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_CreateList + * DESCRIPTION: + * + * Based on data in CERTAuthInfoAccess array "nssInfoAccess", this function + * creates and returns a PKIX_List of PKIX_PL_InfoAccess at "pInfoAccessList". + * + * PARAMETERS + * "nssInfoAccess" + * The pointer array of CERTAuthInfoAccess that contains access data. + * May be NULL. + * "pInfoAccessList" + * Address where a list of PKIX_PL_InfoAccess 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_InfoAccess_CreateList( + CERTAuthInfoAccess **nssInfoAccess, + PKIX_List **pInfoAccessList, /* of PKIX_PL_InfoAccess */ + void *plContext) +{ + PKIX_List *infoAccessList = NULL; + PKIX_PL_InfoAccess *infoAccess = NULL; + PKIX_PL_GeneralName *location = NULL; + PKIX_UInt32 method; + int i; + + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_CreateList"); + PKIX_NULLCHECK_ONE(pInfoAccessList); + + PKIX_CHECK(PKIX_List_Create(&infoAccessList, plContext), + PKIX_LISTCREATEFAILED); + + if (nssInfoAccess == NULL) { + goto cleanup; + } + + for (i = 0; nssInfoAccess[i] != NULL; i++) { + + if (nssInfoAccess[i]->location == NULL) { + continue; + } + + PKIX_CHECK(pkix_pl_GeneralName_Create + (nssInfoAccess[i]->location, &location, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CERT_DEBUG("\t\tCalling SECOID_FindOIDTag).\n"); + method = SECOID_FindOIDTag(&nssInfoAccess[i]->method); + /* Map NSS access method value into PKIX constant */ + switch(method) { + case SEC_OID_PKIX_CA_ISSUERS: + method = PKIX_INFOACCESS_CA_ISSUERS; + break; + case SEC_OID_PKIX_OCSP: + method = PKIX_INFOACCESS_OCSP; + break; + case SEC_OID_PKIX_TIMESTAMPING: + method = PKIX_INFOACCESS_TIMESTAMPING; + break; + case SEC_OID_PKIX_CA_REPOSITORY: + method = PKIX_INFOACCESS_CA_REPOSITORY; + break; + default: + PKIX_ERROR(PKIX_UNKNOWNINFOACCESSMETHOD); + } + + PKIX_CHECK(pkix_pl_InfoAccess_Create + (method, location, &infoAccess, plContext), + PKIX_INFOACCESSCREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (infoAccessList, + (PKIX_PL_Object *)infoAccess, + plContext), + PKIX_LISTAPPENDITEMFAILED); + PKIX_DECREF(infoAccess); + PKIX_DECREF(location); + } + + *pInfoAccessList = infoAccessList; + infoAccessList = NULL; + +cleanup: + + PKIX_DECREF(infoAccessList); + PKIX_DECREF(infoAccess); + PKIX_DECREF(location); + + PKIX_RETURN(INFOACCESS); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_InfoAccess_GetMethod (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_InfoAccess_GetMethod( + PKIX_PL_InfoAccess *infoAccess, + PKIX_UInt32 *pMethod, + void *plContext) +{ + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetMethod"); + PKIX_NULLCHECK_TWO(infoAccess, pMethod); + + *pMethod = infoAccess->method; + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: PKIX_PL_InfoAccess_GetLocation (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_InfoAccess_GetLocation( + PKIX_PL_InfoAccess *infoAccess, + PKIX_PL_GeneralName **pLocation, + void *plContext) +{ + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocation"); + PKIX_NULLCHECK_TWO(infoAccess, pLocation); + + PKIX_INCREF(infoAccess->location); + + *pLocation = infoAccess->location; + +cleanup: + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: PKIX_PL_InfoAccess_GetLocationType (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_InfoAccess_GetLocationType( + PKIX_PL_InfoAccess *infoAccess, + PKIX_UInt32 *pType, + void *plContext) +{ + PKIX_PL_String *locationString = NULL; + PKIX_UInt32 type = PKIX_INFOACCESS_LOCATION_UNKNOWN; + PKIX_UInt32 len = 0; + void *location = NULL; + + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocationType"); + PKIX_NULLCHECK_TWO(infoAccess, pType); + + if (infoAccess->location != NULL) { + + PKIX_TOSTRING(infoAccess->location, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (locationString, PKIX_ESCASCII, &location, &len, plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n"); +#ifndef NSS_PKIX_NO_LDAP + if (PORT_Strncmp(location, "ldap:", 5) == 0){ + type = PKIX_INFOACCESS_LOCATION_LDAP; + } else +#endif + if (PORT_Strncmp(location, "http:", 5) == 0){ + type = PKIX_INFOACCESS_LOCATION_HTTP; + } + } + + *pType = type; + +cleanup: + + PKIX_PL_Free(location, plContext); + PKIX_DECREF(locationString); + + PKIX_RETURN(INFOACCESS); +} + +#ifndef NSS_PKIX_NO_LDAP +/* + * FUNCTION: pkix_pl_InfoAccess_ParseTokens + * DESCRIPTION: + * + * This function parses the string beginning at "startPos" into tokens using + * the separator contained in "separator" and the terminator contained in + * "terminator", copying the tokens into space allocated from the arena + * pointed to by "arena". It stores in "tokens" a null-terminated array of + * pointers to those tokens. + * + * PARAMETERS + * "arena" + * Address of a PLArenaPool to be used in populating the LDAPLocation. + * Must be non-NULL. + * "startPos" + * The address of char string that contains a subset of ldap location. + * "tokens" + * The address of an array of char string for storing returned tokens. + * Must be non-NULL. + * "separator" + * The character that is taken as token separator. Must be non-NULL. + * "terminator" + * The character that is taken as parsing terminator. 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 InfoAccess 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_InfoAccess_ParseTokens( + PLArenaPool *arena, + char **startPos, /* return update */ + char ***tokens, + char separator, + char terminator, + void *plContext) +{ + PKIX_UInt32 numFilters = 0; + char *endPos = NULL; + char **filterP = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseTokens"); + PKIX_NULLCHECK_THREE(arena, startPos, tokens); + + endPos = *startPos; + + /* First pass: parse to <terminator> to count number of components */ + numFilters = 0; + while (*endPos != terminator && *endPos != '\0') { + endPos++; + if (*endPos == separator) { + numFilters++; + } + } + + if (*endPos != terminator) { + PKIX_ERROR(PKIX_LOCATIONSTRINGNOTPROPERLYTERMINATED); + } + + /* Last component doesn't need a separator, although we allow it */ + if (endPos > *startPos && *(endPos-1) != separator) { + numFilters++; + } + + /* + * If string is a=xx, b=yy, c=zz, etc., use a=xx for filter, + * and everything else for the base + */ + if (numFilters > 2) numFilters = 2; + + filterP = PORT_ArenaZNewArray(arena, char*, numFilters+1); + if (filterP == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + /* Second pass: parse to fill in components in token array */ + *tokens = filterP; + endPos = *startPos; + + while (numFilters) { + if (*endPos == separator || *endPos == terminator) { + PKIX_UInt32 len = endPos - *startPos; + char *p = PORT_ArenaZAlloc(arena, len+1); + if (p == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PORT_Memcpy(p, *startPos, len); + p[len] = '\0'; + + *filterP = p; + filterP++; + numFilters--; + + separator = terminator; + + if (*endPos == '\0') { + *startPos = endPos; + break; + } else { + endPos++; + *startPos = endPos; + continue; + } + } + endPos++; + } + + *filterP = NULL; + +cleanup: + + PKIX_RETURN(INFOACCESS); +} + +static int +pkix_pl_HexDigitToInt( + int ch) +{ + if (isdigit(ch)) { + ch = ch - '0'; + } else if (isupper(ch)) { + ch = ch - 'A' + 10; + } else { + ch = ch - 'a' + 10; + } + return ch; +} + +/* + * Convert the "%" hex hex escape sequences in the URL 'location' in place. + */ +static void +pkix_pl_UnescapeURL( + char *location) +{ + const char *src; + char *dst; + + for (src = dst = location; *src != '\0'; src++, dst++) { + if (*src == '%' && isxdigit((unsigned char)*(src+1)) && + isxdigit((unsigned char)*(src+2))) { + *dst = pkix_pl_HexDigitToInt((unsigned char)*(src+1)); + *dst *= 16; + *dst += pkix_pl_HexDigitToInt((unsigned char)*(src+2)); + src += 2; + } else { + *dst = *src; + } + } + *dst = *src; /* the terminating null */ +} + +/* + * FUNCTION: pkix_pl_InfoAccess_ParseLocation + * DESCRIPTION: + * + * This function parses the GeneralName pointed to by "generalName" into the + * fields of the LDAPRequestParams pointed to by "request" and a domainName + * pointed to by "pDomainName", using the PLArenaPool pointed to by "arena" to + * allocate storage for the request components and for the domainName string. + * + * The expected GeneralName string should be in the format described by the + * following BNF: + * + * ldap://<ldap-server-site>/[cn=<cname>][,o=<org>][,c=<country>]? + * [caCertificate|crossCertificatPair|certificateRevocationList]; + * [binary|<other-type>] + * [[,caCertificate|crossCertificatPair|certificateRevocationList] + * [binary|<other-type>]]* + * + * PARAMETERS + * "gName" + * Address of the GeneralName whose LDAPLocation is to be parsed. Must be + * non-NULL. + * "arena" + * Address of PLArenaPool to be used for the domainName and for components + * of the LDAPRequest. Must be non-NULL. + * "request" + * Address of the LDAPRequestParams into which request components are + * stored. Must be non-NULL. + * *pDomainName" + * Address at which the domainName 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 InfoAccess 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_InfoAccess_ParseLocation( + PKIX_PL_GeneralName *gName, + PLArenaPool *arena, + LDAPRequestParams *request, + char **pDomainName, + void *plContext) +{ + PKIX_PL_String *locationString = NULL; + PKIX_UInt32 len = 0; + PKIX_UInt32 ncIndex = 0; + char *domainName = NULL; + char **avaArray = NULL; + char **attrArray = NULL; + char *attr = NULL; + char *locationAscii = NULL; + char *startPos = NULL; + char *endPos = NULL; + char *avaPtr = NULL; + LdapAttrMask attrBit = 0; + LDAPNameComponent **setOfNameComponent = NULL; + LDAPNameComponent *nameComponent = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseLocation"); + PKIX_NULLCHECK_FOUR(gName, arena, request, pDomainName); + + PKIX_TOSTRING(gName, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (locationString, + PKIX_ESCASCII, + (void **)&locationAscii, + &len, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + pkix_pl_UnescapeURL(locationAscii); + + /* Skip "ldap:" */ + endPos = locationAscii; + while (*endPos != ':' && *endPos != '\0') { + endPos++; + } + if (*endPos == '\0') { + PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGLOCATIONTYPE); + } + + /* Skip "//" */ + endPos++; + if (*endPos != '\0' && *(endPos+1) != '0' && + *endPos == '/' && *(endPos+1) == '/') { + endPos += 2; + } else { + PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGDOUBLESLASH); + } + + /* Get the server-site */ + startPos = endPos; + while(*endPos != '/' && *(endPos) != '\0') { + endPos++; + } + if (*endPos == '\0') { + PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGSERVERSITE); + } + + len = endPos - startPos; + endPos++; + + domainName = PORT_ArenaZAlloc(arena, len + 1); + if (!domainName) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PORT_Memcpy(domainName, startPos, len); + + domainName[len] = '\0'; + + *pDomainName = domainName; + + /* + * Get a list of AttrValueAssertions (such as + * "cn=CommonName, o=Organization, c=US" into a null-terminated array + */ + startPos = endPos; + PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens + (arena, + &startPos, + (char ***) &avaArray, + ',', + '?', + plContext), + PKIX_INFOACCESSPARSETOKENSFAILED); + + /* Count how many AVAs we have */ + for (len = 0; avaArray[len] != NULL; len++) {} + + if (len < 2) { + PKIX_ERROR(PKIX_NOTENOUGHNAMECOMPONENTSINGENERALNAME); + } + + /* Use last name component for baseObject */ + request->baseObject = avaArray[len - 1]; + + /* Use only one component for filter. LDAP servers aren't too smart. */ + len = 2; /* Eliminate this when servers get smarter. */ + + avaArray[len - 1] = NULL; + + /* Get room for null-terminated array of (LdapNameComponent *) */ + setOfNameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent *, len); + if (setOfNameComponent == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + /* Get room for the remaining LdapNameComponents */ + nameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent, --len); + if (nameComponent == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + /* Convert remaining AVAs to LDAPNameComponents */ + for (ncIndex = 0; ncIndex < len; ncIndex ++) { + setOfNameComponent[ncIndex] = nameComponent; + avaPtr = avaArray[ncIndex]; + nameComponent->attrType = (unsigned char *)avaPtr; + while ((*avaPtr != '=') && (*avaPtr != '\0')) { + avaPtr++; + if (*avaPtr == '\0') { + PKIX_ERROR(PKIX_NAMECOMPONENTWITHNOEQ); + } + } + *(avaPtr++) = '\0'; + nameComponent->attrValue = (unsigned char *)avaPtr; + nameComponent++; + } + + setOfNameComponent[len] = NULL; + request->nc = setOfNameComponent; + + /* + * Get a list of AttrTypes (such as + * "caCertificate;binary, crossCertificatePair;binary") into + * a null-terminated array + */ + + PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens + (arena, + (char **) &startPos, + (char ***) &attrArray, + ',', + '\0', + plContext), + PKIX_INFOACCESSPARSETOKENSFAILED); + + /* Convert array of Attr Types into a bit mask */ + request->attributes = 0; + attr = attrArray[0]; + while (attr != NULL) { + PKIX_CHECK(pkix_pl_LdapRequest_AttrStringToBit + (attr, &attrBit, plContext), + PKIX_LDAPREQUESTATTRSTRINGTOBITFAILED); + request->attributes |= attrBit; + attr = *(++attrArray); + } + +cleanup: + + PKIX_PL_Free(locationAscii, plContext); + PKIX_DECREF(locationString); + + PKIX_RETURN(INFOACCESS); +} +#endif /* !NSS_PKIX_NO_LDAP */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h new file mode 100644 index 0000000000..e69d7b4139 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_infoaccess.h + * + * InfoAccess Object Definitions + * + */ + +#ifndef _PKIX_PL_INFOACCESS_H +#define _PKIX_PL_INFOACCESS_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_InfoAccessStruct{ + PKIX_UInt32 method; + PKIX_PL_GeneralName *location; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_InfoAccess_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_InfoAccess_CreateList( + CERTAuthInfoAccess **authInfoAccess, + PKIX_List **pAiaList, /* of PKIX_PL_InfoAccess */ + void *plContext); + +#ifndef NSS_PKIX_NO_LDAP +PKIX_Error * +pkix_pl_InfoAccess_ParseLocation( + PKIX_PL_GeneralName *generalName, + PLArenaPool *arena, + LDAPRequestParams *request, + char **pDomainName, + void *plContext); +#endif /* !NSS_PKIX_NO_LDAP */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_INFOACCESS_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c new file mode 100644 index 0000000000..1d0b61bb44 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c @@ -0,0 +1,1279 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_nameconstraints.c + * + * Name Constraints Object Functions Definitions + * + */ + +#include "pkix_pl_nameconstraints.h" + + +/* --Private-NameConstraints-Functions----------------------------- */ + +/* + * FUNCTION: pkix_pl_CertNameConstraints_GetPermitted + * DESCRIPTION: + * + * This function retrieve name constraints permitted list from NSS + * data in "nameConstraints" and returns a PKIX_PL_GeneralName list + * in "pPermittedList". + * + * PARAMETERS + * "nameConstraints" + * Address of CertNameConstraints which has a pointer to + * CERTNameConstraints data. Must be non-NULL. + * "pPermittedList" + * Address where returned permitted name list is stored. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a NameConstraints 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_CertNameConstraints_GetPermitted( + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_List **pPermittedList, + void *plContext) +{ + CERTNameConstraints *nssNameConstraints = NULL; + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraint *nssPermitted = NULL; + CERTNameConstraint *firstPermitted = NULL; + PKIX_List *permittedList = NULL; + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_GetPermitted"); + PKIX_NULLCHECK_TWO(nameConstraints, pPermittedList); + + /* + * nssNameConstraints is an array of CERTNameConstraints + * pointers where CERTNameConstraints keep its permitted and excluded + * lists as pointer array of CERTNameConstraint. + */ + + if (nameConstraints->permittedList == NULL) { + + PKIX_OBJECT_LOCK(nameConstraints); + + if (nameConstraints->permittedList == NULL) { + + PKIX_CHECK(PKIX_List_Create(&permittedList, plContext), + PKIX_LISTCREATEFAILED); + + numItems = nameConstraints->numNssNameConstraints; + nssNameConstraintsList = + nameConstraints->nssNameConstraintsList; + + for (i = 0; i < numItems; i++) { + + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + nssNameConstraints = *(nssNameConstraintsList + i); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + if (nssNameConstraints->permited != NULL) { + + nssPermitted = nssNameConstraints->permited; + firstPermitted = nssPermitted; + + do { + + PKIX_CHECK(pkix_pl_GeneralName_Create + (&nssPermitted->name, &name, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (permittedList, + (PKIX_PL_Object *)name, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(name); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstraint\n"); + nssPermitted = CERT_GetNextNameConstraint + (nssPermitted); + + } while (nssPermitted != firstPermitted); + + } + } + + PKIX_CHECK(PKIX_List_SetImmutable(permittedList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + nameConstraints->permittedList = permittedList; + + } + + PKIX_OBJECT_UNLOCK(nameConstraints); + + } + + PKIX_INCREF(nameConstraints->permittedList); + + *pPermittedList = nameConstraints->permittedList; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_GetExcluded + * DESCRIPTION: + * + * This function retrieve name constraints excluded list from NSS + * data in "nameConstraints" and returns a PKIX_PL_GeneralName list + * in "pExcludedList". + * + * PARAMETERS + * "nameConstraints" + * Address of CertNameConstraints which has a pointer to NSS data. + * Must be non-NULL. + * "pPermittedList" + * Address where returned excluded name list is stored. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a NameConstraints 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_CertNameConstraints_GetExcluded( + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_List **pExcludedList, + void *plContext) +{ + CERTNameConstraints *nssNameConstraints = NULL; + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraint *nssExcluded = NULL; + CERTNameConstraint *firstExcluded = NULL; + PKIX_List *excludedList = NULL; + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_GetExcluded"); + PKIX_NULLCHECK_TWO(nameConstraints, pExcludedList); + + if (nameConstraints->excludedList == NULL) { + + PKIX_OBJECT_LOCK(nameConstraints); + + if (nameConstraints->excludedList == NULL) { + + PKIX_CHECK(PKIX_List_Create(&excludedList, plContext), + PKIX_LISTCREATEFAILED); + + numItems = nameConstraints->numNssNameConstraints; + nssNameConstraintsList = + nameConstraints->nssNameConstraintsList; + + for (i = 0; i < numItems; i++) { + + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + nssNameConstraints = *(nssNameConstraintsList + i); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + if (nssNameConstraints->excluded != NULL) { + + nssExcluded = nssNameConstraints->excluded; + firstExcluded = nssExcluded; + + do { + + PKIX_CHECK(pkix_pl_GeneralName_Create + (&nssExcluded->name, &name, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (excludedList, + (PKIX_PL_Object *)name, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(name); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstraint\n"); + nssExcluded = CERT_GetNextNameConstraint + (nssExcluded); + + } while (nssExcluded != firstExcluded); + + } + + } + PKIX_CHECK(PKIX_List_SetImmutable(excludedList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + nameConstraints->excludedList = excludedList; + + } + + PKIX_OBJECT_UNLOCK(nameConstraints); + } + + PKIX_INCREF(nameConstraints->excludedList); + + *pExcludedList = nameConstraints->excludedList; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_CheckNameSpaceNssNames + * DESCRIPTION: + * + * This function checks if CERTGeneralNames in "nssSubjectNames" comply + * with the permitted and excluded names in "nameConstraints". It returns + * PKIX_TRUE in "pCheckPass", if the Names satify the name space of the + * permitted list and if the Names are not in the excluded list. Otherwise, + * it returns PKIX_FALSE. + * + * PARAMETERS + * "nssSubjectNames" + * List of CERTGeneralName that nameConstraints verification is based on. + * "nameConstraints" + * Address of CertNameConstraints that provides lists of permitted + * and excluded names. Must be non-NULL. + * "pCheckPass" + * Address where PKIX_TRUE is returned if the all names in "nameList" are + * valid. + * "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 NameConstraints 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_CertNameConstraints_CheckNameSpaceNssNames( + CERTGeneralName *nssSubjectNames, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext) +{ + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + CERTGeneralName *nssMatchName = NULL; + PLArenaPool *arena = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + SECStatus status = SECSuccess; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_CheckNameSpaceNssNames"); + PKIX_NULLCHECK_THREE(nssSubjectNames, nameConstraints, pCheckPass); + + *pCheckPass = PKIX_TRUE; + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + nssMatchName = nssSubjectNames; + nssNameConstraintsList = nameConstraints->nssNameConstraintsList; + + /* + * CERTNameConstraint items in each permitted or excluded list + * is verified as OR condition. That means, if one item matched, + * then the checking on the remaining items on the list is skipped. + * (see NSS cert_CompareNameWithConstraints(...)). + * Items on PKIX_PL_NameConstraint's nssNameConstraints are verified + * as AND condition. PKIX_PL_NameConstraint keeps an array of pointers + * of CERTNameConstraints resulting from merging multiple + * PKIX_PL_NameConstraints. Since each CERTNameConstraint are created + * for different entity, a union condition of these entities then is + * performed. + */ + + do { + + numItems = nameConstraints->numNssNameConstraints; + + for (i = 0; i < numItems; i++) { + + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + nssNameConstraints = *(nssNameConstraintsList + i); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CheckNameSpace\n"); + status = CERT_CheckNameSpace + (arena, nssNameConstraints, nssMatchName); + if (status != SECSuccess) { + break; + } + + } + + if (status != SECSuccess) { + break; + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextGeneralName\n"); + nssMatchName = CERT_GetNextGeneralName(nssMatchName); + + } while (nssMatchName != nssSubjectNames); + + if (status == SECFailure) { + + *pCheckPass = PKIX_FALSE; + } + +cleanup: + + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_NameConstraints_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTNAMECONSTRAINTS); + + nameConstraints = (PKIX_PL_CertNameConstraints *)object; + + PKIX_CHECK(PKIX_PL_Free + (nameConstraints->nssNameConstraintsList, plContext), + PKIX_FREEFAILED); + + if (nameConstraints->arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(nameConstraints->arena, PR_FALSE); + nameConstraints->arena = NULL; + } + + PKIX_DECREF(nameConstraints->permittedList); + PKIX_DECREF(nameConstraints->excludedList); + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the object + * NameConstraints and stores it at "pString". + * + * PARAMETERS + * "nameConstraints" + * Address of CertNameConstraints whose string representation is + * desired. Must be non-NULL. + * "pString" + * Address where string 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 NameConstraints 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_CertNameConstraints_ToString_Helper( + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiFormat = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_List *permittedList = NULL; + PKIX_List *excludedList = NULL; + PKIX_PL_String *permittedListString = NULL; + PKIX_PL_String *excludedListString = NULL; + PKIX_PL_String *nameConstraintsString = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_ToString_Helper"); + PKIX_NULLCHECK_TWO(nameConstraints, pString); + + asciiFormat = + "[\n" + "\t\tPermitted Name: %s\n" + "\t\tExcluded Name: %s\n" + "\t]\n"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (nameConstraints, &permittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_TOSTRING(permittedList, &permittedListString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (nameConstraints, &excludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_TOSTRING(excludedList, &excludedListString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&nameConstraintsString, + plContext, + formatString, + permittedListString, + excludedListString), + PKIX_SPRINTFFAILED); + + *pString = nameConstraintsString; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(permittedList); + PKIX_DECREF(excludedList); + PKIX_DECREF(permittedListString); + PKIX_DECREF(excludedListString); + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *nameConstraintsString = NULL; + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType( + object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTNAMECONSTRAINTS); + + nameConstraints = (PKIX_PL_CertNameConstraints *)object; + + PKIX_CHECK(pkix_pl_CertNameConstraints_ToString_Helper + (nameConstraints, &nameConstraintsString, plContext), + PKIX_CERTNAMECONSTRAINTSTOSTRINGHELPERFAILED); + + *pString = nameConstraintsString; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + PKIX_List *permittedList = NULL; + PKIX_List *excludedList = NULL; + PKIX_UInt32 permitHash = 0; + PKIX_UInt32 excludeHash = 0; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTNAMECONSTRAINTS); + + nameConstraints = (PKIX_PL_CertNameConstraints *)object; + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (nameConstraints, &permittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_HASHCODE(permittedList, &permitHash, plContext, + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (nameConstraints, &excludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_HASHCODE(excludedList, &excludeHash, plContext, + PKIX_OBJECTHASHCODEFAILED); + + *pHashcode = (((permitHash << 7) + excludeHash) << 7) + + nameConstraints->numNssNameConstraints; + +cleanup: + + PKIX_DECREF(permittedList); + PKIX_DECREF(excludedList); + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertNameConstraints *firstNC = NULL; + PKIX_PL_CertNameConstraints *secondNC = NULL; + PKIX_List *firstPermittedList = NULL; + PKIX_List *secondPermittedList = NULL; + PKIX_List *firstExcludedList = NULL; + PKIX_List *secondExcludedList = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult = PKIX_FALSE; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertNameConstraints */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTNAMECONSTRAINTS); + + firstNC = (PKIX_PL_CertNameConstraints *)firstObject; + secondNC = (PKIX_PL_CertNameConstraints *)secondObject; + + /* + * Since we know firstObject is a CertNameConstraints, if both + * references are identical, they must be equal + */ + if (firstNC == secondNC){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondNC isn't a CertNameConstraints, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + + PKIX_CHECK(PKIX_PL_Object_GetType + ((PKIX_PL_Object *)secondNC, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + + if (secondType != PKIX_CERTNAMECONSTRAINTS_TYPE) { + goto cleanup; + } + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (firstNC, &firstPermittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (secondNC, &secondPermittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_EQUALS + (firstPermittedList, secondPermittedList, &cmpResult, plContext, + PKIX_OBJECTEQUALSFAILED); + + if (cmpResult != PKIX_TRUE) { + goto cleanup; + } + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (firstNC, &firstExcludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (secondNC, &secondExcludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_EQUALS + (firstExcludedList, secondExcludedList, &cmpResult, plContext, + PKIX_OBJECTEQUALSFAILED); + + if (cmpResult != PKIX_TRUE) { + goto cleanup; + } + + /* + * numNssNameConstraints is not checked because it is basically a + * merge count, it cannot determine the data equality. + */ + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_DECREF(firstPermittedList); + PKIX_DECREF(secondPermittedList); + PKIX_DECREF(firstExcludedList); + PKIX_DECREF(secondExcludedList); + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTNAMECONSTRAINTS_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_CertNameConstraints_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_RegisterSelf"); + + entry.description = "CertNameConstraints"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertNameConstraints); + entry.destructor = pkix_pl_CertNameConstraints_Destroy; + entry.equalsFunction = pkix_pl_CertNameConstraints_Equals; + entry.hashcodeFunction = pkix_pl_CertNameConstraints_Hashcode; + entry.toStringFunction = pkix_pl_CertNameConstraints_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTNAMECONSTRAINTS_TYPE] = entry; + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Create_Helper + * + * DESCRIPTION: + * This function retrieves name constraints in "nssNameConstraints", + * converts and stores the result in a PKIX_PL_CertNameConstraints object. + * + * PARAMETERS + * "nssNameConstraints" + * Address of CERTNameConstraints that contains this object's data. + * Must be non-NULL. + * "pNameConstraints" + * Address where object pointer will be stored. Must be non-NULL. + * A NULL value will be returned if there is no Name Constraints extension. + * "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 NameConstraints 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_CertNameConstraints_Create_Helper( + CERTNameConstraints *nssNameConstraints, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints **nssNameConstraintPtr = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_Create_Helper"); + PKIX_NULLCHECK_TWO(nssNameConstraints, pNameConstraints); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTNAMECONSTRAINTS_TYPE, + sizeof (PKIX_PL_CertNameConstraints), + (PKIX_PL_Object **)&nameConstraints, + plContext), + PKIX_COULDNOTCREATECERTNAMECONSTRAINTSOBJECT); + + PKIX_CHECK(PKIX_PL_Malloc + (sizeof (CERTNameConstraint *), + (void *)&nssNameConstraintPtr, + plContext), + PKIX_MALLOCFAILED); + + nameConstraints->numNssNameConstraints = 1; + nameConstraints->nssNameConstraintsList = nssNameConstraintPtr; + *nssNameConstraintPtr = nssNameConstraints; + + nameConstraints->permittedList = NULL; + nameConstraints->excludedList = NULL; + nameConstraints->arena = NULL; + + *pNameConstraints = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(nameConstraints); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Create + * + * DESCRIPTION: + * function that allocates and initialize the object CertNameConstraints. + * + * PARAMETERS + * "nssCert" + * Address of CERT that contains this object's data. + * Must be non-NULL. + * "pNameConstraints" + * Address where object pointer will be stored. Must be non-NULL. + * A NULL value will be returned if there is no Name Constraints extension. + * "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 NameConstraints 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_CertNameConstraints_Create( + CERTCertificate *nssCert, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + PLArenaPool *arena = NULL; + SECStatus status; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Create"); + PKIX_NULLCHECK_THREE(nssCert, pNameConstraints, nssCert->arena); + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_FindNameConstraintsExten\n"); + status = CERT_FindNameConstraintsExten + (arena, nssCert, &nssNameConstraints); + + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DECODINGCERTNAMECONSTRAINTSFAILED); + } + + if (nssNameConstraints == NULL) { + *pNameConstraints = NULL; + /* we free the arnea here because PKIX_ERROR_RECEIVED + * may not be set. Setting arena to NULL makes sure + * we don't try to free it again (and makes scanners + * happy). */ + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + arena = NULL; + } + goto cleanup; + } + + PKIX_CHECK(pkix_pl_CertNameConstraints_Create_Helper + (nssNameConstraints, &nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEHELPERFAILED); + + nameConstraints->arena = arena; + + *pNameConstraints = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_CreateByMerge + * + * DESCRIPTION: + * + * This function allocates and creates a PKIX_PL_NameConstraint object + * for merging. It also allocates CERTNameConstraints data space for the + * merged NSS NameConstraints data. + * + * PARAMETERS + * "pNameConstraints" + * Address where object pointer will be stored and 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 NameConstraints 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_CertNameConstraints_CreateByMerge( + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_CreateByMerge"); + PKIX_NULLCHECK_ONE(pNameConstraints); + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_ArenaZNew).\n"); + nssNameConstraints = PORT_ArenaZNew(arena, CERTNameConstraints); + if (nssNameConstraints == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + nssNameConstraints->permited = NULL; + nssNameConstraints->excluded = NULL; + nssNameConstraints->DERPermited = NULL; + nssNameConstraints->DERExcluded = NULL; + + PKIX_CHECK(pkix_pl_CertNameConstraints_Create_Helper + (nssNameConstraints, &nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEHELPERFAILED); + + nameConstraints->arena = arena; + + *pNameConstraints = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_CopyNssNameConstraints + * + * DESCRIPTION: + * + * This function allocates and copies data to a NSS CERTNameConstraints from + * the NameConstraints given by "srcNC" and stores the result at "pDestNC". It + * copies items on both the permitted and excluded lists, but not the + * DERPermited and DERExcluded. + * + * PARAMETERS + * "arena" + * Memory pool where object data is allocated from. Must be non-NULL. + * "srcNC" + * Address of the NameConstraints to copy from. Must be non-NULL. + * "pDestNC" + * Address where new copied object is stored and 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 NameConstraints 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_CertNameConstraints_CopyNssNameConstraints( + PLArenaPool *arena, + CERTNameConstraints *srcNC, + CERTNameConstraints **pDestNC, + void *plContext) +{ + CERTNameConstraints *nssNameConstraints = NULL; + CERTNameConstraint *nssNameConstraintHead = NULL; + CERTNameConstraint *nssCurrent = NULL; + CERTNameConstraint *nssCopyTo = NULL; + CERTNameConstraint *nssCopyFrom = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_CopyNssNameConstraints"); + PKIX_NULLCHECK_THREE(arena, srcNC, pDestNC); + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_ArenaZNew).\n"); + nssNameConstraints = PORT_ArenaZNew(arena, CERTNameConstraints); + if (nssNameConstraints == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + if (srcNC->permited) { + + nssCopyFrom = srcNC->permited; + + do { + + nssCopyTo = NULL; + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CopyNameConstraint).\n"); + nssCopyTo = CERT_CopyNameConstraint + (arena, nssCopyTo, nssCopyFrom); + if (nssCopyTo == NULL) { + PKIX_ERROR(PKIX_CERTCOPYNAMECONSTRAINTFAILED); + } + if (nssCurrent == NULL) { + nssCurrent = nssNameConstraintHead = nssCopyTo; + } else { + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_AddNameConstraint).\n"); + nssCurrent = CERT_AddNameConstraint + (nssCurrent, nssCopyTo); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstrain).\n"); + nssCopyFrom = CERT_GetNextNameConstraint(nssCopyFrom); + + } while (nssCopyFrom != srcNC->permited); + + nssNameConstraints->permited = nssNameConstraintHead; + } + + if (srcNC->excluded) { + + nssCurrent = NULL; + nssCopyFrom = srcNC->excluded; + + do { + + /* + * Cannot use CERT_DupGeneralNameList, which just increments + * refcount. We need our own copy since arena is for each + * PKIX_PL_NameConstraints. Perhaps contribute this code + * as CERT_CopyGeneralNameList (in the future). + */ + nssCopyTo = NULL; + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CopyNameConstraint).\n"); + nssCopyTo = CERT_CopyNameConstraint + (arena, nssCopyTo, nssCopyFrom); + if (nssCopyTo == NULL) { + PKIX_ERROR(PKIX_CERTCOPYNAMECONSTRAINTFAILED); + } + if (nssCurrent == NULL) { + nssCurrent = nssNameConstraintHead = nssCopyTo; + } else { + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_AddNameConstraint).\n"); + nssCurrent = CERT_AddNameConstraint + (nssCurrent, nssCopyTo); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstrain).\n"); + nssCopyFrom = CERT_GetNextNameConstraint(nssCopyFrom); + + } while (nssCopyFrom != srcNC->excluded); + + nssNameConstraints->excluded = nssNameConstraintHead; + } + + *pDestNC = nssNameConstraints; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Merge + * + * DESCRIPTION: + * + * This function merges two NameConstraints pointed to by "firstNC" and + * "secondNC" and stores the result in "pMergedNC". + * + * PARAMETERS + * "firstNC" + * Address of the first NameConstraints to be merged. Must be non-NULL. + * "secondNC" + * Address of the second NameConstraints to be merged. Must be non-NULL. + * "pMergedNC" + * Address where the merge result is stored and 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 NameConstraints 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_CertNameConstraints_Merge( + PKIX_PL_CertNameConstraints *firstNC, + PKIX_PL_CertNameConstraints *secondNC, + PKIX_PL_CertNameConstraints **pMergedNC, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints **nssNCto = NULL; + CERTNameConstraints **nssNCfrom = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + PKIX_UInt32 numNssItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Merge"); + PKIX_NULLCHECK_THREE(firstNC, secondNC, pMergedNC); + + PKIX_CHECK(pkix_pl_CertNameConstraints_CreateByMerge + (&nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEBYMERGEFAILED); + + /* Merge NSSCertConstraint lists */ + + numNssItems = firstNC->numNssNameConstraints + + secondNC->numNssNameConstraints; + + /* Free the default space (only one entry) allocated by create */ + PKIX_CHECK(PKIX_PL_Free + (nameConstraints->nssNameConstraintsList, plContext), + PKIX_FREEFAILED); + + /* Reallocate the size we need */ + PKIX_CHECK(PKIX_PL_Malloc + (numNssItems * sizeof (CERTNameConstraint *), + (void *)&nssNCto, + plContext), + PKIX_MALLOCFAILED); + + nameConstraints->nssNameConstraintsList = nssNCto; + + nssNCfrom = firstNC->nssNameConstraintsList; + + for (i = 0; i < firstNC->numNssNameConstraints; i++) { + + PKIX_CHECK(pkix_pl_CertNameConstraints_CopyNssNameConstraints + (nameConstraints->arena, + *nssNCfrom, + &nssNameConstraints, + plContext), + PKIX_CERTNAMECONSTRAINTSCOPYNSSNAMECONSTRAINTSFAILED); + + *nssNCto = nssNameConstraints; + + nssNCto++; + nssNCfrom++; + } + + nssNCfrom = secondNC->nssNameConstraintsList; + + for (i = 0; i < secondNC->numNssNameConstraints; i++) { + + PKIX_CHECK(pkix_pl_CertNameConstraints_CopyNssNameConstraints + (nameConstraints->arena, + *nssNCfrom, + &nssNameConstraints, + plContext), + PKIX_CERTNAMECONSTRAINTSCOPYNSSNAMECONSTRAINTSFAILED); + + *nssNCto = nssNameConstraints; + + nssNCto++; + nssNCfrom++; + } + + nameConstraints->numNssNameConstraints = numNssItems; + nameConstraints->permittedList = NULL; + nameConstraints->excludedList = NULL; + + *pMergedNC = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(nameConstraints); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* --Public-NameConstraints-Functions-------------------------------- */ + +/* + * FUNCTION: PKIX_PL_CertNameConstraints_CheckNamesInNameSpace + * (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_CertNameConstraints_CheckNamesInNameSpace( + PKIX_List *nameList, /* List of PKIX_PL_GeneralName */ + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext) +{ + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + CERTGeneralName *nssMatchName = NULL; + PLArenaPool *arena = NULL; + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 numNameItems = 0; + PKIX_UInt32 numNCItems = 0; + PKIX_UInt32 i, j; + SECStatus status = SECSuccess; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "PKIX_PL_CertNameConstraints_CheckNamesInNameSpace"); + PKIX_NULLCHECK_TWO(nameConstraints, pCheckPass); + + *pCheckPass = PKIX_TRUE; + + if (nameList != NULL) { + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + nssNameConstraintsList = + nameConstraints->nssNameConstraintsList; + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + numNCItems = nameConstraints->numNssNameConstraints; + + PKIX_CHECK(PKIX_List_GetLength + (nameList, &numNameItems, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (i = 0; i < numNameItems; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (nameList, + i, + (PKIX_PL_Object **) &name, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_pl_GeneralName_GetNssGeneralName + (name, &nssMatchName, plContext), + PKIX_GENERALNAMEGETNSSGENERALNAMEFAILED); + + PKIX_DECREF(name); + + for (j = 0; j < numNCItems; j++) { + + nssNameConstraints = *(nssNameConstraintsList + j); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CheckNameSpace\n"); + status = CERT_CheckNameSpace + (arena, nssNameConstraints, nssMatchName); + if (status != SECSuccess) { + break; + } + + } + + if (status != SECSuccess) { + break; + } + + } + } + + if (status == SECFailure) { + *pCheckPass = PKIX_FALSE; + } + +cleanup: + + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h new file mode 100644 index 0000000000..2f305ac10a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_nameconstraints.h + * + * Name Constraints Object Definitions + * + */ + +#ifndef _PKIX_PL_NAMECONSTRAINTS_H +#define _PKIX_PL_NAMECONSTRAINTS_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_CertNameConstraintsStruct { + PLArenaPool *arena; + CERTNameConstraints **nssNameConstraintsList; + PKIX_UInt32 numNssNameConstraints; + PKIX_List *permittedList; /* list of PKIX_PL_GeneralName */ + PKIX_List *excludedList; /* list of PKIX_PL_GeneralName */ +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_CertNameConstraints_RegisterSelf(void *plContext); + +PKIX_Error *pkix_pl_CertNameConstraints_Create( + CERTCertificate *nssCert, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext); + +PKIX_Error * +pkix_pl_CertNameConstraints_CreateWithNames( + PKIX_List *names, /* List of PKIX_PL_GeneralName */ + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext); + +PKIX_Error * +pkix_pl_CertNameConstraints_CheckNameSpaceNssNames( + CERTGeneralName *nssSubjectNames, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext); + +PKIX_Error * +pkix_pl_CertNameConstraints_CheckNameSpacePkixNames( + PKIX_List *nameList, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext); + + +PKIX_Error *pkix_pl_CertNameConstraints_Merge( + PKIX_PL_CertNameConstraints *firstNC, + PKIX_PL_CertNameConstraints *secondNC, + PKIX_PL_CertNameConstraints **pMergedNC, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_NAMECONSTRAINTS_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c new file mode 100644 index 0000000000..679811dec1 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c @@ -0,0 +1,251 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ocspcertid.c + * + * Certificate ID Object for OCSP + * + */ + +#include "pkix_pl_ocspcertid.h" + +/* --Private-Cert-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspCertID_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspCertID_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_OcspCertID *certID = NULL; + + PKIX_ENTER(OCSPCERTID, "pkix_pl_OcspCertID_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPCERTID_TYPE, plContext), + PKIX_OBJECTNOTOCSPCERTID); + + certID = (PKIX_PL_OcspCertID *)object; + + if (certID->certID) { + CERT_DestroyOCSPCertID(certID->certID); + } + +cleanup: + + PKIX_RETURN(OCSPCERTID); +} + +/* + * FUNCTION: pkix_pl_OcspCertID_RegisterSelf + * DESCRIPTION: + * Registers PKIX_PUBLICKEY_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_OcspCertID_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(OCSPCERTID, "pkix_pl_OcspCertID_RegisterSelf"); + + entry.description = "OcspCertID"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_OcspCertID); + entry.destructor = pkix_pl_OcspCertID_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + systemClasses[PKIX_OCSPCERTID_TYPE] = entry; + + PKIX_RETURN(OCSPCERTID); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_OcspCertID_Create + * DESCRIPTION: + * + * This function creates an OcspCertID for a given certificate, + * to be used with OCSP transactions. + * + * If a Date is provided in "validity" it may be used in the search for the + * issuer of "cert" but has no effect on the request itself. + * + * PARAMETERS: + * "cert" + * Address of the Cert for which an OcspCertID is to be created. Must be + * non-NULL. + * "validity" + * Address of the Date for which the Cert's validity is to be determined. + * May be NULL. + * "object" + * 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 an OcspCertID 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_OcspCertID_Create( + PKIX_PL_Cert *cert, + PKIX_PL_Date *validity, + PKIX_PL_OcspCertID **object, + void *plContext) +{ + PKIX_PL_OcspCertID *cid = NULL; + PRTime time = 0; + + PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_Create"); + PKIX_NULLCHECK_TWO(cert, object); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OCSPCERTID_TYPE, + sizeof (PKIX_PL_OcspCertID), + (PKIX_PL_Object **)&cid, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + if (validity != NULL) { + PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + } else { + time = PR_Now(); + } + + cid->certID = CERT_CreateOCSPCertID(cert->nssCert, time); + if (!cid->certID) { + PKIX_ERROR(PKIX_COULDNOTCREATEOBJECT); + } + + *object = cid; + cid = NULL; +cleanup: + PKIX_DECREF(cid); + PKIX_RETURN(OCSPCERTID); +} + +/* + * FUNCTION: PKIX_PL_OcspCertID_GetFreshCacheStatus + * DESCRIPTION: + * + * This function may return cached OCSP results for the provided + * certificate, but only if stored information is still considered to be + * fresh. + * + * PARAMETERS + * "cid" + * A certificate ID as used by OCSP + * "validity" + * Optional date parameter to request validity for a specifc time. + * "hasFreshStatus" + * Output parameter, if the function successed to find fresh cached + * information, this will be set to true. Must be non-NULL. + * "statusIsGood" + * The good/bad result stored in the cache. Must be non-NULL. + * "missingResponseError" + * If OCSP status is "bad", this variable may indicate the exact + * reason why the previous OCSP request had failed. + * "plContext" + * Platform-specific context pointer. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OcspCertID 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_OcspCertID_GetFreshCacheStatus( + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_Boolean *hasFreshStatus, + PKIX_Boolean *statusIsGood, + SECErrorCodes *missingResponseError, + void *plContext) +{ + PRTime time = 0; + SECStatus rv; + SECStatus rvOcsp; + OCSPFreshness freshness; + + PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_GetFreshCacheStatus"); + PKIX_NULLCHECK_THREE(cid, hasFreshStatus, statusIsGood); + + if (validity != NULL) { + PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + } else { + time = PR_Now(); + } + + rv = ocsp_GetCachedOCSPResponseStatus( + cid->certID, time, PR_TRUE, /*ignoreGlobalOcspFailureSetting*/ + &rvOcsp, missingResponseError, &freshness); + + *hasFreshStatus = (rv == SECSuccess && freshness == ocspFresh); + if (*hasFreshStatus) { + *statusIsGood = (rvOcsp == SECSuccess); + } +cleanup: + PKIX_RETURN(OCSPCERTID); +} + +/* + * FUNCTION: PKIX_PL_OcspCertID_RememberOCSPProcessingFailure + * DESCRIPTION: + * + * Information about the current failure associated to the given certID + * will be remembered in the cache, potentially allowing future calls + * to prevent repetitive OCSP requests. + * After this function got called, it may no longer be safe to + * use the provided cid parameter, because ownership might have been + * transfered to the cache. This status will be recorded inside the + * cid object. + * + * PARAMETERS + * "cid" + * The certificate ID associated to a failed OCSP processing. + * "plContext" + * Platform-specific context pointer. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OcspCertID 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_OcspCertID_RememberOCSPProcessingFailure( + PKIX_PL_OcspCertID *cid, + void *plContext) +{ + PRBool certIDWasConsumed = PR_FALSE; + + PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_RememberOCSPProcessingFailure"); + PKIX_NULLCHECK_TWO(cid, cid->certID); + + cert_RememberOCSPProcessingFailure(cid->certID, &certIDWasConsumed); + + if (certIDWasConsumed) { + cid->certID = NULL; + } + + PKIX_RETURN(OCSPCERTID); +} + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h new file mode 100644 index 0000000000..772a12b25f --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ocspcertid.h + * + * Public Key Object Definitions + * + */ + +#ifndef _PKIX_PL_OCSPCERTID_H +#define _PKIX_PL_OCSPCERTID_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_OcspCertIDStruct { + CERTOCSPCertID *certID; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_OcspCertID_RegisterSelf(void *plContext); + +PKIX_Error * +PKIX_PL_OcspCertID_Create( + PKIX_PL_Cert *cert, + PKIX_PL_Date *validity, + PKIX_PL_OcspCertID **object, + void *plContext); + +PKIX_Error * +PKIX_PL_OcspCertID_GetFreshCacheStatus( + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_Boolean *hasFreshStatus, + PKIX_Boolean *statusIsGood, + SECErrorCodes *missingResponseError, + void *plContext); + +PKIX_Error * +PKIX_PL_OcspCertID_RememberOCSPProcessingFailure( + PKIX_PL_OcspCertID *cid, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OCSPCERTID_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c new file mode 100644 index 0000000000..28b6953a76 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c @@ -0,0 +1,441 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ocsprequest.c + * + */ + +#include "pkix_pl_ocsprequest.h" + +/* --Private-OcspRequest-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspRequest_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspRequest_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_OcspRequest *ocspReq = NULL; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), + PKIX_OBJECTNOTOCSPREQUEST); + + ocspReq = (PKIX_PL_OcspRequest *)object; + + if (ocspReq->decoded != NULL) { + CERT_DestroyOCSPRequest(ocspReq->decoded); + } + + if (ocspReq->encoded != NULL) { + SECITEM_FreeItem(ocspReq->encoded, PR_TRUE); + } + + if (ocspReq->location != NULL) { + PORT_Free(ocspReq->location); + } + + PKIX_DECREF(ocspReq->cert); + PKIX_DECREF(ocspReq->validity); + PKIX_DECREF(ocspReq->signerCert); + +cleanup: + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspRequest_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_UInt32 certHash = 0; + PKIX_UInt32 dateHash = 0; + PKIX_UInt32 extensionHash = 0; + PKIX_UInt32 signerHash = 0; + PKIX_PL_OcspRequest *ocspRq = NULL; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), + PKIX_OBJECTNOTOCSPREQUEST); + + ocspRq = (PKIX_PL_OcspRequest *)object; + + *pHashcode = 0; + + PKIX_HASHCODE(ocspRq->cert, &certHash, plContext, + PKIX_CERTHASHCODEFAILED); + + PKIX_HASHCODE(ocspRq->validity, &dateHash, plContext, + PKIX_DATEHASHCODEFAILED); + + if (ocspRq->addServiceLocator == PKIX_TRUE) { + extensionHash = 0xff; + } + + PKIX_HASHCODE(ocspRq->signerCert, &signerHash, plContext, + PKIX_CERTHASHCODEFAILED); + + *pHashcode = (((((extensionHash << 8) | certHash) << 8) | + dateHash) << 8) | signerHash; + +cleanup: + + PKIX_RETURN(OCSPREQUEST); + +} + +/* + * FUNCTION: pkix_pl_OcspRequest_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspRequest_Equals( + PKIX_PL_Object *firstObj, + PKIX_PL_Object *secondObj, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_Boolean match = PKIX_FALSE; + PKIX_UInt32 secondType = 0; + PKIX_PL_OcspRequest *firstReq = NULL; + PKIX_PL_OcspRequest *secondReq = NULL; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Equals"); + PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); + + /* test that firstObj is a OcspRequest */ + PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPREQUEST_TYPE, plContext), + PKIX_FIRSTOBJARGUMENTNOTOCSPREQUEST); + + /* + * Since we know firstObj is a OcspRequest, if both references are + * identical, they must be equal + */ + if (firstObj == secondObj){ + match = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObj isn't a OcspRequest, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObj, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_OCSPREQUEST_TYPE) { + goto cleanup; + } + + firstReq = (PKIX_PL_OcspRequest *)firstObj; + secondReq = (PKIX_PL_OcspRequest *)secondObj; + + if (firstReq->addServiceLocator != secondReq->addServiceLocator) { + goto cleanup; + } + + PKIX_EQUALS(firstReq->cert, secondReq->cert, &match, plContext, + PKIX_CERTEQUALSFAILED); + + if (match == PKIX_FALSE) { + goto cleanup; + } + + PKIX_EQUALS(firstReq->validity, secondReq->validity, &match, plContext, + PKIX_DATEEQUALSFAILED); + + if (match == PKIX_FALSE) { + goto cleanup; + } + + PKIX_EQUALS + (firstReq->signerCert, secondReq->signerCert, &match, plContext, + PKIX_CERTEQUALSFAILED); + +cleanup: + + *pResult = match; + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OCSPREQUEST_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_OcspRequest_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_RegisterSelf"); + + entry.description = "OcspRequest"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_OcspRequest); + entry.destructor = pkix_pl_OcspRequest_Destroy; + entry.equalsFunction = pkix_pl_OcspRequest_Equals; + entry.hashcodeFunction = pkix_pl_OcspRequest_Hashcode; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_OCSPREQUEST_TYPE] = entry; + + PKIX_RETURN(OCSPREQUEST); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspRequest_Create + * DESCRIPTION: + * + * This function creates an OcspRequest to be used in validating the Cert + * pointed to by "cert" and storing the result at "pRequest". If a URI + * is found for an OCSP responder, PKIX_TRUE is stored at "pURIFound". If no + * URI is found, PKIX_FALSE is stored. + * + * If a Date is provided in "validity" it may be used in the search for the + * issuer of "cert" but has no effect on the request itself. If + * "addServiceLocator" is TRUE, the AddServiceLocator extension will be + * included in the Request. If "signerCert" is provided it will be used to sign + * the Request. (Note: this signed request feature is not currently supported.) + * + * PARAMETERS: + * "cert" + * Address of the Cert for which an OcspRequest is to be created. Must be + * non-NULL. + * "validity" + * Address of the Date for which the Cert's validity is to be determined. + * May be NULL. + * "signerCert" + * Address of the Cert to be used, if present, in signing the request. + * May be NULL. + * "pRequest" + * 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 an OcspRequest 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_OcspRequest_Create( + PKIX_PL_Cert *cert, + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_PL_Cert *signerCert, + PKIX_UInt32 methodFlags, + PKIX_Boolean *pURIFound, + PKIX_PL_OcspRequest **pRequest, + void *plContext) +{ + PKIX_PL_OcspRequest *ocspRequest = NULL; + + CERTCertDBHandle *handle = NULL; + SECStatus rv = SECFailure; + SECItem *encoding = NULL; + CERTOCSPRequest *certRequest = NULL; + PRTime time = 0; + PRBool addServiceLocatorExtension = PR_FALSE; + CERTCertificate *nssCert = NULL; + CERTCertificate *nssSignerCert = NULL; + char *location = NULL; + PRErrorCode locError = 0; + PKIX_Boolean canUseDefaultSource = PKIX_FALSE; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Create"); + PKIX_NULLCHECK_TWO(cert, pRequest); + + /* create a PKIX_PL_OcspRequest object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OCSPREQUEST_TYPE, + sizeof (PKIX_PL_OcspRequest), + (PKIX_PL_Object **)&ocspRequest, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + PKIX_INCREF(cert); + ocspRequest->cert = cert; + + PKIX_INCREF(validity); + ocspRequest->validity = validity; + + PKIX_INCREF(signerCert); + ocspRequest->signerCert = signerCert; + + ocspRequest->decoded = NULL; + ocspRequest->encoded = NULL; + + ocspRequest->location = NULL; + + nssCert = cert->nssCert; + + /* + * Does this Cert have an Authority Information Access extension with + * the URI of an OCSP responder? + */ + handle = CERT_GetDefaultCertDB(); + + if (!(methodFlags & PKIX_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE)) { + canUseDefaultSource = PKIX_TRUE; + } + location = ocsp_GetResponderLocation(handle, nssCert, + canUseDefaultSource, + &addServiceLocatorExtension); + if (location == NULL) { + locError = PORT_GetError(); + if (locError == SEC_ERROR_EXTENSION_NOT_FOUND || + locError == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) { + PORT_SetError(0); + *pURIFound = PKIX_FALSE; + goto cleanup; + } + PKIX_ERROR(PKIX_ERRORFINDINGORPROCESSINGURI); + } + + ocspRequest->location = location; + *pURIFound = PKIX_TRUE; + + if (signerCert != NULL) { + nssSignerCert = signerCert->nssCert; + } + + if (validity != NULL) { + PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + } else { + time = PR_Now(); + } + + certRequest = cert_CreateSingleCertOCSPRequest( + cid->certID, cert->nssCert, time, + addServiceLocatorExtension, nssSignerCert); + + ocspRequest->decoded = certRequest; + + if (certRequest == NULL) { + PKIX_ERROR(PKIX_UNABLETOCREATECERTOCSPREQUEST); + } + + rv = CERT_AddOCSPAcceptableResponses( + certRequest, SEC_OID_PKIX_OCSP_BASIC_RESPONSE); + + if (rv == SECFailure) { + PKIX_ERROR(PKIX_UNABLETOADDACCEPTABLERESPONSESTOREQUEST); + } + + encoding = CERT_EncodeOCSPRequest(NULL, certRequest, NULL); + + ocspRequest->encoded = encoding; + + *pRequest = ocspRequest; + ocspRequest = NULL; + +cleanup: + PKIX_DECREF(ocspRequest); + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_GetEncoded + * DESCRIPTION: + * + * This function obtains the encoded message from the OcspRequest pointed to + * by "request", storing the result at "pRequest". + * + * PARAMETERS + * "request" + * The address of the OcspRequest whose encoded message is to be + * retrieved. Must be non-NULL. + * "pRequest" + * 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 a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_OcspRequest_GetEncoded( + PKIX_PL_OcspRequest *request, + SECItem **pRequest, + void *plContext) +{ + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetEncoded"); + PKIX_NULLCHECK_TWO(request, pRequest); + + *pRequest = request->encoded; + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_GetLocation + * DESCRIPTION: + * + * This function obtains the location from the OcspRequest pointed to + * by "request", storing the result at "pLocation". + * + * PARAMETERS + * "request" + * The address of the OcspRequest whose encoded message is to be + * retrieved. Must be non-NULL. + * "pLocation" + * The address at which is stored the address of the location. 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_OcspRequest_GetLocation( + PKIX_PL_OcspRequest *request, + char **pLocation, + void *plContext) +{ + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetLocation"); + PKIX_NULLCHECK_TWO(request, pLocation); + + *pLocation = request->location; + + PKIX_RETURN(OCSPREQUEST); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h new file mode 100644 index 0000000000..fa79266eec --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ocsprequest.h + * + * OcspRequest Object Definitions + * + */ + +#ifndef _PKIX_PL_OCSPREQUEST_H +#define _PKIX_PL_OCSPREQUEST_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_OcspRequestStruct{ + PKIX_PL_Cert *cert; + PKIX_PL_Date *validity; + PKIX_Boolean addServiceLocator; + PKIX_PL_Cert *signerCert; + CERTOCSPRequest *decoded; + SECItem *encoded; + char *location; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_OcspRequest_Create( + PKIX_PL_Cert *cert, + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_PL_Cert *signerCert, + PKIX_UInt32 methodFlags, + PKIX_Boolean *pURIFound, + PKIX_PL_OcspRequest **pRequest, + void *plContext); + +PKIX_Error * +pkix_pl_OcspRequest_GetEncoded( + PKIX_PL_OcspRequest *request, + SECItem **pRequest, + void *plContext); + +PKIX_Error * +pkix_pl_OcspRequest_GetLocation( + PKIX_PL_OcspRequest *request, + char **pLocation, + void *plContext); + +PKIX_Error *pkix_pl_OcspRequest_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OCSPREQUEST_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c new file mode 100644 index 0000000000..fa41f8102e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c @@ -0,0 +1,1069 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ocspresponse.c + * + */ + +#include "pkix_pl_ocspresponse.h" + +/* ----Public functions------------------------------------- */ +/* + * This is the libpkix replacement for CERT_VerifyOCSPResponseSignature. + * It is used if it has been set as the verifyFcn member of ocspChecker. + */ +PKIX_Error * +PKIX_PL_OcspResponse_UseBuildChain( + PKIX_PL_Cert *signerCert, + PKIX_PL_Date *producedAt, + PKIX_ProcessingParams *procParams, + void **pNBIOContext, + void **pState, + PKIX_BuildResult **pBuildResult, + PKIX_VerifyNode **pVerifyTree, + void *plContext) +{ + PKIX_ProcessingParams *caProcParams = NULL; + PKIX_PL_Date *date = NULL; + PKIX_ComCertSelParams *certSelParams = NULL; + PKIX_CertSelector *certSelector = NULL; + void *nbioContext = NULL; + PKIX_Error *buildError = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_OcspResponse_UseBuildChain"); + PKIX_NULLCHECK_THREE(signerCert, producedAt, procParams); + PKIX_NULLCHECK_THREE(pNBIOContext, pState, pBuildResult); + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + /* Are we resuming after a WOULDBLOCK return, or starting anew ? */ + if (nbioContext == NULL) { + /* Starting anew */ + PKIX_CHECK(PKIX_PL_Object_Duplicate + ((PKIX_PL_Object *)procParams, + (PKIX_PL_Object **)&caProcParams, + plContext), + PKIX_OBJECTDUPLICATEFAILED); + + PKIX_CHECK(PKIX_ProcessingParams_SetDate(procParams, date, plContext), + PKIX_PROCESSINGPARAMSSETDATEFAILED); + + /* create CertSelector with target certificate in params */ + + PKIX_CHECK(PKIX_CertSelector_Create + (NULL, NULL, &certSelector, plContext), + PKIX_CERTSELECTORCREATEFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_Create + (&certSelParams, plContext), + PKIX_COMCERTSELPARAMSCREATEFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_SetCertificate + (certSelParams, signerCert, plContext), + PKIX_COMCERTSELPARAMSSETCERTIFICATEFAILED); + + PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams + (certSelector, certSelParams, plContext), + PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED); + + PKIX_CHECK(PKIX_ProcessingParams_SetTargetCertConstraints + (caProcParams, certSelector, plContext), + PKIX_PROCESSINGPARAMSSETTARGETCERTCONSTRAINTSFAILED); + } + + buildError = PKIX_BuildChain + (caProcParams, + &nbioContext, + pState, + pBuildResult, + pVerifyTree, + plContext); + + /* non-null nbioContext means the build would block */ + if (nbioContext != NULL) { + + *pNBIOContext = nbioContext; + + /* no buildResult means the build has failed */ + } else if (buildError) { + pkixErrorResult = buildError; + buildError = NULL; + } else { + PKIX_DECREF(*pState); + } + +cleanup: + + PKIX_DECREF(caProcParams); + PKIX_DECREF(date); + PKIX_DECREF(certSelParams); + PKIX_DECREF(certSelector); + + PKIX_RETURN(OCSPRESPONSE); +} + +/* --Private-OcspResponse-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspResponse_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspResponse_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_OcspResponse *ocspRsp = NULL; + const SEC_HttpClientFcn *httpClient = NULL; + const SEC_HttpClientFcnV1 *hcv1 = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext), + PKIX_OBJECTNOTANOCSPRESPONSE); + + ocspRsp = (PKIX_PL_OcspResponse *)object; + + if (ocspRsp->nssOCSPResponse != NULL) { + CERT_DestroyOCSPResponse(ocspRsp->nssOCSPResponse); + ocspRsp->nssOCSPResponse = NULL; + } + + if (ocspRsp->signerCert != NULL) { + CERT_DestroyCertificate(ocspRsp->signerCert); + ocspRsp->signerCert = NULL; + } + + httpClient = (const SEC_HttpClientFcn *)(ocspRsp->httpClient); + + if (httpClient && (httpClient->version == 1)) { + + hcv1 = &(httpClient->fcnTable.ftable1); + + if (ocspRsp->sessionRequest != NULL) { + (*hcv1->freeFcn)(ocspRsp->sessionRequest); + ocspRsp->sessionRequest = NULL; + } + + if (ocspRsp->serverSession != NULL) { + (*hcv1->freeSessionFcn)(ocspRsp->serverSession); + ocspRsp->serverSession = NULL; + } + } + + if (ocspRsp->arena != NULL) { + PORT_FreeArena(ocspRsp->arena, PR_FALSE); + ocspRsp->arena = NULL; + } + + PKIX_DECREF(ocspRsp->producedAtDate); + PKIX_DECREF(ocspRsp->pkixSignerCert); + PKIX_DECREF(ocspRsp->request); + +cleanup: + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspResponse_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_OcspResponse *ocspRsp = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext), + PKIX_OBJECTNOTANOCSPRESPONSE); + + ocspRsp = (PKIX_PL_OcspResponse *)object; + + if (ocspRsp->encodedResponse->data == NULL) { + *pHashcode = 0; + } else { + PKIX_CHECK(pkix_hash + (ocspRsp->encodedResponse->data, + ocspRsp->encodedResponse->len, + pHashcode, + plContext), + PKIX_HASHFAILED); + } + +cleanup: + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspResponse_Equals( + PKIX_PL_Object *firstObj, + PKIX_PL_Object *secondObj, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType = 0; + PKIX_UInt32 firstLen = 0; + PKIX_UInt32 i = 0; + PKIX_PL_OcspResponse *rsp1 = NULL; + PKIX_PL_OcspResponse *rsp2 = NULL; + const unsigned char *firstData = NULL; + const unsigned char *secondData = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Equals"); + PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); + + /* test that firstObj is a OcspResponse */ + PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPRESPONSE_TYPE, plContext), + PKIX_FIRSTOBJARGUMENTNOTANOCSPRESPONSE); + + /* + * Since we know firstObj is a OcspResponse, if both references are + * identical, they must be equal + */ + if (firstObj == secondObj){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObj isn't a OcspResponse, 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_OCSPRESPONSE_TYPE) { + goto cleanup; + } + + rsp1 = (PKIX_PL_OcspResponse *)firstObj; + rsp2 = (PKIX_PL_OcspResponse *)secondObj; + + /* If either lacks an encoded string, they cannot be compared */ + firstData = (const unsigned char *)rsp1->encodedResponse->data; + secondData = (const unsigned char *)rsp2->encodedResponse->data; + if ((firstData == NULL) || (secondData == NULL)) { + goto cleanup; + } + + firstLen = rsp1->encodedResponse->len; + + if (firstLen != rsp2->encodedResponse->len) { + goto cleanup; + } + + for (i = 0; i < firstLen; i++) { + if (*firstData++ != *secondData++) { + goto cleanup; + } + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OCSPRESPONSE_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_OcspResponse_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_OCSPRESPONSE_TYPE]; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_RegisterSelf"); + + entry->description = "OcspResponse"; + entry->typeObjectSize = sizeof(PKIX_PL_OcspResponse); + entry->destructor = pkix_pl_OcspResponse_Destroy; + entry->equalsFunction = pkix_pl_OcspResponse_Equals; + entry->hashcodeFunction = pkix_pl_OcspResponse_Hashcode; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(OCSPRESPONSE); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspResponse_Create + * DESCRIPTION: + * + * This function transmits the OcspRequest pointed to by "request" and obtains + * an OcspResponse, which it stores at "pOcspResponse". If the HTTPClient + * supports non-blocking I/O this function may store a non-NULL value at + * "pNBIOContext" (the WOULDBLOCK condition). In that case the caller should + * make a subsequent call with the same value in "pNBIOContext" and + * "pOcspResponse" to resume the operation. Additional WOULDBLOCK returns may + * occur; the caller should persist until a return occurs with NULL stored at + * "pNBIOContext". + * + * If a SEC_HttpClientFcn "responder" is supplied, it is used as the client + * to which the OCSP query is sent. If none is supplied, the default responder + * is used. + * + * If an OcspResponse_VerifyCallback "verifyFcn" is supplied, it is used to + * verify the Cert received from the responder as the signer. If none is + * supplied, the default verification function is used. + * + * The contents of "request" are ignored on calls subsequent to a WOULDBLOCK + * return, and the caller is permitted to supply NULL. + * + * PARAMETERS + * "request" + * Address of the OcspRequest for which a response is desired. + * "httpMethod" + * GET or POST + * "responder" + * Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP + * query. + * "verifyFcn" + * Address, if non-NULL, of the OcspResponse_VerifyCallback function to be + * used to verify the Cert of the OCSP responder. + * "pNBIOContext" + * Address at which platform-dependent information is stored for handling + * of non-blocking I/O. Must be non-NULL. + * "pOcspResponse" + * The address where the created OcspResponse is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OcspResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_OcspResponse_Create( + PKIX_PL_OcspRequest *request, + const char *httpMethod, + void *responder, + PKIX_PL_VerifyCallback verifyFcn, + void **pNBIOContext, + PKIX_PL_OcspResponse **pResponse, + void *plContext) +{ + void *nbioContext = NULL; + PKIX_PL_OcspResponse *ocspResponse = NULL; + const SEC_HttpClientFcn *httpClient = NULL; + const SEC_HttpClientFcnV1 *hcv1 = NULL; + SECStatus rv = SECFailure; + char *location = NULL; + char *hostname = NULL; + char *path = NULL; + char *responseContentType = NULL; + PRUint16 port = 0; + SEC_HTTP_SERVER_SESSION serverSession = NULL; + SEC_HTTP_REQUEST_SESSION sessionRequest = NULL; + SECItem *encodedRequest = NULL; + PRUint16 responseCode = 0; + char *responseData = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create"); + PKIX_NULLCHECK_TWO(pNBIOContext, pResponse); + + if (!strcmp(httpMethod, "GET") && !strcmp(httpMethod, "POST")) { + PKIX_ERROR(PKIX_INVALIDOCSPHTTPMETHOD); + } + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + if (nbioContext != NULL) { + + ocspResponse = *pResponse; + PKIX_NULLCHECK_ONE(ocspResponse); + + httpClient = ocspResponse->httpClient; + serverSession = ocspResponse->serverSession; + sessionRequest = ocspResponse->sessionRequest; + PKIX_NULLCHECK_THREE(httpClient, serverSession, sessionRequest); + + } else { + PKIX_UInt32 timeout = + ((PKIX_PL_NssContext*)plContext)->timeoutSeconds; + + PKIX_NULLCHECK_ONE(request); + + PKIX_CHECK(pkix_pl_OcspRequest_GetEncoded + (request, &encodedRequest, plContext), + PKIX_OCSPREQUESTGETENCODEDFAILED); + + /* prepare initial message to HTTPClient */ + + /* Is there a default responder and is it enabled? */ + if (responder) { + httpClient = (const SEC_HttpClientFcn *)responder; + } else { + httpClient = SEC_GetRegisteredHttpClient(); + } + + if (httpClient && (httpClient->version == 1)) { + char *fullGetPath = NULL; + const char *sessionPath = NULL; + PRBool usePOST = !strcmp(httpMethod, "POST"); + + hcv1 = &(httpClient->fcnTable.ftable1); + + PKIX_CHECK(pkix_pl_OcspRequest_GetLocation + (request, &location, plContext), + PKIX_OCSPREQUESTGETLOCATIONFAILED); + + /* parse location -> hostname, port, path */ + rv = CERT_ParseURL(location, &hostname, &port, &path); + if (rv == SECFailure || hostname == NULL || path == NULL) { + PKIX_ERROR(PKIX_URLPARSINGFAILED); + } + + rv = (*hcv1->createSessionFcn)(hostname, port, + &serverSession); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + + if (usePOST) { + sessionPath = path; + } else { + /* calculate, are we allowed to use GET? */ + enum { max_get_request_size = 255 }; /* defined by RFC2560 */ + char b64ReqBuf[max_get_request_size+1]; + size_t base64size; + size_t slashLengthIfNeeded = 0; + size_t pathLength; + PRInt32 urlEncodedBufLength; + size_t getURLLength; + char *walkOutput = NULL; + + pathLength = strlen(path); + if (path[pathLength-1] != '/') { + slashLengthIfNeeded = 1; + } + base64size = (((encodedRequest->len +2)/3) * 4); + if (base64size > max_get_request_size) { + PKIX_ERROR(PKIX_OCSPGETREQUESTTOOBIG); + } + memset(b64ReqBuf, 0, sizeof(b64ReqBuf)); + PL_Base64Encode((const char *)encodedRequest->data, encodedRequest->len, b64ReqBuf); + urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL); + getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded; + fullGetPath = (char*)PORT_Alloc(getURLLength); + if (!fullGetPath) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + strcpy(fullGetPath, path); + walkOutput = fullGetPath + pathLength; + if (walkOutput > fullGetPath && slashLengthIfNeeded) { + strcpy(walkOutput, "/"); + ++walkOutput; + } + ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput); + sessionPath = fullGetPath; + } + + rv = (*hcv1->createFcn)(serverSession, "http", + sessionPath, httpMethod, + PR_SecondsToInterval(timeout), + &sessionRequest); + sessionPath = NULL; + if (fullGetPath) { + PORT_Free(fullGetPath); + fullGetPath = NULL; + } + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + + if (usePOST) { + rv = (*hcv1->setPostDataFcn)(sessionRequest, + (char *)encodedRequest->data, + encodedRequest->len, + "application/ocsp-request"); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + } + + /* create a PKIX_PL_OcspResponse object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OCSPRESPONSE_TYPE, + sizeof (PKIX_PL_OcspResponse), + (PKIX_PL_Object **)&ocspResponse, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + PKIX_INCREF(request); + ocspResponse->request = request; + ocspResponse->httpClient = httpClient; + ocspResponse->serverSession = serverSession; + serverSession = NULL; + ocspResponse->sessionRequest = sessionRequest; + sessionRequest = NULL; + ocspResponse->verifyFcn = verifyFcn; + ocspResponse->handle = CERT_GetDefaultCertDB(); + ocspResponse->encodedResponse = NULL; + ocspResponse->arena = NULL; + ocspResponse->producedAt = 0; + ocspResponse->producedAtDate = NULL; + ocspResponse->pkixSignerCert = NULL; + ocspResponse->nssOCSPResponse = NULL; + ocspResponse->signerCert = NULL; + } + } + + /* begin or resume IO to HTTPClient */ + if (httpClient && (httpClient->version == 1)) { + PRUint32 responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + hcv1 = &(httpClient->fcnTable.ftable1); + + rv = (*hcv1->trySendAndReceiveFcn)(ocspResponse->sessionRequest, + (PRPollDesc **)&nbioContext, + &responseCode, + (const char **)&responseContentType, + NULL, /* responseHeaders */ + (const char **)&responseData, + &responseDataLen); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + /* responseContentType is a pointer to the null-terminated + * string returned by httpclient. Memory allocated for context + * type will be freed with freeing of the HttpClient struct. */ + if (PORT_Strcasecmp(responseContentType, + "application/ocsp-response")) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + if (nbioContext != NULL) { + *pNBIOContext = nbioContext; + goto cleanup; + } + if (responseCode != 200) { + PKIX_ERROR(PKIX_OCSPBADHTTPRESPONSE); + } + ocspResponse->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (ocspResponse->arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + ocspResponse->encodedResponse = SECITEM_AllocItem + (ocspResponse->arena, NULL, responseDataLen); + if (ocspResponse->encodedResponse == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + PORT_Memcpy(ocspResponse->encodedResponse->data, + responseData, responseDataLen); + } + *pResponse = ocspResponse; + ocspResponse = NULL; + +cleanup: + + if (path != NULL) { + PORT_Free(path); + } + if (hostname != NULL) { + PORT_Free(hostname); + } + if (ocspResponse) { + PKIX_DECREF(ocspResponse); + } + if (serverSession) { + hcv1->freeSessionFcn(serverSession); + } + if (sessionRequest) { + hcv1->freeFcn(sessionRequest); + } + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_Decode + * DESCRIPTION: + * + * This function decodes the DER data contained in the OcspResponse pointed to + * by "response", storing PKIX_TRUE at "pPassed" if the decoding was + * successful, and PKIX_FALSE otherwise. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose DER data is to be decoded. Must + * be non-NULL. + * "pPassed" + * Address at which the Boolean result is stored. Must be non-NULL. + * "pReturnCode" + * Address at which the SECErrorCodes 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 OcspResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ + +PKIX_Error * +pkix_pl_OcspResponse_Decode( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext) +{ + + PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_Decode"); + PKIX_NULLCHECK_TWO(response, response->encodedResponse); + + response->nssOCSPResponse = + CERT_DecodeOCSPResponse(response->encodedResponse); + + if (response->nssOCSPResponse != NULL) { + *pPassed = PKIX_TRUE; + *pReturnCode = 0; + } else { + *pPassed = PKIX_FALSE; + *pReturnCode = PORT_GetError(); + } + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_GetStatus + * DESCRIPTION: + * + * This function checks the response status of the OcspResponse pointed to + * by "response", storing PKIX_TRUE at "pPassed" if the responder understood + * the request and considered it valid, and PKIX_FALSE otherwise. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose status is to be retrieved. Must + * be non-NULL. + * "pPassed" + * Address at which the Boolean 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 OcspResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ + +PKIX_Error * +pkix_pl_OcspResponse_GetStatus( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext) +{ + SECStatus rv = SECFailure; + + PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_GetStatus"); + PKIX_NULLCHECK_FOUR(response, response->nssOCSPResponse, pPassed, pReturnCode); + + rv = CERT_GetOCSPResponseStatus(response->nssOCSPResponse); + + if (rv == SECSuccess) { + *pPassed = PKIX_TRUE; + *pReturnCode = 0; + } else { + *pPassed = PKIX_FALSE; + *pReturnCode = PORT_GetError(); + } + + PKIX_RETURN(OCSPRESPONSE); +} + + +static PKIX_Error* +pkix_pl_OcspResponse_VerifyResponse( + PKIX_PL_OcspResponse *response, + PKIX_ProcessingParams *procParams, + SECCertUsage certUsage, + void **state, + PKIX_BuildResult **buildResult, + void **pNBIOContext, + void *plContext) +{ + SECStatus rv = SECFailure; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifyResponse"); + + if (response->verifyFcn != NULL) { + void *lplContext = NULL; + + PKIX_CHECK( + PKIX_PL_NssContext_Create(((SECCertificateUsage)1) << certUsage, + PKIX_FALSE, NULL, &lplContext), + PKIX_NSSCONTEXTCREATEFAILED); + + PKIX_CHECK( + (response->verifyFcn)((PKIX_PL_Object*)response->pkixSignerCert, + NULL, response->producedAtDate, + procParams, pNBIOContext, + state, buildResult, + NULL, lplContext), + PKIX_CERTVERIFYKEYUSAGEFAILED); + rv = SECSuccess; + } else { + /* checkSig is !isRoot */ + PRBool checkSig = response->signerCert->isRoot ? PR_FALSE : PR_TRUE; + rv = CERT_VerifyCert(response->handle, response->signerCert, checkSig, + certUsage, response->producedAt, NULL, NULL); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_CERTVERIFYKEYUSAGEFAILED); + } + } + +cleanup: + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); + } + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_VerifySignature + * DESCRIPTION: + * + * This function verifies the ocspResponse signature field in the OcspResponse + * pointed to by "response", storing PKIX_TRUE at "pPassed" if verification + * is successful and PKIX_FALSE otherwise. If verification is unsuccessful an + * error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose signature field is to be + * retrieved. Must be non-NULL. + * "cert" + * The address of the Cert for which the OCSP query was made. Must be + * non-NULL. + * "procParams" + * Address of ProcessingParams used to initialize the ExpirationChecker + * and TargetCertChecker. Must be non-NULL. + * "pPassed" + * Address at which the Boolean result is stored. Must be non-NULL. + * "pNBIOContext" + * Address at which the NBIOContext is stored indicating whether the + * checking 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 OcspResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_OcspResponse_VerifySignature( + PKIX_PL_OcspResponse *response, + PKIX_PL_Cert *cert, + PKIX_ProcessingParams *procParams, + PKIX_Boolean *pPassed, + void **pNBIOContext, + void *plContext) +{ + SECStatus rv = SECFailure; + CERTOCSPResponse *nssOCSPResponse = NULL; + CERTCertificate *issuerCert = NULL; + PKIX_BuildResult *buildResult = NULL; + void *nbio = NULL; + void *state = NULL; + + ocspSignature *signature = NULL; + ocspResponseData *tbsData = NULL; + SECItem *tbsResponseDataDER = NULL; + + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature"); + PKIX_NULLCHECK_FOUR(response, cert, pPassed, pNBIOContext); + + nbio = *pNBIOContext; + *pNBIOContext = NULL; + + nssOCSPResponse = response->nssOCSPResponse; + if (nssOCSPResponse == NULL) { + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); + goto cleanup; + } + + tbsData = + ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER); + + signature = ocsp_GetResponseSignature(nssOCSPResponse); + + + /* Are we resuming after a WOULDBLOCK response? */ + if (nbio == NULL) { + /* No, this is a new query */ + + issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(), + certUsageAnyCA); + + /* + * If this signature has already gone through verification, + * just return the cached result. + */ + if (signature->wasChecked) { + if (signature->status == SECSuccess) { + response->signerCert = + CERT_DupCertificate(signature->cert); + } else { + PORT_SetError(signature->failureReason); + goto cleanup; + } + } + + response->signerCert = + ocsp_GetSignerCertificate(response->handle, tbsData, + signature, issuerCert); + + if (response->signerCert == NULL) { + if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) { + /* Make the error a little more specific. */ + PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); + } + goto cleanup; + } + PKIX_CHECK( + PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert, + &(response->pkixSignerCert), + plContext), + PKIX_CERTCREATEWITHNSSCERTFAILED); + + /* + * We could mark this true at the top of this function, or + * always below at "finish", but if the problem was just that + * we could not find the signer's cert, leave that as if the + * signature hasn't been checked. Maybe a subsequent call will + * have better luck. + */ + signature->wasChecked = PR_TRUE; + + /* + * We are about to verify the signer certificate; we need to + * specify *when* that certificate must be valid -- for our + * purposes we expect it to be valid when the response was + * signed. The value of "producedAt" is the signing time. + */ + rv = DER_GeneralizedTimeToTime(&response->producedAt, + &tbsData->producedAt); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); + goto cleanup; + } + + /* + * We need producedAtDate and pkixSignerCert if we are calling a + * user-supplied verification function. Let's put their + * creation before the code that gets repeated when + * non-blocking I/O is used. + */ + + PKIX_CHECK( + pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt, + &(response->producedAtDate), + plContext), + PKIX_DATECREATEFROMPRTIMEFAILED); + + } + + /* + * Just because we have a cert does not mean it is any good; check + * it for validity, trust and usage. Use the caller-supplied + * verification function, if one was supplied. + */ + if (ocsp_CertIsOCSPDefaultResponder(response->handle, + response->signerCert)) { + rv = SECSuccess; + } else { + SECCertUsage certUsage; + if (CERT_IsCACert(response->signerCert, NULL)) { + certUsage = certUsageAnyCA; + } else { + certUsage = certUsageStatusResponder; + } + PKIX_CHECK_ONLY_FATAL( + pkix_pl_OcspResponse_VerifyResponse(response, procParams, + certUsage, &state, + &buildResult, &nbio, + plContext), + PKIX_CERTVERIFYKEYUSAGEFAILED); + if (pkixTempErrorReceived) { + rv = SECFailure; + goto cleanup; + } + if (nbio != NULL) { + *pNBIOContext = nbio; + goto cleanup; + } + } + + rv = ocsp_VerifyResponseSignature(response->signerCert, signature, + tbsResponseDataDER, NULL); + +cleanup: + if (rv == SECSuccess) { + *pPassed = PKIX_TRUE; + } else { + *pPassed = PKIX_FALSE; + } + + if (signature) { + if (signature->wasChecked) { + signature->status = rv; + } + + if (rv != SECSuccess) { + signature->failureReason = PORT_GetError(); + if (response->signerCert != NULL) { + CERT_DestroyCertificate(response->signerCert); + response->signerCert = NULL; + } + } else { + /* Save signer's certificate in signature. */ + signature->cert = CERT_DupCertificate(response->signerCert); + } + } + + if (issuerCert) + CERT_DestroyCertificate(issuerCert); + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_GetStatusForCert + * DESCRIPTION: + * + * This function checks the revocation status of the Cert for which the + * OcspResponse was obtained, storing PKIX_TRUE at "pPassed" if the Cert has + * not been revoked and PKIX_FALSE otherwise. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose certificate status is to be + * retrieved. Must be non-NULL. + * "pPassed" + * Address at which the Boolean result is stored. Must be non-NULL. + * "pReturnCode" + * Address at which the SECErrorCodes 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 OcspResponse Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_OcspResponse_GetStatusForCert( + PKIX_PL_OcspCertID *cid, + PKIX_PL_OcspResponse *response, + PKIX_Boolean allowCachingOfFailures, + PKIX_PL_Date *validity, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext) +{ + PRTime time = 0; + SECStatus rv = SECFailure; + CERTOCSPSingleResponse *single = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert"); + PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode); + + /* + * It is an error to call this function except following a successful + * return from pkix_pl_OcspResponse_VerifySignature, which would have + * set response->signerCert. + */ + PKIX_NULLCHECK_TWO(response->signerCert, response->request); + PKIX_NULLCHECK_TWO(cid, cid->certID); + + if (validity != NULL) { + PKIX_Error *er = pkix_pl_Date_GetPRTime(validity, &time, plContext); + PKIX_DECREF(er); + } + if (!time) { + time = PR_Now(); + } + + rv = ocsp_GetVerifiedSingleResponseForCertID(response->handle, + response->nssOCSPResponse, + cid->certID, + response->signerCert, + time, &single); + if (rv == SECSuccess) { + /* + * Check whether the status says revoked, and if so + * how that compares to the time value passed into this routine. + */ + rv = ocsp_CertHasGoodStatus(single->certStatus, time); + } + + if (rv == SECSuccess || allowCachingOfFailures) { + /* allowed to update the cache */ + PRBool certIDWasConsumed = PR_FALSE; + + if (single) { + ocsp_CacheSingleResponse(cid->certID,single, + &certIDWasConsumed); + } else { + cert_RememberOCSPProcessingFailure(cid->certID, + &certIDWasConsumed); + } + + if (certIDWasConsumed) { + cid->certID = NULL; + } + } + + if (rv == SECSuccess) { + *pPassed = PKIX_TRUE; + *pReturnCode = 0; + } else { + *pPassed = PKIX_FALSE; + *pReturnCode = PORT_GetError(); + } + + PKIX_RETURN(OCSPRESPONSE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h new file mode 100644 index 0000000000..dcf88c9603 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h @@ -0,0 +1,106 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_ocspresponse.h + * + * OcspResponse Object Definitions + * + */ + +#ifndef _PKIX_PL_OCSPRESPONSE_H +#define _PKIX_PL_OCSPRESPONSE_H + +#include "pkix_pl_common.h" +#include "pkix_pl_ocspcertid.h" +#include "hasht.h" +#include "cryptohi.h" +#include "ocspti.h" +#include "ocspi.h" +#include "plbase64.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_OCSP_RESPONSE_LEN (64*1024) + +struct PKIX_PL_OcspResponseStruct{ + PLArenaPool *arena; + const PKIX_PL_OcspRequest *request; + const SEC_HttpClientFcn *httpClient; + SEC_HTTP_SERVER_SESSION serverSession; + SEC_HTTP_REQUEST_SESSION sessionRequest; + PKIX_PL_VerifyCallback verifyFcn; + SECItem *encodedResponse; + CERTCertDBHandle *handle; + PRTime producedAt; + PKIX_PL_Date *producedAtDate; + PKIX_PL_Cert *pkixSignerCert; + CERTOCSPResponse *nssOCSPResponse; + CERTCertificate *signerCert; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_OcspResponse_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_Create( + PKIX_PL_OcspRequest *request, + const char *httpMechanism, + void *responder, + PKIX_PL_VerifyCallback verifyFcn, + void **pNBIOContext, + PKIX_PL_OcspResponse **pResponse, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_Decode( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *passed, + SECErrorCodes *pReturnCode, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_GetStatus( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *passed, + SECErrorCodes *pReturnCode, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_VerifySignature( + PKIX_PL_OcspResponse *response, + PKIX_PL_Cert *cert, + PKIX_ProcessingParams *procParams, + PKIX_Boolean *pPassed, + void **pNBIOContext, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_GetStatusForCert( + PKIX_PL_OcspCertID *cid, + PKIX_PL_OcspResponse *response, + PKIX_Boolean allowCachingOfFailures, + PKIX_PL_Date *validity, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext); + +PKIX_Error * +PKIX_PL_OcspResponse_UseBuildChain( + PKIX_PL_Cert *signerCert, + PKIX_PL_Date *producedAt, + PKIX_ProcessingParams *procParams, + void **pNBIOContext, + void **pState, + PKIX_BuildResult **pBuildResult, + PKIX_VerifyNode **pVerifyTree, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OCSPRESPONSE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c new file mode 100644 index 0000000000..2dfe9a9c2c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c @@ -0,0 +1,489 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_publickey.c + * + * Certificate Object Functions + * + */ + +#include "pkix_pl_publickey.h" + +/* --Private-Cert-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_PublicKey_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the PublicKey + * pointed to by "pkixPubKey" and stores it at "pString". + * + * PARAMETERS + * "pkixPubKey" + * Address of PublicKey whose string representation is desired. + * Must be non-NULL. + * "pString" + * 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 PublicKey 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_PublicKey_ToString_Helper( + PKIX_PL_PublicKey *pkixPubKey, + PKIX_PL_String **pString, + void *plContext) +{ + SECAlgorithmID algorithm; + SECOidTag pubKeyTag; + char *asciiOID = NULL; + PKIX_Boolean freeAsciiOID = PKIX_FALSE; + SECItem oidBytes; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_ToString_Helper"); + PKIX_NULLCHECK_THREE(pkixPubKey, pkixPubKey->nssSPKI, pString); + + /* + * XXX for now, we print out public key algorithm's + * description - add params and bytes later + */ + + /* + * If the algorithm OID is known to NSS, + * we print out the ASCII description that is + * registered with NSS. Otherwise, if unknown, + * we print out the OID numbers (eg. "1.2.840.3") + */ + + algorithm = pkixPubKey->nssSPKI->algorithm; + + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_GetAlgorithmTag).\n"); + pubKeyTag = SECOID_GetAlgorithmTag(&algorithm); + if (pubKeyTag != SEC_OID_UNKNOWN){ + PKIX_PUBLICKEY_DEBUG + ("\t\tCalling SECOID_FindOIDTagDescription).\n"); + asciiOID = (char *)SECOID_FindOIDTagDescription(pubKeyTag); + if (!asciiOID){ + PKIX_ERROR(PKIX_SECOIDFINDOIDTAGDESCRIPTIONFAILED); + } + } else { /* pubKeyTag == SEC_OID_UNKNOWN */ + oidBytes = algorithm.algorithm; + PKIX_CHECK(pkix_pl_oidBytes2Ascii + (&oidBytes, &asciiOID, plContext), + PKIX_OIDBYTES2ASCIIFAILED); + freeAsciiOID = PKIX_TRUE; + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, (void *)asciiOID, 0, pString, plContext), + PKIX_UNABLETOCREATEPSTRING); + +cleanup: + + /* + * we only free asciiOID if it was malloc'ed by pkix_pl_oidBytes2Ascii + */ + if (freeAsciiOID){ + PKIX_FREE(asciiOID); + } + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_DestroySPKI + * DESCRIPTION: + * Frees all memory associated with the CERTSubjectPublicKeyInfo pointed to + * by "nssSPKI". + * PARAMETERS + * "nssSPKI" + * Address of CERTSubjectPublicKeyInfo. 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 Object 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_DestroySPKI( + CERTSubjectPublicKeyInfo *nssSPKI, + void *plContext) +{ + PKIX_ENTER(PUBLICKEY, "pkix_pl_DestroySPKI"); + + PKIX_NULLCHECK_ONE(nssSPKI); + + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_DestroyAlgorithmID).\n"); + SECOID_DestroyAlgorithmID(&nssSPKI->algorithm, PKIX_FALSE); + + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&nssSPKI->subjectPublicKey, PKIX_FALSE); + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_PublicKey *pubKey = NULL; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_OBJECTNOTPUBLICKEY); + + pubKey = (PKIX_PL_PublicKey *)object; + + if (pubKey->nssSPKI) { + + PKIX_CHECK(pkix_pl_DestroySPKI(pubKey->nssSPKI, plContext), + PKIX_DESTROYSPKIFAILED); + + PKIX_FREE(pubKey->nssSPKI); + } + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_PublicKey *pkixPubKey = NULL; + PKIX_PL_String *pubKeyString = NULL; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_OBJECTNOTPUBLICKEY); + + pkixPubKey = (PKIX_PL_PublicKey *)object; + + PKIX_CHECK(pkix_pl_PublicKey_ToString_Helper + (pkixPubKey, &pubKeyString, plContext), + PKIX_PUBLICKEYTOSTRINGHELPERFAILED); + + *pString = pubKeyString; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_PublicKey *pkixPubKey = NULL; + SECItem algOID; + SECItem algParams; + SECItem nssPubKey; + PKIX_UInt32 algOIDHash; + PKIX_UInt32 algParamsHash; + PKIX_UInt32 pubKeyHash; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_OBJECTNOTPUBLICKEY); + + pkixPubKey = (PKIX_PL_PublicKey *)object; + + PKIX_NULLCHECK_ONE(pkixPubKey->nssSPKI); + + algOID = pkixPubKey->nssSPKI->algorithm.algorithm; + algParams = pkixPubKey->nssSPKI->algorithm.parameters; + nssPubKey = pkixPubKey->nssSPKI->subjectPublicKey; + + PKIX_CHECK(pkix_hash + (algOID.data, algOID.len, &algOIDHash, plContext), + PKIX_HASHFAILED); + + PKIX_CHECK(pkix_hash + (algParams.data, algParams.len, &algParamsHash, plContext), + PKIX_HASHFAILED); + + PKIX_CHECK(pkix_hash + (nssPubKey.data, nssPubKey.len, &pubKeyHash, plContext), + PKIX_HASHFAILED); + + *pHashcode = pubKeyHash; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + + +/* + * FUNCTION: pkix_pl_PublicKey_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_PublicKey *firstPKIXPubKey = NULL; + PKIX_PL_PublicKey *secondPKIXPubKey = NULL; + CERTSubjectPublicKeyInfo *firstSPKI = NULL; + CERTSubjectPublicKeyInfo *secondSPKI = NULL; + SECComparison cmpResult; + PKIX_UInt32 secondType; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a PublicKey */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_FIRSTOBJECTNOTPUBLICKEY); + + /* + * Since we know firstObject is a PublicKey, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a PublicKey, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_PUBLICKEY_TYPE) goto cleanup; + + firstPKIXPubKey = ((PKIX_PL_PublicKey *)firstObject); + secondPKIXPubKey = (PKIX_PL_PublicKey *)secondObject; + + firstSPKI = firstPKIXPubKey->nssSPKI; + secondSPKI = secondPKIXPubKey->nssSPKI; + + PKIX_NULLCHECK_TWO(firstSPKI, secondSPKI); + + PKIX_PL_NSSCALLRV(PUBLICKEY, cmpResult, SECOID_CompareAlgorithmID, + (&firstSPKI->algorithm, &secondSPKI->algorithm)); + + if (cmpResult == SECEqual){ + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); + cmpResult = SECITEM_CompareItem + (&firstSPKI->subjectPublicKey, + &secondSPKI->subjectPublicKey); + } + + *pResult = (cmpResult == SECEqual)?PKIX_TRUE:PKIX_FALSE; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_RegisterSelf + * DESCRIPTION: + * Registers PKIX_PUBLICKEY_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_PublicKey_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_RegisterSelf"); + + entry.description = "PublicKey"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_PublicKey); + entry.destructor = pkix_pl_PublicKey_Destroy; + entry.equalsFunction = pkix_pl_PublicKey_Equals; + entry.hashcodeFunction = pkix_pl_PublicKey_Hashcode; + entry.toStringFunction = pkix_pl_PublicKey_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + systemClasses[PKIX_PUBLICKEY_TYPE] = entry; + + PKIX_RETURN(PUBLICKEY); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_PublicKey_NeedsDSAParameters + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PublicKey_NeedsDSAParameters( + PKIX_PL_PublicKey *pubKey, + PKIX_Boolean *pNeedsParams, + void *plContext) +{ + CERTSubjectPublicKeyInfo *nssSPKI = NULL; + KeyType pubKeyType; + PKIX_Boolean needsParams = PKIX_FALSE; + + PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_NeedsDSAParameters"); + PKIX_NULLCHECK_TWO(pubKey, pNeedsParams); + + nssSPKI = pubKey->nssSPKI; + + PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); + pubKeyType = CERT_GetCertKeyType(nssSPKI); + if (!pubKeyType){ + PKIX_ERROR(PKIX_PUBKEYTYPENULLKEY); + } + + if ((pubKeyType == dsaKey) && + (nssSPKI->algorithm.parameters.len == 0)){ + needsParams = PKIX_TRUE; + } + + *pNeedsParams = needsParams; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: PKIX_PL_PublicKey_MakeInheritedDSAPublicKey + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PublicKey_MakeInheritedDSAPublicKey( + PKIX_PL_PublicKey *firstKey, + PKIX_PL_PublicKey *secondKey, + PKIX_PL_PublicKey **pResultKey, + void *plContext) +{ + CERTSubjectPublicKeyInfo *firstSPKI = NULL; + CERTSubjectPublicKeyInfo *secondSPKI = NULL; + CERTSubjectPublicKeyInfo *thirdSPKI = NULL; + PKIX_PL_PublicKey *resultKey = NULL; + KeyType firstPubKeyType; + KeyType secondPubKeyType; + SECStatus rv; + + PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_MakeInheritedDSAPublicKey"); + PKIX_NULLCHECK_THREE(firstKey, secondKey, pResultKey); + PKIX_NULLCHECK_TWO(firstKey->nssSPKI, secondKey->nssSPKI); + + firstSPKI = firstKey->nssSPKI; + secondSPKI = secondKey->nssSPKI; + + PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); + firstPubKeyType = CERT_GetCertKeyType(firstSPKI); + if (!firstPubKeyType){ + PKIX_ERROR(PKIX_FIRSTPUBKEYTYPENULLKEY); + } + + PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); + secondPubKeyType = CERT_GetCertKeyType(secondSPKI); + if (!secondPubKeyType){ + PKIX_ERROR(PKIX_SECONDPUBKEYTYPENULLKEY); + } + + if ((firstPubKeyType == dsaKey) && + (firstSPKI->algorithm.parameters.len == 0)){ + if (secondPubKeyType != dsaKey) { + PKIX_ERROR(PKIX_SECONDKEYNOTDSAPUBLICKEY); + } else if (secondSPKI->algorithm.parameters.len == 0) { + PKIX_ERROR + (PKIX_SECONDKEYDSAPUBLICKEY); + } else { + PKIX_CHECK(PKIX_PL_Calloc + (1, + sizeof (CERTSubjectPublicKeyInfo), + (void **)&thirdSPKI, + plContext), + PKIX_CALLOCFAILED); + + PKIX_PUBLICKEY_DEBUG + ("\t\tCalling" + "SECKEY_CopySubjectPublicKeyInfo).\n"); + rv = SECKEY_CopySubjectPublicKeyInfo + (NULL, thirdSPKI, firstSPKI); + if (rv != SECSuccess) { + PKIX_ERROR + (PKIX_SECKEYCOPYSUBJECTPUBLICKEYINFOFAILED); + } + + PKIX_PUBLICKEY_DEBUG + ("\t\tCalling SECITEM_CopyItem).\n"); + rv = SECITEM_CopyItem(NULL, + &thirdSPKI->algorithm.parameters, + &secondSPKI->algorithm.parameters); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + /* create a PKIX_PL_PublicKey object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_PUBLICKEY_TYPE, + sizeof (PKIX_PL_PublicKey), + (PKIX_PL_Object **)&resultKey, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* populate the SPKI field */ + resultKey->nssSPKI = thirdSPKI; + *pResultKey = resultKey; + } + } else { + *pResultKey = NULL; + } + +cleanup: + + if (thirdSPKI && PKIX_ERROR_RECEIVED){ + PKIX_CHECK(pkix_pl_DestroySPKI(thirdSPKI, plContext), + PKIX_DESTROYSPKIFAILED); + PKIX_FREE(thirdSPKI); + } + + PKIX_RETURN(PUBLICKEY); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h new file mode 100644 index 0000000000..8918859d2d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_publickey.h + * + * Public Key Object Definitions + * + */ + +#ifndef _PKIX_PL_PUBLICKEY_H +#define _PKIX_PL_PUBLICKEY_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_PublicKeyStruct { + CERTSubjectPublicKeyInfo *nssSPKI; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_PublicKey_RegisterSelf(void *plContext); + +PKIX_Error * +PKIX_PL_PublicKey_NeedsDSAParameters( + PKIX_PL_PublicKey *pubKey, + PKIX_Boolean *pNeedsParams, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_PUBLICKEY_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c new file mode 100644 index 0000000000..e37439cf01 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c @@ -0,0 +1,667 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_x500name.c + * + * X500Name Object Functions + * + */ + +#include "pkix_pl_x500name.h" + +/* --Private-X500Name-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_X500Name_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_X500Name *name = NULL; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext), + PKIX_OBJECTNOTANX500NAME); + + name = (PKIX_PL_X500Name *)object; + + /* PORT_FreeArena will destroy arena, and, allocated on it, CERTName + * and SECItem */ + if (name->arena) { + PORT_FreeArena(name->arena, PR_FALSE); + name->arena = NULL; + } + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_X500Name *name = NULL; + char *string = NULL; + PKIX_UInt32 strLength = 0; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext), + PKIX_OBJECTNOTANX500NAME); + + name = (PKIX_PL_X500Name *)object; + string = CERT_NameToAscii(&name->nssDN); + if (!string){ + PKIX_ERROR(PKIX_CERTNAMETOASCIIFAILED); + } + strLength = PL_strlen(string); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, string, strLength, pString, plContext), + PKIX_STRINGCREATEFAILED); + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_X500Name *name = NULL; + SECItem *derBytes = NULL; + PKIX_UInt32 nameHash; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext), + PKIX_OBJECTNOTANX500NAME); + + name = (PKIX_PL_X500Name *)object; + + /* we hash over the bytes in the DER encoding */ + + derBytes = &name->derName; + + PKIX_CHECK(pkix_hash + (derBytes->data, derBytes->len, &nameHash, plContext), + PKIX_HASHFAILED); + + *pHashcode = nameHash; + +cleanup: + + PKIX_RETURN(X500NAME); +} + + +/* + * FUNCTION: pkix_pl_X500Name_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is an X500Name */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_X500NAME_TYPE, plContext), + PKIX_FIRSTOBJECTARGUMENTNOTANX500NAME); + + /* + * Since we know firstObject is an X500Name, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't an X500Name, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_X500NAME_TYPE) goto cleanup; + + PKIX_CHECK( + PKIX_PL_X500Name_Match((PKIX_PL_X500Name *)firstObject, + (PKIX_PL_X500Name *)secondObject, + pResult, plContext), + PKIX_X500NAMEMATCHFAILED); + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_RegisterSelf + * DESCRIPTION: + * Registers PKIX_X500NAME_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_X500Name_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_RegisterSelf"); + + entry.description = "X500Name"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_X500Name); + entry.destructor = pkix_pl_X500Name_Destroy; + entry.equalsFunction = pkix_pl_X500Name_Equals; + entry.hashcodeFunction = pkix_pl_X500Name_Hashcode; + entry.toStringFunction = pkix_pl_X500Name_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_X500NAME_TYPE] = entry; + + PKIX_RETURN(X500NAME); +} + +#ifdef BUILD_LIBPKIX_TESTS +/* + * FUNCTION: pkix_pl_X500Name_CreateFromUtf8 + * + * DESCRIPTION: + * Creates an X500Name object from the RFC1485 string representation pointed + * to by "stringRep", and stores the result at "pName". If the string cannot + * be successfully converted, a non-fatal error is returned. + * + * NOTE: ifdefed BUILD_LIBPKIX_TESTS function: this function is allowed to be + * called only by pkix tests programs. + * + * PARAMETERS: + * "stringRep" + * Address of the RFC1485 string to be converted. Must be non-NULL. + * "pName" + * Address where the X500Name result 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 an X500NAME 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_X500Name_CreateFromUtf8( + char *stringRep, + PKIX_PL_X500Name **pName, + void *plContext) +{ + PKIX_PL_X500Name *x500Name = NULL; + PLArenaPool *arena = NULL; + CERTName *nssDN = NULL; + SECItem *resultSecItem = NULL; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_CreateFromUtf8"); + PKIX_NULLCHECK_TWO(pName, stringRep); + + nssDN = CERT_AsciiToName(stringRep); + if (nssDN == NULL) { + PKIX_ERROR(PKIX_COULDNOTCREATENSSDN); + } + + arena = nssDN->arena; + + /* create a PKIX_PL_X500Name object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_X500NAME_TYPE, + sizeof (PKIX_PL_X500Name), + (PKIX_PL_Object **)&x500Name, + plContext), + PKIX_COULDNOTCREATEX500NAMEOBJECT); + + /* populate the nssDN field */ + x500Name->arena = arena; + x500Name->nssDN.arena = arena; + x500Name->nssDN.rdns = nssDN->rdns; + + resultSecItem = + SEC_ASN1EncodeItem(arena, &x500Name->derName, nssDN, + CERT_NameTemplate); + + if (resultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + *pName = x500Name; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + if (x500Name) { + PKIX_PL_Object_DecRef((PKIX_PL_Object*)x500Name, + plContext); + } else if (nssDN) { + CERT_DestroyName(nssDN); + } + } + + PKIX_RETURN(X500NAME); +} +#endif /* BUILD_LIBPKIX_TESTS */ + +/* + * FUNCTION: pkix_pl_X500Name_GetCERTName + * + * DESCRIPTION: + * + * Returns the pointer to CERTName member of X500Name structure. + * + * Returned pointed should not be freed.2 + * + * PARAMETERS: + * "xname" + * Address of X500Name whose OrganizationName is to be extracted. Must be + * non-NULL. + * "pCERTName" + * Address where result 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_X500Name_GetCERTName( + PKIX_PL_X500Name *xname, + CERTName **pCERTName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCERTName"); + PKIX_NULLCHECK_TWO(xname, pCERTName); + + *pCERTName = &xname->nssDN; + + PKIX_RETURN(X500NAME); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_X500Name_CreateFromCERTName (see comments in pkix_pl_pki.h) + */ + +PKIX_Error * +PKIX_PL_X500Name_CreateFromCERTName( + SECItem *derName, + CERTName *name, + PKIX_PL_X500Name **pName, + void *plContext) +{ + PLArenaPool *arena = NULL; + SECStatus rv = SECFailure; + PKIX_PL_X500Name *x500Name = NULL; + + PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_CreateFromCERTName"); + PKIX_NULLCHECK_ONE(pName); + if (derName == NULL && name == NULL) { + PKIX_ERROR(PKIX_NULLARGUMENT); + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_X500NAME_TYPE, + sizeof (PKIX_PL_X500Name), + (PKIX_PL_Object **)&x500Name, + plContext), + PKIX_COULDNOTCREATEX500NAMEOBJECT); + + x500Name->arena = arena; + x500Name->nssDN.arena = NULL; + + if (derName != NULL) { + rv = SECITEM_CopyItem(arena, &x500Name->derName, derName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + } + + if (name != NULL) { + rv = CERT_CopyName(arena, &x500Name->nssDN, name); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_CERTCOPYNAMEFAILED); + } + } else { + rv = SEC_QuickDERDecodeItem(arena, &x500Name->nssDN, + CERT_NameTemplate, + &x500Name->derName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_SECQUICKDERDECODERFAILED); + } + } + + *pName = x500Name; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + if (x500Name) { + PKIX_PL_Object_DecRef((PKIX_PL_Object*)x500Name, + plContext); + } else if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + } + + PKIX_RETURN(X500NAME); +} + +#ifdef BUILD_LIBPKIX_TESTS +/* + * FUNCTION: PKIX_PL_X500Name_Create (see comments in pkix_pl_pki.h) + * + * NOTE: ifdefed BUILD_LIBPKIX_TESTS function: this function is allowed + * to be called only by pkix tests programs. + */ +PKIX_Error * +PKIX_PL_X500Name_Create( + PKIX_PL_String *stringRep, + PKIX_PL_X500Name **pName, + void *plContext) +{ + char *utf8String = NULL; + PKIX_UInt32 utf8Length = 0; + + PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_Create"); + PKIX_NULLCHECK_TWO(pName, stringRep); + + /* + * convert the input PKIX_PL_String to PKIX_UTF8_NULL_TERM. + * we need to use this format specifier because + * CERT_AsciiToName expects a NULL-terminated UTF8 string. + * Since UTF8 allow NUL characters in the middle of the + * string, this is buggy. However, as a workaround, using + * PKIX_UTF8_NULL_TERM gives us a NULL-terminated UTF8 string. + */ + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stringRep, + PKIX_UTF8_NULL_TERM, + (void **)&utf8String, + &utf8Length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_CHECK( + pkix_pl_X500Name_CreateFromUtf8(utf8String, + pName, plContext), + PKIX_X500NAMECREATEFROMUTF8FAILED); + +cleanup: + PKIX_FREE(utf8String); + + PKIX_RETURN(X500NAME); +} +#endif /* BUILD_LIBPKIX_TESTS */ + +/* + * FUNCTION: PKIX_PL_X500Name_Match (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_X500Name_Match( + PKIX_PL_X500Name *firstX500Name, + PKIX_PL_X500Name *secondX500Name, + PKIX_Boolean *pResult, + void *plContext) +{ + SECItem *firstDerName = NULL; + SECItem *secondDerName = NULL; + SECComparison cmpResult; + + PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_Match"); + PKIX_NULLCHECK_THREE(firstX500Name, secondX500Name, pResult); + + if (firstX500Name == secondX500Name){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + firstDerName = &firstX500Name->derName; + secondDerName = &secondX500Name->derName; + + PKIX_NULLCHECK_TWO(firstDerName->data, secondDerName->data); + + cmpResult = SECITEM_CompareItem(firstDerName, secondDerName); + if (cmpResult != SECEqual) { + cmpResult = CERT_CompareName(&firstX500Name->nssDN, + &secondX500Name->nssDN); + } + + *pResult = (cmpResult == SECEqual); + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetSECName + * + * DESCRIPTION: + * Returns a copy of CERTName DER representation allocated on passed in arena. + * If allocation on arena can not be done, NULL is stored at "pSECName". + * + * PARAMETERS: + * "xname" + * Address of X500Name whose CERTName flag is to be encoded. Must be + * non-NULL. + * "arena" + * Address of the PLArenaPool to be used in the encoding, and in which + * "pSECName" will be allocated. Must be non-NULL. + * "pSECName" + * Address where result 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_X500Name_GetDERName( + PKIX_PL_X500Name *xname, + PLArenaPool *arena, + SECItem **pDERName, + void *plContext) +{ + SECItem *derName = NULL; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetDERName"); + + PKIX_NULLCHECK_THREE(xname, arena, pDERName); + + /* Return NULL is X500Name was not created from DER */ + if (xname->derName.data == NULL) { + *pDERName = NULL; + goto cleanup; + } + + derName = SECITEM_ArenaDupItem(arena, &xname->derName); + if (derName == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + *pDERName = derName; +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetCommonName + * + * DESCRIPTION: + * Extracts the CommonName component of the X500Name object pointed to by + * "xname", and stores the result at "pCommonName". If the CommonName cannot + * be successfully extracted, NULL is stored at "pCommonName". + * + * The returned string must be freed with PORT_Free. + * + * PARAMETERS: + * "xname" + * Address of X500Name whose CommonName is to be extracted. Must be + * non-NULL. + * "pCommonName" + * Address where result 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_X500Name_GetCommonName( + PKIX_PL_X500Name *xname, + unsigned char **pCommonName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCommonName"); + PKIX_NULLCHECK_TWO(xname, pCommonName); + + *pCommonName = (unsigned char *)CERT_GetCommonName(&xname->nssDN); + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetCountryName + * + * DESCRIPTION: + * Extracts the CountryName component of the X500Name object pointed to by + * "xname", and stores the result at "pCountryName". If the CountryName cannot + * be successfully extracted, NULL is stored at "pCountryName". + * + * The returned string must be freed with PORT_Free. + * + * PARAMETERS: + * "xname" + * Address of X500Name whose CountryName is to be extracted. Must be + * non-NULL. + * "pCountryName" + * Address where result 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_X500Name_GetCountryName( + PKIX_PL_X500Name *xname, + unsigned char **pCountryName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCountryName"); + PKIX_NULLCHECK_TWO(xname, pCountryName); + + *pCountryName = (unsigned char*)CERT_GetCountryName(&xname->nssDN); + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetOrgName + * + * DESCRIPTION: + * Extracts the OrganizationName component of the X500Name object pointed to by + * "xname", and stores the result at "pOrgName". If the OrganizationName cannot + * be successfully extracted, NULL is stored at "pOrgName". + * + * The returned string must be freed with PORT_Free. + * + * PARAMETERS: + * "xname" + * Address of X500Name whose OrganizationName is to be extracted. Must be + * non-NULL. + * "pOrgName" + * Address where result 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_X500Name_GetOrgName( + PKIX_PL_X500Name *xname, + unsigned char **pOrgName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetOrgName"); + PKIX_NULLCHECK_TWO(xname, pOrgName); + + *pOrgName = (unsigned char*)CERT_GetOrgName(&xname->nssDN); + + PKIX_RETURN(X500NAME); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h new file mode 100644 index 0000000000..a62bdb82d5 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_x500name.h + * + * X500Name Object Type Definitions + * + */ + +#ifndef _PKIX_PL_X500NAME_H +#define _PKIX_PL_X500NAME_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct PKIX_PL_X500NameStruct{ + PLArenaPool *arena; /* X500Name arena. Shared arena with nssDN + * and derName */ + CERTName nssDN; + SECItem derName; /* adding DER encoded CERTName to the structure + * to avoid unnecessary name encoding when pass + * der name to cert finder */ +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_X500Name_RegisterSelf(void *plContext); + +PKIX_Error *pkix_pl_X500Name_GetDERName( + PKIX_PL_X500Name *xname, + PLArenaPool *arena, + SECItem **pSECName, + void *plContext); + +#ifdef BUILD_LIBPKIX_TESTS +PKIX_Error * pkix_pl_X500Name_CreateFromUtf8( + char *stringRep, + PKIX_PL_X500Name **pName, + void *plContext); +#endif /* BUILD_LIBPKIX_TESTS */ + +PKIX_Error *pkix_pl_X500Name_GetCommonName( + PKIX_PL_X500Name *xname, + unsigned char **pCommonName, + void *plContext); + +PKIX_Error * +pkix_pl_X500Name_GetCountryName( + PKIX_PL_X500Name *xname, + unsigned char **pCountryName, + void *plContext); + +PKIX_Error * +pkix_pl_X500Name_GetOrgName( + PKIX_PL_X500Name *xname, + unsigned char **pOrgName, + void *plContext); + +PKIX_Error * +pkix_pl_X500Name_GetCERTName( + PKIX_PL_X500Name *xname, + CERTName **pCERTName, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_X500NAME_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/system/Makefile new file mode 100644 index 0000000000..2b4b1574ab --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/Makefile @@ -0,0 +1,47 @@ +#! gmake +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp new file mode 100644 index 0000000000..a2f759441e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp @@ -0,0 +1,37 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'lib_libpkix_pkix_pl_nss_system_exports', + 'type': 'none', + 'copies': [ + { + 'files': [ + 'pkix_pl_bigint.h', + 'pkix_pl_bytearray.h', + 'pkix_pl_common.h', + 'pkix_pl_hashtable.h', + 'pkix_pl_lifecycle.h', + 'pkix_pl_mem.h', + 'pkix_pl_monitorlock.h', + 'pkix_pl_mutex.h', + 'pkix_pl_object.h', + 'pkix_pl_oid.h', + 'pkix_pl_primhash.h', + 'pkix_pl_rwlock.h', + 'pkix_pl_string.h' + ], + 'destination': '<(nss_private_dist_dir)/<(module)' + } + ] + } + ], + 'variables': { + 'module': 'nss' + } +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/system/manifest.mn new file mode 100644 index 0000000000..a143a03eed --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/manifest.mn @@ -0,0 +1,43 @@ +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +CORE_DEPTH = ../../../.. + +PRIVATE_EXPORTS = \ + pkix_pl_common.h \ + pkix_pl_mem.h \ + pkix_pl_object.h \ + pkix_pl_string.h \ + pkix_pl_primhash.h \ + pkix_pl_bigint.h \ + pkix_pl_mutex.h \ + pkix_pl_bytearray.h \ + pkix_pl_lifecycle.h \ + pkix_pl_oid.h \ + pkix_pl_hashtable.h \ + pkix_pl_rwlock.h \ + pkix_pl_monitorlock.h \ + $(NULL) + +MODULE = nss + +CSRCS = \ + pkix_pl_bigint.c \ + pkix_pl_bytearray.c \ + pkix_pl_common.c \ + pkix_pl_error.c \ + pkix_pl_hashtable.c \ + pkix_pl_lifecycle.c \ + pkix_pl_mem.c \ + pkix_pl_monitorlock.c \ + pkix_pl_mutex.c \ + pkix_pl_object.c \ + pkix_pl_oid.c \ + pkix_pl_primhash.c \ + pkix_pl_rwlock.c \ + pkix_pl_string.c \ + $(NULL) + +LIBRARY_NAME = pkixsystem +SHARED_LIBRARY = $(NULL) diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c new file mode 100644 index 0000000000..cd8e15ee4b --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c @@ -0,0 +1,398 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_bigint.c + * + * BigInt Object Functions + * + */ + +#include "pkix_pl_bigint.h" + +/* --Private-Big-Int-Functions------------------------------------ */ + +/* + * FUNCTION: pkix_pl_BigInt_Comparator + * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_BigInt_Comparator( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_PL_BigInt *firstBigInt = NULL; + PKIX_PL_BigInt *secondBigInt = NULL; + char *firstPtr = NULL; + char *secondPtr = NULL; + PKIX_UInt32 firstLen, secondLen; + + PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Comparator"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + PKIX_CHECK(pkix_CheckTypes + (firstObject, secondObject, PKIX_BIGINT_TYPE, plContext), + PKIX_ARGUMENTSNOTBIGINTS); + + /* It's safe to cast */ + firstBigInt = (PKIX_PL_BigInt*)firstObject; + secondBigInt = (PKIX_PL_BigInt*)secondObject; + + *pResult = 0; + firstPtr = firstBigInt->dataRep; + secondPtr = secondBigInt->dataRep; + firstLen = firstBigInt->length; + secondLen = secondBigInt->length; + + if (firstLen < secondLen) { + *pResult = -1; + } else if (firstLen > secondLen) { + *pResult = 1; + } else if (firstLen == secondLen) { + PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcmp).\n"); + *pResult = PORT_Memcmp(firstPtr, secondPtr, firstLen); + } + +cleanup: + + PKIX_RETURN(BIGINT); +} + +/* + * FUNCTION: pkix_pl_BigInt_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_BigInt_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_BigInt *bigInt = NULL; + + PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext), + PKIX_OBJECTNOTBIGINT); + + bigInt = (PKIX_PL_BigInt*)object; + + PKIX_FREE(bigInt->dataRep); + bigInt->dataRep = NULL; + bigInt->length = 0; + +cleanup: + + PKIX_RETURN(BIGINT); +} + + +/* + * FUNCTION: pkix_pl_BigInt_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_BigInt_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_BigInt *bigInt = NULL; + char *outputText = NULL; + PKIX_UInt32 i, j, lengthChars; + + PKIX_ENTER(BIGINT, "pkix_pl_BigInt_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext), + PKIX_OBJECTNOTBIGINT); + + bigInt = (PKIX_PL_BigInt*)object; + + /* number of chars = 2 * (number of bytes) + null terminator */ + lengthChars = (bigInt->length * 2) + 1; + + PKIX_CHECK(PKIX_PL_Malloc + (lengthChars, (void **)&outputText, plContext), + PKIX_MALLOCFAILED); + + for (i = 0, j = 0; i < bigInt->length; i += 1, j += 2){ + outputText[j] = pkix_i2hex + ((char) ((*(bigInt->dataRep+i) & 0xf0) >> 4)); + outputText[j+1] = pkix_i2hex + ((char) (*(bigInt->dataRep+i) & 0x0f)); + } + + outputText[lengthChars-1] = '\0'; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + outputText, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + +cleanup: + + PKIX_FREE(outputText); + + PKIX_RETURN(BIGINT); +} + + +/* + * FUNCTION: pkix_pl_BigInt_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_BigInt_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_BigInt *bigInt = NULL; + + PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext), + PKIX_OBJECTNOTBIGINT); + + bigInt = (PKIX_PL_BigInt*)object; + + PKIX_CHECK(pkix_hash + ((void *)bigInt->dataRep, + bigInt->length, + pHashcode, + plContext), + PKIX_HASHFAILED); + +cleanup: + + PKIX_RETURN(BIGINT); +} + +/* + * FUNCTION: pkix_pl_BigInt_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_BigInt_Equals( + PKIX_PL_Object *first, + PKIX_PL_Object *second, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType; + PKIX_Int32 cmpResult = 0; + + PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Equals"); + PKIX_NULLCHECK_THREE(first, second, pResult); + + PKIX_CHECK(pkix_CheckType(first, PKIX_BIGINT_TYPE, plContext), + PKIX_FIRSTOBJECTNOTBIGINT); + + PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + + *pResult = PKIX_FALSE; + + if (secondType != PKIX_BIGINT_TYPE) goto cleanup; + + PKIX_CHECK(pkix_pl_BigInt_Comparator + (first, second, &cmpResult, plContext), + PKIX_BIGINTCOMPARATORFAILED); + + *pResult = (cmpResult == 0); + +cleanup: + + PKIX_RETURN(BIGINT); +} + +/* + * FUNCTION: pkix_pl_BigInt_RegisterSelf + * DESCRIPTION: + * Registers PKIX_BIGINT_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_BigInt_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(BIGINT, "pkix_pl_BigInt_RegisterSelf"); + + entry.description = "BigInt"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_BigInt); + entry.destructor = pkix_pl_BigInt_Destroy; + entry.equalsFunction = pkix_pl_BigInt_Equals; + entry.hashcodeFunction = pkix_pl_BigInt_Hashcode; + entry.toStringFunction = pkix_pl_BigInt_ToString; + entry.comparator = pkix_pl_BigInt_Comparator; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_BIGINT_TYPE] = entry; + + PKIX_RETURN(BIGINT); +} + +/* + * FUNCTION: pkix_pl_BigInt_CreateWithBytes + * DESCRIPTION: + * + * Creates a new BigInt of size "length" representing the array of bytes + * pointed to by "bytes" and stores it at "pBigInt". The caller should make + * sure that the first byte is not 0x00 (unless it is the the only byte). + * This function does not do that checking. + * + * Once created, a PKIX_PL_BigInt object is immutable. + * + * PARAMETERS: + * "bytes" + * Address of array of bytes. Must be non-NULL. + * "length" + * Length of the array. Must be non-zero. + * "pBigInt" + * 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_BigInt_CreateWithBytes( + char *bytes, + PKIX_UInt32 length, + PKIX_PL_BigInt **pBigInt, + void *plContext) +{ + PKIX_PL_BigInt *bigInt = NULL; + + PKIX_ENTER(BIGINT, "pkix_pl_BigInt_CreateWithBytes"); + PKIX_NULLCHECK_TWO(pBigInt, bytes); + + if (length == 0) { + PKIX_ERROR(PKIX_BIGINTLENGTH0INVALID) + } + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_BIGINT_TYPE, + sizeof (PKIX_PL_BigInt), + (PKIX_PL_Object **)&bigInt, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + PKIX_CHECK(PKIX_PL_Malloc + (length, (void **)&(bigInt->dataRep), plContext), + PKIX_MALLOCFAILED); + + PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcpy).\n"); + (void) PORT_Memcpy(bigInt->dataRep, bytes, length); + + bigInt->length = length; + + *pBigInt = bigInt; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(bigInt); + } + + PKIX_RETURN(BIGINT); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_BigInt_Create (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_BigInt_Create( + PKIX_PL_String *stringRep, + PKIX_PL_BigInt **pBigInt, + void *plContext) +{ + PKIX_PL_BigInt *bigInt = NULL; + char *asciiString = NULL; + PKIX_UInt32 lengthBytes; + PKIX_UInt32 lengthString; + PKIX_UInt32 i; + char currChar; + + PKIX_ENTER(BIGINT, "PKIX_PL_BigInt_Create"); + PKIX_NULLCHECK_TWO(pBigInt, stringRep); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stringRep, + PKIX_ESCASCII, + (void **)&asciiString, + &lengthString, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + if ((lengthString == 0) || ((lengthString % 2) != 0)){ + PKIX_ERROR(PKIX_SOURCESTRINGHASINVALIDLENGTH); + } + + if (lengthString != 2){ + if ((asciiString[0] == '0') && (asciiString[1] == '0')){ + PKIX_ERROR(PKIX_FIRSTDOUBLEHEXMUSTNOTBE00); + } + } + + for (i = 0; i < lengthString; i++) { + currChar = asciiString[i]; + if (!PKIX_ISXDIGIT(currChar)){ + PKIX_ERROR(PKIX_INVALIDCHARACTERINBIGINT); + } + } + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_BIGINT_TYPE, + sizeof (PKIX_PL_BigInt), + (PKIX_PL_Object **)&bigInt, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* number of bytes = 0.5 * (number of chars) */ + lengthBytes = lengthString/2; + + PKIX_CHECK(PKIX_PL_Malloc + (lengthBytes, (void **)&(bigInt->dataRep), plContext), + PKIX_MALLOCFAILED); + + for (i = 0; i < lengthString; i += 2){ + (bigInt->dataRep)[i/2] = + (pkix_hex2i(asciiString[i])<<4) | + pkix_hex2i(asciiString[i+1]); + } + + bigInt->length = lengthBytes; + + *pBigInt = bigInt; + +cleanup: + + PKIX_FREE(asciiString); + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(bigInt); + } + + PKIX_RETURN(BIGINT); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h new file mode 100644 index 0000000000..b3df808a8d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_bigint.h + * + * Bigint Object Definitions + * + */ + +#ifndef _PKIX_PL_BIGINT_H +#define _PKIX_PL_BIGINT_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_BigIntStruct { + char *dataRep; + PKIX_UInt32 length; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_BigInt_CreateWithBytes( + char *bytes, + PKIX_UInt32 length, + PKIX_PL_BigInt **pBigInt, + void *plContext); + +PKIX_Error *pkix_pl_BigInt_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_BIGINT_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c new file mode 100644 index 0000000000..0a2e9c08f3 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c @@ -0,0 +1,504 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_bytearray.c + * + * ByteArray Object Functions + * + */ + +#include "pkix_pl_bytearray.h" + +/* --Private-ByteArray-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_ByteArray_ToHexString + * DESCRIPTION: + * + * Creates a hex-String representation of the ByteArray pointed to by "array" + * and stores the result at "pString". The hex-String consists of hex-digit + * pairs separated by spaces, and the entire string enclosed within square + * brackets, e.g. [43 61 6E 20 79 6F 75 20 72 65 61 64 20 74 68 69 73 3F]. + * A zero-length ByteArray is represented as []. + * PARAMETERS + * "array" + * ByteArray to be represented by the hex-String; must be non-NULL + * "pString" + * Address where String 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 Cert 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_ByteArray_ToHexString( + PKIX_PL_ByteArray *array, + PKIX_PL_String **pString, + void *plContext) +{ + char *tempText = NULL; + char *stringText = NULL; /* "[XX XX XX ...]" */ + PKIX_UInt32 i, outputLen, bufferSize; + + PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToHexString"); + PKIX_NULLCHECK_TWO(array, pString); + + if ((array->length) == 0) { + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "[]", 0, pString, plContext), + PKIX_COULDNOTCREATESTRING); + } else { + /* + * Allocate space for format string + * '[' + "XX" + (n-1)*" XX" + ']' + '\0' + */ + bufferSize = 2 + (3*(array->length)); + + PKIX_CHECK(PKIX_PL_Malloc + (bufferSize, (void **)&stringText, plContext), + PKIX_COULDNOTALLOCATEMEMORY); + + stringText[0] = 0; + outputLen = 0; + + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); + tempText = PR_smprintf + ("[%02X", (0x0FF&((char *)(array->array))[0])); + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); + outputLen += PL_strlen(tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); + stringText = PL_strcat(stringText, tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); + PR_smprintf_free(tempText); + + for (i = 1; i < array->length; i++) { + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); + tempText = PR_smprintf + (" %02X", (0x0FF&((char *)(array->array))[i])); + + if (tempText == NULL){ + PKIX_ERROR(PKIX_PRSMPRINTFFAILED); + } + + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); + outputLen += PL_strlen(tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); + stringText = PL_strcat(stringText, tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); + PR_smprintf_free(tempText); + tempText = NULL; + } + + stringText[outputLen++] = ']'; + stringText[outputLen] = 0; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + stringText, + 0, + pString, + plContext), + PKIX_COULDNOTCREATESTRING); + } + +cleanup: + + PKIX_FREE(stringText); + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: pkix_pl_ByteArray_Comparator + * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) + * + * NOTE: + * It is not clear that this definition of comparing byte arrays makes + * sense. It does allow you to tell whether two blocks of memory are + * identical, so we only use it for the Equals function (i.e. we don't + * register it as a Compare function for ByteArray). + */ +static PKIX_Error * +pkix_pl_ByteArray_Comparator( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_PL_ByteArray *firstByteArray = NULL; + PKIX_PL_ByteArray *secondByteArray = NULL; + unsigned char *firstData = NULL; + unsigned char *secondData = NULL; + PKIX_UInt32 i; + + PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Comparator"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + PKIX_CHECK(pkix_CheckTypes + (firstObject, secondObject, PKIX_BYTEARRAY_TYPE, plContext), + PKIX_ARGUMENTSNOTBYTEARRAYS); + + /* It's safe to cast */ + firstByteArray = (PKIX_PL_ByteArray *)firstObject; + secondByteArray = (PKIX_PL_ByteArray *)secondObject; + + *pResult = 0; + firstData = (unsigned char *)firstByteArray->array; + secondData = (unsigned char *)secondByteArray->array; + + if (firstByteArray->length < secondByteArray->length) { + *pResult = -1; + } else if (firstByteArray->length > secondByteArray->length) { + *pResult = 1; + } else if (firstByteArray->length == secondByteArray->length) { + /* Check if both array contents are identical */ + for (i = 0; + (i < firstByteArray->length) && (*pResult == 0); + i++) { + if (firstData[i] < secondData[i]) { + *pResult = -1; + } else if (firstData[i] > secondData[i]) { + *pResult = 1; + } + } + } + +cleanup: + + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: pkix_pl_ByteArray_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_ByteArray_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_ByteArray *array = NULL; + char *tempText = NULL; + char *stringText = NULL; /* "[OOO, OOO, ... OOO]" */ + PKIX_UInt32 i, outputLen, bufferSize; + + PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext), + PKIX_OBJECTNOTBYTEARRAY); + + array = (PKIX_PL_ByteArray *)object; + + if ((array->length) == 0) { + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "[]", 0, pString, plContext), + PKIX_COULDNOTCREATESTRING); + } else { + /* Allocate space for "XXX, ". */ + bufferSize = 2+5*array->length; + + /* Allocate space for format string */ + PKIX_CHECK(PKIX_PL_Malloc + (bufferSize, (void **)&stringText, plContext), + PKIX_MALLOCFAILED); + + stringText[0] = 0; + outputLen = 0; + + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); + tempText = + PR_smprintf + ("[%03u", (0x0FF&((char *)(array->array))[0])); + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); + outputLen += PL_strlen(tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); + stringText = PL_strcat(stringText, tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); + PR_smprintf_free(tempText); + + for (i = 1; i < array->length; i++) { + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); + tempText = PR_smprintf + (", %03u", + (0x0FF&((char *)(array->array))[i])); + + if (tempText == NULL){ + PKIX_ERROR(PKIX_PRSMPRINTFFAILED); + } + + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); + outputLen += PL_strlen(tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); + stringText = PL_strcat(stringText, tempText); + + PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); + PR_smprintf_free(tempText); + tempText = NULL; + } + + stringText[outputLen++] = ']'; + stringText[outputLen] = 0; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, stringText, 0, pString, plContext), + PKIX_STRINGCREATEFAILED); + + } + +cleanup: + + PKIX_FREE(stringText); + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: pkix_pl_ByteArray_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_ByteArray_Equals( + PKIX_PL_Object *first, + PKIX_PL_Object *second, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType; + PKIX_Int32 cmpResult = 0; + + PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Equals"); + PKIX_NULLCHECK_THREE(first, second, pResult); + + /* Sanity check: Test that "first" is a ByteArray */ + PKIX_CHECK(pkix_CheckType(first, PKIX_BYTEARRAY_TYPE, plContext), + PKIX_FIRSTARGUMENTNOTBYTEARRAY); + + PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + + /* If types differ, then we will return false */ + *pResult = PKIX_FALSE; + + /* Second type may not be a BA */ + if (secondType != PKIX_BYTEARRAY_TYPE) goto cleanup; + + /* It's safe to cast here */ + PKIX_CHECK(pkix_pl_ByteArray_Comparator + (first, second, &cmpResult, plContext), + PKIX_BYTEARRAYCOMPARATORFAILED); + + /* ByteArrays are equal iff Comparator Result is 0 */ + *pResult = (cmpResult == 0); + +cleanup: + + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: pkix_pl_ByteArray_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_ByteArray_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_ByteArray *array = NULL; + + PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext), + PKIX_OBJECTNOTBYTEARRAY); + + array = (PKIX_PL_ByteArray*)object; + + PKIX_FREE(array->array); + array->array = NULL; + array->length = 0; + +cleanup: + + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: pkix_pl_ByteArray_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_ByteArray_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_ByteArray *array = NULL; + + PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext), + PKIX_OBJECTNOTBYTEARRAY); + + array = (PKIX_PL_ByteArray*)object; + + PKIX_CHECK(pkix_hash + ((const unsigned char *)array->array, + array->length, + pHashcode, + plContext), + PKIX_HASHFAILED); + +cleanup: + + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: pkix_pl_ByteArray_RegisterSelf + * DESCRIPTION: + * Registers PKIX_BYTEARRAY_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_ByteArray_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_RegisterSelf"); + + entry.description = "ByteArray"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_ByteArray); + entry.destructor = pkix_pl_ByteArray_Destroy; + entry.equalsFunction = pkix_pl_ByteArray_Equals; + entry.hashcodeFunction = pkix_pl_ByteArray_Hashcode; + entry.toStringFunction = pkix_pl_ByteArray_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_BYTEARRAY_TYPE] = entry; + + PKIX_RETURN(BYTEARRAY); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_ByteArray_Create (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_ByteArray_Create( + void *array, + PKIX_UInt32 length, + PKIX_PL_ByteArray **pByteArray, + void *plContext) +{ + PKIX_PL_ByteArray *byteArray = NULL; + + PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_Create"); + PKIX_NULLCHECK_ONE(pByteArray); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_BYTEARRAY_TYPE, + sizeof (PKIX_PL_ByteArray), + (PKIX_PL_Object **)&byteArray, + plContext), + PKIX_COULDNOTCREATEOBJECTSTORAGE); + + byteArray->length = length; + byteArray->array = NULL; + + if (length != 0){ + /* Alloc space for array */ + PKIX_NULLCHECK_ONE(array); + + PKIX_CHECK(PKIX_PL_Malloc + (length, (void**)&(byteArray->array), plContext), + PKIX_MALLOCFAILED); + + PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n"); + (void) PORT_Memcpy(byteArray->array, array, length); + } + + *pByteArray = byteArray; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(byteArray); + } + + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: PKIX_PL_ByteArray_GetPointer (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_ByteArray_GetPointer( + PKIX_PL_ByteArray *byteArray, + void **pArray, + void *plContext) +{ + void *bytes = NULL; + PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetPointer"); + PKIX_NULLCHECK_TWO(byteArray, pArray); + + if (byteArray->length != 0){ + PKIX_CHECK(PKIX_PL_Malloc + (byteArray->length, &bytes, plContext), + PKIX_MALLOCFAILED); + + PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n"); + (void) PORT_Memcpy + (bytes, byteArray->array, byteArray->length); + } + + *pArray = bytes; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_FREE(bytes); + } + + PKIX_RETURN(BYTEARRAY); +} + +/* + * FUNCTION: PKIX_PL_ByteArray_GetLength (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_ByteArray_GetLength( + PKIX_PL_ByteArray *byteArray, + PKIX_UInt32 *pLength, + void *plContext) +{ + PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetLength"); + PKIX_NULLCHECK_TWO(byteArray, pLength); + + *pLength = byteArray->length; + + PKIX_RETURN(BYTEARRAY); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h new file mode 100644 index 0000000000..4ba18eed74 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h @@ -0,0 +1,40 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_bytearray.h + * + * ByteArray Object Definitions + * + */ + +#ifndef _PKIX_PL_BYTEARRAY_H +#define _PKIX_PL_BYTEARRAY_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_ByteArrayStruct { + void *array; + PKIX_UInt32 length; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_ByteArray_ToHexString( + PKIX_PL_ByteArray *array, + PKIX_PL_String **pString, + void *plContext); + +PKIX_Error * +pkix_pl_ByteArray_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_BYTEARRAY_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c new file mode 100644 index 0000000000..831ce538d3 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c @@ -0,0 +1,1073 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_common.c + * + * Common utility functions used by various PKIX_PL functions + * + */ + +#include "pkix_pl_common.h" + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_LockObject + * DESCRIPTION: + * + * Locks the object pointed to by "object". + * + * PARAMETERS: + * "object" + * Address of 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_LockObject( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader; + + PKIX_ENTER(OBJECT, "pkix_LockObject"); + PKIX_NULLCHECK_ONE(object); + + if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) { + goto cleanup; + } + + PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); + /* The header is sizeof(PKIX_PL_Object) before the object pointer */ + + objectHeader = object-1; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(objectHeader->lock); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_UnlockObject + * DESCRIPTION: + * + * Unlocks the object pointed to by "object". + * + * PARAMETERS: + * "object" + * Address of 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_UnlockObject( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader; + PRStatus result; + + PKIX_ENTER(OBJECT, "pkix_UnlockObject"); + PKIX_NULLCHECK_ONE(object); + + if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) { + goto cleanup; + } + + PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); + /* The header is sizeof(PKIX_PL_Object) before the object pointer */ + + objectHeader = object-1; + + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + result = PR_Unlock(objectHeader->lock); + + if (result == PR_FAILURE) { + PKIX_OBJECT_DEBUG("\tPR_Unlock failed.).\n"); + PKIX_ERROR_FATAL(PKIX_ERRORUNLOCKINGOBJECT); + } + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_UInt32_Overflows + * DESCRIPTION: + * + * Returns a PKIX_Boolean indicating whether the unsigned integer + * represented by "string" is too large to fit in 32-bits (i.e. + * whether it overflows). With the exception of the string "0", + * all other strings are stripped of any leading zeros. It is assumed + * that every character in "string" is from the set {'0' - '9'}. + * + * PARAMETERS + * "string" + * Address of array of bytes representing PKIX_UInt32 that's being tested + * for 32-bit overflow + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * PKIX_TRUE if PKIX_UInt32 represented by "string" overflows; + * PKIX_FALSE otherwise + */ +PKIX_Boolean +pkix_pl_UInt32_Overflows(char *string){ + char *firstNonZero = NULL; + PKIX_UInt32 length, i; + char *MAX_UINT32_STRING = "4294967295"; + + PKIX_DEBUG_ENTER(OID); + + PKIX_OID_DEBUG("\tCalling PL_strlen).\n"); + length = PL_strlen(string); + + if (length < MAX_DIGITS_32){ + return (PKIX_FALSE); + } + + firstNonZero = string; + for (i = 0; i < length; i++){ + if (*string == '0'){ + firstNonZero++; + } + } + + PKIX_OID_DEBUG("\tCalling PL_strlen).\n"); + length = PL_strlen(firstNonZero); + + if (length > MAX_DIGITS_32){ + return (PKIX_TRUE); + } + + PKIX_OID_DEBUG("\tCalling PL_strlen).\n"); + if (length == MAX_DIGITS_32){ + PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n"); + if (PORT_Strcmp(firstNonZero, MAX_UINT32_STRING) > 0){ + return (PKIX_TRUE); + } + } + + return (PKIX_FALSE); +} + +/* + * FUNCTION: pkix_pl_getOIDToken + * DESCRIPTION: + * + * Takes the array of DER-encoded bytes pointed to by "derBytes" + * (representing an OID) and the value of "index" representing the index into + * the array, and decodes the bytes until an integer token is retrieved. If + * successful, this function stores the integer component at "pToken" and + * stores the index representing the next byte in the array at "pIndex" + * (following the last byte that was used in the decoding). This new output + * index can be used in subsequent calls as an input index, allowing each + * token of the OID to be retrieved consecutively. Note that there is a + * special case for the first byte, in that it encodes two separate integer + * tokens. For example, the byte {2a} represents the integer tokens {1,2}. + * This special case is not handled here and must be handled by the caller. + * + * PARAMETERS + * "derBytes" + * Address of array of bytes representing a DER-encoded OID. + * Must be non-NULL. + * "index" + * Index into the array that this function will begin decoding at. + * "pToken" + * Destination for decoded OID token. Must be non-NULL. + * "pIndex" + * Destination for index of next byte following last byte used. + * 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 Object 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_getOIDToken( + char *derBytes, + PKIX_UInt32 index, + PKIX_UInt32 *pToken, + PKIX_UInt32 *pIndex, + void *plContext) +{ + PKIX_UInt32 retval, i, tmp; + + PKIX_ENTER(OID, "pkix_pl_getOIDToken"); + PKIX_NULLCHECK_THREE(derBytes, pToken, pIndex); + + /* + * We should only need to parse a maximum of four bytes, because + * RFC 3280 "mandates support for OIDs which have arc elements + * with values that are less than 2^28, that is, they MUST be between + * 0 and 268,435,455, inclusive. This allows each arc element to be + * represented within a single 32 bit word." + */ + + for (i = 0, retval = 0; i < 4; i++) { + retval <<= 7; + tmp = derBytes[index]; + index++; + retval |= (tmp & 0x07f); + if ((tmp & 0x080) == 0){ + *pToken = retval; + *pIndex = index; + goto cleanup; + } + } + + PKIX_ERROR(PKIX_INVALIDENCODINGOIDTOKENVALUETOOBIG); + +cleanup: + + PKIX_RETURN(OID); + +} + +/* + * FUNCTION: pkix_pl_helperBytes2Ascii + * DESCRIPTION: + * + * Converts an array of integers pointed to by "tokens" with a length of + * "numTokens", to an ASCII string consisting of those integers with dots in + * between them and stores the result at "pAscii". The ASCII representation is + * guaranteed to end with a NUL character. This is particularly useful for + * OID's and IP Addresses. + * + * The return value "pAscii" is not reference-counted and will need to + * be freed with PKIX_PL_Free. + * + * PARAMETERS + * "tokens" + * Address of array of integers. Must be non-NULL. + * "numTokens" + * Length of array of integers. Must be non-zero. + * "pAscii" + * 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 an Object 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_helperBytes2Ascii( + PKIX_UInt32 *tokens, + PKIX_UInt32 numTokens, + char **pAscii, + void *plContext) +{ + char *tempString = NULL; + char *outputString = NULL; + char *format = "%d"; + PKIX_UInt32 i = 0; + PKIX_UInt32 outputLen = 0; + PKIX_Int32 error; + + PKIX_ENTER(OBJECT, "pkix_pl_helperBytes2Ascii"); + PKIX_NULLCHECK_TWO(tokens, pAscii); + + if (numTokens == 0) { + PKIX_ERROR_FATAL(PKIX_HELPERBYTES2ASCIINUMTOKENSZERO); + } + + /* + * tempString will hold the string representation of a PKIX_UInt32 type + * The maximum value that can be held by an unsigned 32-bit integer + * is (2^32 - 1) = 4294967295 (which is ten digits long) + * Since tempString will hold the string representation of a + * PKIX_UInt32, we allocate 11 bytes for it (1 byte for '\0') + */ + + PKIX_CHECK(PKIX_PL_Malloc + (MAX_DIGITS_32 + 1, (void **)&tempString, plContext), + PKIX_MALLOCFAILED); + + for (i = 0; i < numTokens; i++){ + PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n"); + error = PR_snprintf(tempString, + MAX_DIGITS_32 + 1, + format, + tokens[i]); + if (error == -1){ + PKIX_ERROR(PKIX_PRSNPRINTFFAILED); + } + + PKIX_OBJECT_DEBUG("\tCalling PL_strlen).\n"); + outputLen += PL_strlen(tempString); + + /* Include a dot to separate each number */ + outputLen++; + } + + /* Allocate space for the destination string */ + PKIX_CHECK(PKIX_PL_Malloc + (outputLen, (void **)&outputString, plContext), + PKIX_MALLOCFAILED); + + *outputString = '\0'; + + /* Concatenate all strings together */ + for (i = 0; i < numTokens; i++){ + + PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n"); + error = PR_snprintf(tempString, + MAX_DIGITS_32 + 1, + format, + tokens[i]); + if (error == -1){ + PKIX_ERROR(PKIX_PRSNPRINTFFAILED); + } + + PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n"); + (void) PL_strcat(outputString, tempString); + + /* we don't want to put a "." at the very end */ + if (i < (numTokens - 1)){ + PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n"); + (void) PL_strcat(outputString, "."); + } + } + + /* Ensure output string ends with terminating null */ + outputString[outputLen-1] = '\0'; + + *pAscii = outputString; + outputString = NULL; + +cleanup: + + PKIX_FREE(outputString); + PKIX_FREE(tempString); + + PKIX_RETURN(OBJECT); + +} + +/* + * FUNCTION: pkix_pl_ipAddrBytes2Ascii + * DESCRIPTION: + * + * Converts the DER encoding of an IPAddress pointed to by "secItem" to an + * ASCII representation and stores the result at "pAscii". The ASCII + * representation is guaranteed to end with a NUL character. The input + * SECItem must contain non-NULL data and must have a positive length. + * + * The return value "pAscii" is not reference-counted and will need to + * be freed with PKIX_PL_Free. + * XXX this function assumes that IPv4 addresses are being used + * XXX what about IPv6? can NSS tell the difference + * + * PARAMETERS + * "secItem" + * Address of SECItem which contains bytes and length of DER encoding. + * Must be non-NULL. + * "pAscii" + * 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 an Object 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_ipAddrBytes2Ascii( + SECItem *secItem, + char **pAscii, + void *plContext) +{ + char *data = NULL; + PKIX_UInt32 *tokens = NULL; + PKIX_UInt32 numTokens = 0; + PKIX_UInt32 i = 0; + char *asciiString = NULL; + + PKIX_ENTER(OBJECT, "pkix_pl_ipAddrBytes2Ascii"); + PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data); + + if (secItem->len == 0) { + PKIX_ERROR_FATAL(PKIX_IPADDRBYTES2ASCIIDATALENGTHZERO); + } + + data = (char *)(secItem->data); + numTokens = secItem->len; + + /* allocate space for array of integers */ + PKIX_CHECK(PKIX_PL_Malloc + (numTokens * sizeof (PKIX_UInt32), + (void **)&tokens, + plContext), + PKIX_MALLOCFAILED); + + /* populate array of integers */ + for (i = 0; i < numTokens; i++){ + tokens[i] = data[i]; + } + + /* convert array of integers to ASCII */ + PKIX_CHECK(pkix_pl_helperBytes2Ascii + (tokens, numTokens, &asciiString, plContext), + PKIX_HELPERBYTES2ASCIIFAILED); + + *pAscii = asciiString; + +cleanup: + + PKIX_FREE(tokens); + + PKIX_RETURN(OBJECT); +} + + +/* + * FUNCTION: pkix_pl_oidBytes2Ascii + * DESCRIPTION: + * + * Converts the DER encoding of an OID pointed to by "secItem" to an ASCII + * representation and stores it at "pAscii". The ASCII representation is + * guaranteed to end with a NUL character. The input SECItem must contain + * non-NULL data and must have a positive length. + * + * Example: the six bytes {2a 86 48 86 f7 0d} represent the + * four integer tokens {1, 2, 840, 113549}, which we will convert + * into ASCII yielding "1.2.840.113549" + * + * The return value "pAscii" is not reference-counted and will need to + * be freed with PKIX_PL_Free. + * + * PARAMETERS + * "secItem" + * Address of SECItem which contains bytes and length of DER encoding. + * Must be non-NULL. + * "pAscii" + * 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 an OID 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_oidBytes2Ascii( + SECItem *secItem, + char **pAscii, + void *plContext) +{ + char *data = NULL; + PKIX_UInt32 *tokens = NULL; + PKIX_UInt32 token = 0; + PKIX_UInt32 numBytes = 0; + PKIX_UInt32 numTokens = 0; + PKIX_UInt32 i = 0, x = 0, y = 0; + PKIX_UInt32 index = 0; + char *asciiString = NULL; + + PKIX_ENTER(OID, "pkix_pl_oidBytes2Ascii"); + PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data); + + if (secItem->len == 0) { + PKIX_ERROR_FATAL(PKIX_OIDBYTES2ASCIIDATALENGTHZERO); + } + + data = (char *)(secItem->data); + numBytes = secItem->len; + numTokens = 0; + + /* calculate how many integer tokens are represented by the bytes. */ + for (i = 0; i < numBytes; i++){ + if ((data[i] & 0x080) == 0){ + numTokens++; + } + } + + /* if we are unable to retrieve any tokens at all, we throw an error */ + if (numTokens == 0){ + PKIX_ERROR(PKIX_INVALIDDERENCODINGFOROID); + } + + /* add one more token b/c the first byte always contains two tokens */ + numTokens++; + + /* allocate space for array of integers */ + PKIX_CHECK(PKIX_PL_Malloc + (numTokens * sizeof (PKIX_UInt32), + (void **)&tokens, + plContext), + PKIX_MALLOCFAILED); + + /* populate array of integers */ + for (i = 0; i < numTokens; i++){ + + /* retrieve integer token */ + PKIX_CHECK(pkix_pl_getOIDToken + (data, index, &token, &index, plContext), + PKIX_GETOIDTOKENFAILED); + + if (i == 0){ + + /* + * special case: the first DER-encoded byte represents + * two tokens. We take advantage of fact that first + * token must be 0, 1, or 2; and second token must be + * between {0, 39} inclusive if first token is 0 or 1. + */ + + if (token < 40) + x = 0; + else if (token < 80) + x = 1; + else + x = 2; + y = token - (x * 40); + + tokens[0] = x; + tokens[1] = y; + i++; + } else { + tokens[i] = token; + } + } + + /* convert array of integers to ASCII */ + PKIX_CHECK(pkix_pl_helperBytes2Ascii + (tokens, numTokens, &asciiString, plContext), + PKIX_HELPERBYTES2ASCIIFAILED); + + *pAscii = asciiString; + +cleanup: + + PKIX_FREE(tokens); + PKIX_RETURN(OID); + +} + +/* + * FUNCTION: pkix_UTF16_to_EscASCII + * DESCRIPTION: + * + * Converts array of bytes pointed to by "utf16String" with length of + * "utf16Length" (which must be even) into a freshly allocated Escaped ASCII + * string and stores a pointer to that string at "pDest" and stores the + * string's length at "pLength". The Escaped ASCII string's length does not + * include the final NUL character. The caller is responsible for freeing + * "pDest" using PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug + * encoding. + * + * PARAMETERS: + * "utf16String" + * Address of array of bytes representing data source. Must be non-NULL. + * "utf16Length" + * Length of data source. Must be even. + * "debug" + * Boolean value indicating whether debug mode is desired. + * "pDest" + * Address where data will be stored. Must be non-NULL. + * "pLength" + * Address where data length 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 String 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_UTF16_to_EscASCII( + const void *utf16String, + PKIX_UInt32 utf16Length, + PKIX_Boolean debug, + char **pDest, + PKIX_UInt32 *pLength, + void *plContext) +{ + char *destPtr = NULL; + PKIX_UInt32 i, charLen; + PKIX_UInt32 x = 0, y = 0, z = 0; + unsigned char *utf16Char = (unsigned char *)utf16String; + + PKIX_ENTER(STRING, "pkix_UTF16_to_EscASCII"); + PKIX_NULLCHECK_THREE(utf16String, pDest, pLength); + + /* Assume every pair of bytes becomes &#xNNNN; */ + charLen = 4*utf16Length; + + /* utf16Lenght must be even */ + if ((utf16Length % 2) != 0){ + PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR); + } + + /* Count how many bytes we need */ + for (i = 0; i < utf16Length; i += 2) { + if ((utf16Char[i] == 0x00)&& + pkix_isPlaintext(utf16Char[i+1], debug)) { + if (utf16Char[i+1] == '&') { + /* Need to convert this to & */ + charLen -= 3; + } else { + /* We can fit this into one char */ + charLen -= 7; + } + } else if ((utf16Char[i] >= 0xD8) && (utf16Char[i] <= 0xDB)) { + if ((i+3) >= utf16Length) { + PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR); + } else if ((utf16Char[i+2] >= 0xDC)&& + (utf16Char[i+2] <= 0xDF)) { + /* Quartet of bytes will become &#xNNNNNNNN; */ + charLen -= 4; + /* Quartet of bytes will produce 12 chars */ + i += 2; + } else { + /* Second pair should be DC00-DFFF */ + PKIX_ERROR(PKIX_UTF16LOWZONEERROR); + } + } + } + + *pLength = charLen; + + /* Ensure this string is null terminated */ + charLen++; + + /* Allocate space for character array */ + PKIX_CHECK(PKIX_PL_Malloc(charLen, (void **)pDest, plContext), + PKIX_MALLOCFAILED); + + destPtr = *pDest; + for (i = 0; i < utf16Length; i += 2) { + if ((utf16Char[i] == 0x00)&& + pkix_isPlaintext(utf16Char[i+1], debug)) { + /* Write a single character */ + *destPtr++ = utf16Char[i+1]; + } else if ((utf16Char[i+1] == '&') && (utf16Char[i] == 0x00)){ + *destPtr++ = '&'; + *destPtr++ = 'a'; + *destPtr++ = 'm'; + *destPtr++ = 'p'; + *destPtr++ = ';'; + } else if ((utf16Char[i] >= 0xD8)&& + (utf16Char[i] <= 0xDB)&& + (utf16Char[i+2] >= 0xDC)&& + (utf16Char[i+2] <= 0xDF)) { + /* + * Special UTF pairs are of the form: + * x = D800..DBFF; y = DC00..DFFF; + * The result is of the form: + * ((x - D800) * 400 + (y - DC00)) + 0001 0000 + */ + x = 0x0FFFF & ((utf16Char[i]<<8) | utf16Char[i+1]); + y = 0x0FFFF & ((utf16Char[i+2]<<8) | utf16Char[i+3]); + z = ((x - 0xD800) * 0x400 + (y - 0xDC00)) + 0x00010000; + + /* Sprintf &#xNNNNNNNN; */ + PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n"); + if (PR_snprintf(destPtr, 13, "&#x%08X;", z) == + (PKIX_UInt32)(-1)) { + PKIX_ERROR(PKIX_PRSNPRINTFFAILED); + } + i += 2; + destPtr += 12; + } else { + /* Sprintf &#xNNNN; */ + PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n"); + if (PR_snprintf + (destPtr, + 9, + "&#x%02X%02X;", + utf16Char[i], + utf16Char[i+1]) == + (PKIX_UInt32)(-1)) { + PKIX_ERROR(PKIX_PRSNPRINTFFAILED); + } + destPtr += 8; + } + } + *destPtr = '\0'; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_FREE(*pDest); + } + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_EscASCII_to_UTF16 + * DESCRIPTION: + * + * Converts array of bytes pointed to by "escAsciiString" with length of + * "escAsciiLength" into a freshly allocated UTF-16 string and stores a + * pointer to that string at "pDest" and stores the string's length at + * "pLength". The caller is responsible for freeing "pDest" using + * PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug encoding. + * + * PARAMETERS: + * "escAsciiString" + * Address of array of bytes representing data source. Must be non-NULL. + * "escAsciiLength" + * Length of data source. Must be even. + * "debug" + * Boolean value indicating whether debug mode is desired. + * "pDest" + * Address where data will be stored. Must be non-NULL. + * "pLength" + * Address where data length 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 String 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_EscASCII_to_UTF16( + const char *escAsciiString, + PKIX_UInt32 escAsciiLen, + PKIX_Boolean debug, + void **pDest, + PKIX_UInt32 *pLength, + void *plContext) +{ + PKIX_UInt32 newLen, i, j, charSize; + PKIX_UInt32 x = 0, y = 0, z = 0; + unsigned char *destPtr = NULL; + unsigned char testChar, testChar2; + unsigned char *stringData = (unsigned char *)escAsciiString; + + PKIX_ENTER(STRING, "pkix_EscASCII_to_UTF16"); + PKIX_NULLCHECK_THREE(escAsciiString, pDest, pLength); + + if (escAsciiLen == 0) { + PKIX_CHECK(PKIX_PL_Malloc(escAsciiLen, pDest, plContext), + PKIX_MALLOCFAILED); + goto cleanup; + } + + /* Assume each unicode character takes two bytes */ + newLen = escAsciiLen*2; + + /* Count up number of unicode encoded characters */ + for (i = 0; i < escAsciiLen; i++) { + if (!pkix_isPlaintext(stringData[i], debug)&& + (stringData[i] != '&')) { + PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII); + } else if (PL_strstr(escAsciiString+i, "&") == + escAsciiString+i) { + /* Convert EscAscii "&" to two bytes */ + newLen -= 8; + i += 4; + } else if ((PL_strstr(escAsciiString+i, "&#x") == + escAsciiString+i)|| + (PL_strstr(escAsciiString+i, "&#X") == + escAsciiString+i)) { + if (((i+7) <= escAsciiLen)&& + (escAsciiString[i+7] == ';')) { + /* Convert &#xNNNN; to two bytes */ + newLen -= 14; + i += 7; + } else if (((i+11) <= escAsciiLen)&& + (escAsciiString[i+11] == ';')) { + /* Convert &#xNNNNNNNN; to four bytes */ + newLen -= 20; + i += 11; + } else { + PKIX_ERROR(PKIX_ILLEGALUSEOFAMP); + } + } + } + + PKIX_CHECK(PKIX_PL_Malloc(newLen, pDest, plContext), + PKIX_MALLOCFAILED); + + /* Copy into newly allocated space */ + destPtr = (unsigned char *)*pDest; + + i = 0; + while (i < escAsciiLen) { + /* Copy each byte until you hit a & */ + if (pkix_isPlaintext(escAsciiString[i], debug)) { + *destPtr++ = 0x00; + *destPtr++ = escAsciiString[i++]; + } else if (PL_strstr(escAsciiString+i, "&") == + escAsciiString+i) { + /* Convert EscAscii "&" to two bytes */ + *destPtr++ = 0x00; + *destPtr++ = '&'; + i += 5; + } else if (((PL_strstr(escAsciiString+i, "&#x") == + escAsciiString+i)|| + (PL_strstr(escAsciiString+i, "&#X") == + escAsciiString+i))&& + ((i+7) <= escAsciiLen)) { + + /* We're either looking at &#xNNNN; or &#xNNNNNNNN; */ + charSize = (escAsciiString[i+7] == ';')?4:8; + + /* Skip past the &#x */ + i += 3; + + /* Make sure there is a terminating semi-colon */ + if (((i+charSize) > escAsciiLen)|| + (escAsciiString[i+charSize] != ';')) { + PKIX_ERROR(PKIX_TRUNCATEDUNICODEINESCAPEDASCII); + } + + for (j = 0; j < charSize; j++) { + if (!PKIX_ISXDIGIT + (escAsciiString[i+j])) { + PKIX_ERROR(PKIX_ILLEGALUNICODECHARACTER); + } else if (charSize == 8) { + x |= (pkix_hex2i + (escAsciiString[i+j])) + <<(4*(7-j)); + } + } + + testChar = + (pkix_hex2i(escAsciiString[i])<<4)| + pkix_hex2i(escAsciiString[i+1]); + testChar2 = + (pkix_hex2i(escAsciiString[i+2])<<4)| + pkix_hex2i(escAsciiString[i+3]); + + if (charSize == 4) { + if ((testChar >= 0xD8)&& + (testChar <= 0xDF)) { + PKIX_ERROR(PKIX_ILLEGALSURROGATEPAIR); + } else if ((testChar == 0x00)&& + pkix_isPlaintext(testChar2, debug)) { + PKIX_ERROR( + PKIX_ILLEGALCHARACTERINESCAPEDASCII); + } + *destPtr++ = testChar; + *destPtr++ = testChar2; + } else if (charSize == 8) { + /* First two chars must be 0001-0010 */ + if (!((testChar == 0x00)&& + ((testChar2 >= 0x01)&& + (testChar2 <= 0x10)))) { + PKIX_ERROR( + PKIX_ILLEGALCHARACTERINESCAPEDASCII); + } + /* + * Unicode Strings of the form: + * x = 0001 0000..0010 FFFF + * Encoded as pairs of UTF-16 where + * y = ((x - 0001 0000) / 400) + D800 + * z = ((x - 0001 0000) % 400) + DC00 + */ + x -= 0x00010000; + y = (x/0x400)+ 0xD800; + z = (x%0x400)+ 0xDC00; + + /* Copy four bytes */ + *destPtr++ = (y&0xFF00)>>8; + *destPtr++ = (y&0x00FF); + *destPtr++ = (z&0xFF00)>>8; + *destPtr++ = (z&0x00FF); + } + /* Move past the Hex digits and the semi-colon */ + i += charSize+1; + } else { + /* Do not allow any other non-plaintext character */ + PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII); + } + } + + *pLength = newLen; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_FREE(*pDest); + } + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_UTF16_to_UTF8 + * DESCRIPTION: + * + * Converts array of bytes pointed to by "utf16String" with length of + * "utf16Length" into a freshly allocated UTF-8 string and stores a pointer + * to that string at "pDest" and stores the string's length at "pLength" (not + * counting the null terminator, if requested. The caller is responsible for + * freeing "pDest" using PKIX_PL_Free. + * + * PARAMETERS: + * "utf16String" + * Address of array of bytes representing data source. Must be non-NULL. + * "utf16Length" + * Length of data source. Must be even. + * "null-term" + * Boolean value indicating whether output should be null-terminated. + * "pDest" + * Address where data will be stored. Must be non-NULL. + * "pLength" + * Address where data length 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 String 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_UTF16_to_UTF8( + const void *utf16String, + PKIX_UInt32 utf16Length, + PKIX_Boolean null_term, + void **pDest, + PKIX_UInt32 *pLength, + void *plContext) +{ + PKIX_Boolean result; + PKIX_UInt32 reallocLen; + char *endPtr = NULL; + + PKIX_ENTER(STRING, "pkix_UTF16_to_UTF8"); + PKIX_NULLCHECK_THREE(utf16String, pDest, pLength); + + /* XXX How big can a UTF8 string be compared to a UTF16? */ + PKIX_CHECK(PKIX_PL_Calloc(1, utf16Length*2, pDest, plContext), + PKIX_CALLOCFAILED); + + PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n"); + result = PORT_UCS2_UTF8Conversion + (PKIX_FALSE, /* False = From UCS2 */ + (unsigned char *)utf16String, + utf16Length, + (unsigned char *)*pDest, + utf16Length*2, /* Max Size */ + pLength); + if (result == PR_FALSE){ + PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED); + } + + reallocLen = *pLength; + + if (null_term){ + reallocLen++; + } + + PKIX_CHECK(PKIX_PL_Realloc(*pDest, reallocLen, pDest, plContext), + PKIX_REALLOCFAILED); + + if (null_term){ + endPtr = (char*)*pDest + reallocLen - 1; + *endPtr = '\0'; + } + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_FREE(*pDest); + } + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_UTF8_to_UTF16 + * DESCRIPTION: + * + * Converts array of bytes pointed to by "utf8String" with length of + * "utf8Length" into a freshly allocated UTF-16 string and stores a pointer + * to that string at "pDest" and stores the string's length at "pLength". The + * caller is responsible for freeing "pDest" using PKIX_PL_Free. + * + * PARAMETERS: + * "utf8String" + * Address of array of bytes representing data source. Must be non-NULL. + * "utf8Length" + * Length of data source. Must be even. + * "pDest" + * Address where data will be stored. Must be non-NULL. + * "pLength" + * Address where data length 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 String 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_UTF8_to_UTF16( + const void *utf8String, + PKIX_UInt32 utf8Length, + void **pDest, + PKIX_UInt32 *pLength, + void *plContext) +{ + PKIX_Boolean result; + + PKIX_ENTER(STRING, "pkix_UTF8_to_UTF16"); + PKIX_NULLCHECK_THREE(utf8String, pDest, pLength); + + /* XXX How big can a UTF8 string be compared to a UTF16? */ + PKIX_CHECK(PKIX_PL_Calloc(1, utf8Length*2, pDest, plContext), + PKIX_MALLOCFAILED); + + PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n"); + result = PORT_UCS2_UTF8Conversion + (PKIX_TRUE, /* True = From UTF8 */ + (unsigned char *)utf8String, + utf8Length, + (unsigned char *)*pDest, + utf8Length*2, /* Max Size */ + pLength); + if (result == PR_FALSE){ + PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED); + } + + PKIX_CHECK(PKIX_PL_Realloc(*pDest, *pLength, pDest, plContext), + PKIX_REALLOCFAILED); + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_FREE(*pDest); + } + + PKIX_RETURN(STRING); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h new file mode 100644 index 0000000000..2946e07a67 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h @@ -0,0 +1,159 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_common.h + * + * Common central header file included by all PL source files + * + */ + +#ifndef _PKIX_PL_COMMON_H +#define _PKIX_PL_COMMON_H + +/* PKIX HEADERS */ +#include "pkix_tools.h" + +/* NSS headers */ +#include "nss.h" +#include "secport.h" +#include "secasn1.h" +#include "secerr.h" +#include "base64.h" +#include "cert.h" +#include "certdb.h" +#include "genname.h" +#include "xconst.h" +#include "keyhi.h" +#include "ocsp.h" +#include "ocspt.h" +#include "pk11pub.h" +#include "pkcs11.h" +#include "pkcs11t.h" +#include "prio.h" + +/* NSPR headers */ +#include "nspr.h" + +/* private PKIX_PL_NSS system headers */ +#include "pkix_pl_object.h" +#include "pkix_pl_string.h" +#ifndef NSS_PKIX_NO_LDAP +#include "pkix_pl_ldapt.h" +#endif /* !NSS_PKIX_NO_LDAP */ +#include "pkix_pl_aiamgr.h" +#include "pkix_pl_bigint.h" +#include "pkix_pl_oid.h" +#include "pkix_pl_x500name.h" +#include "pkix_pl_generalname.h" +#include "pkix_pl_publickey.h" +#include "pkix_pl_bytearray.h" +#include "pkix_pl_date.h" +#include "pkix_pl_primhash.h" +#include "pkix_pl_basicconstraints.h" +#include "pkix_pl_bytearray.h" +#include "pkix_pl_cert.h" +#include "pkix_pl_certpolicyinfo.h" +#include "pkix_pl_certpolicymap.h" +#include "pkix_pl_certpolicyqualifier.h" +#include "pkix_pl_crldp.h" +#include "pkix_pl_crl.h" +#include "pkix_pl_crlentry.h" +#include "pkix_pl_nameconstraints.h" +#include "pkix_pl_ocsprequest.h" +#include "pkix_pl_ocspresponse.h" +#include "pkix_pl_pk11certstore.h" +#include "pkix_pl_socket.h" +#ifndef NSS_PKIX_NO_LDAP +#include "pkix_pl_ldapcertstore.h" +#include "pkix_pl_ldaprequest.h" +#include "pkix_pl_ldapresponse.h" +#endif /* !NSS_PKIX_NO_LDAP */ +#include "pkix_pl_nsscontext.h" +#include "pkix_pl_httpcertstore.h" +#include "pkix_pl_httpdefaultclient.h" +#include "pkix_pl_infoaccess.h" +#include "pkix_sample_modules.h" + +#define MAX_DIGITS_32 (PKIX_UInt32) 10 + +#define PKIX_PL_NSSCALL(type, func, args) \ + PKIX_ ## type ## _DEBUG_ARG("( Calling %s).\n", #func); \ + (func args) + +#define PKIX_PL_NSSCALLRV(type, lvalue, func, args) \ + PKIX_ ## type ## _DEBUG_ARG("( Calling %s).\n", #func); \ + lvalue = (func args) + +/* see source file for function documentation */ + +PKIX_Error * +pkix_LockObject( + PKIX_PL_Object *object, + void *plContext); + +PKIX_Error * +pkix_UnlockObject( + PKIX_PL_Object *object, + void *plContext); + +PKIX_Boolean +pkix_pl_UInt32_Overflows(char *string); + +PKIX_Error * +pkix_pl_helperBytes2Ascii( + PKIX_UInt32 *tokens, + PKIX_UInt32 numTokens, + char **pAscii, + void *plContext); + +PKIX_Error * +pkix_pl_ipAddrBytes2Ascii( + SECItem *secItem, + char **pAscii, + void *plContext); + +PKIX_Error * +pkix_pl_oidBytes2Ascii( + SECItem *secItem, + char **pAscii, + void *plContext); + +/* --String-Encoding-Conversion-Functions------------------------ */ + +PKIX_Error * +pkix_UTF16_to_EscASCII( + const void *utf16String, + PKIX_UInt32 utf16Length, + PKIX_Boolean debug, + char **pDest, + PKIX_UInt32 *pLength, + void *plContext); + +PKIX_Error * +pkix_EscASCII_to_UTF16( + const char *escAsciiString, + PKIX_UInt32 escAsciiLen, + PKIX_Boolean debug, + void **pDest, + PKIX_UInt32 *pLength, + void *plContext); + +PKIX_Error * +pkix_UTF16_to_UTF8( + const void *utf16String, + PKIX_UInt32 utf16Length, + PKIX_Boolean null_Term, + void **pDest, + PKIX_UInt32 *pLength, + void *plContext); + +PKIX_Error * +pkix_UTF8_to_UTF16( + const void *utf8Source, + PKIX_UInt32 utf8Length, + void **pDest, + PKIX_UInt32 *pLength, + void *plContext); + +#endif /* _PKIX_PL_COMMON_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c new file mode 100644 index 0000000000..2631aed031 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_error.c + * + * PL error functions + * + */ + +#include "pkix_pl_common.h" + +#undef PKIX_ERRORENTRY + +#define PKIX_ERRORENTRY(name,desc,plerr) plerr + +const PKIX_Int32 PKIX_PLErrorIndex[] = +{ +#include "pkix_errorstrings.h" +}; + +int +PKIX_PL_GetPLErrorCode() +{ + return PORT_GetError(); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c new file mode 100644 index 0000000000..260365375e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c @@ -0,0 +1,383 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_hashtable.c + * + * Hashtable Object Functions + * + */ + +#include "pkix_pl_hashtable.h" + +/* --Private-Structure-------------------------------------------- */ + +struct PKIX_PL_HashTableStruct { + pkix_pl_PrimHashTable *primHash; + PKIX_PL_Mutex *tableLock; + PKIX_UInt32 maxEntriesPerBucket; +}; + +/* --Private-Functions-------------------------------------------- */ + +#define PKIX_MUTEX_UNLOCK(mutex) \ + do { \ + if (mutex && lockedMutex == (PKIX_PL_Mutex *)(mutex)) { \ + pkixTempResult = \ + PKIX_PL_Mutex_Unlock((mutex), plContext); \ + PORT_Assert(pkixTempResult == NULL); \ + if (pkixTempResult) { \ + PKIX_DoAddError(&stdVars, pkixTempResult, plContext); \ + pkixTempResult = NULL; \ + } \ + lockedMutex = NULL; \ + } else { \ + PORT_Assert(lockedMutex == NULL); \ + }\ + } while (0) + + +#define PKIX_MUTEX_LOCK(mutex) \ + do { \ + if (mutex){ \ + PORT_Assert(lockedMutex == NULL); \ + PKIX_CHECK(PKIX_PL_Mutex_Lock((mutex), plContext), \ + PKIX_MUTEXLOCKFAILED); \ + lockedMutex = (mutex); \ + } \ + } while (0) + +/* + * FUNCTION: pkix_pl_HashTable_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_HashTable_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_HashTable *ht = NULL; + pkix_pl_HT_Elem *item = NULL; + PKIX_UInt32 i; + + PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_HASHTABLE_TYPE, plContext), + PKIX_OBJECTNOTHASHTABLE); + + ht = (PKIX_PL_HashTable*) object; + + /* DecRef every object in the primitive hash table */ + for (i = 0; i < ht->primHash->size; i++) { + for (item = ht->primHash->buckets[i]; + item != NULL; + item = item->next) { + PKIX_DECREF(item->key); + PKIX_DECREF(item->value); + } + } + + PKIX_CHECK(pkix_pl_PrimHashTable_Destroy(ht->primHash, plContext), + PKIX_PRIMHASHTABLEDESTROYFAILED); + + PKIX_DECREF(ht->tableLock); + +cleanup: + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: pkix_pl_HashTable_RegisterSelf + * DESCRIPTION: + * Registers PKIX_HASHTABLE_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_HashTable_RegisterSelf( + void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_RegisterSelf"); + + entry.description = "HashTable"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_HashTable); + entry.destructor = pkix_pl_HashTable_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_HASHTABLE_TYPE] = entry; + + PKIX_RETURN(HASHTABLE); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_HashTable_Create (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Create( + PKIX_UInt32 numBuckets, + PKIX_UInt32 maxEntriesPerBucket, + PKIX_PL_HashTable **pResult, + void *plContext) +{ + PKIX_PL_HashTable *hashTable = NULL; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Create"); + PKIX_NULLCHECK_ONE(pResult); + + if (numBuckets == 0) { + PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO); + } + + /* Allocate a new hashtable */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_HASHTABLE_TYPE, + sizeof (PKIX_PL_HashTable), + (PKIX_PL_Object **)&hashTable, + plContext), + PKIX_COULDNOTCREATEHASHTABLEOBJECT); + + /* Create the underlying primitive hash table type */ + PKIX_CHECK(pkix_pl_PrimHashTable_Create + (numBuckets, &hashTable->primHash, plContext), + PKIX_PRIMHASHTABLECREATEFAILED); + + /* Create a lock for this table */ + PKIX_CHECK(PKIX_PL_Mutex_Create(&hashTable->tableLock, plContext), + PKIX_ERRORCREATINGTABLELOCK); + + hashTable->maxEntriesPerBucket = maxEntriesPerBucket; + + *pResult = hashTable; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(hashTable); + } + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: PKIX_PL_HashTable_Add (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Add( + PKIX_PL_HashTable *ht, + PKIX_PL_Object *key, + PKIX_PL_Object *value, + void *plContext) +{ + PKIX_PL_Mutex *lockedMutex = NULL; + PKIX_PL_Object *deletedKey = NULL; + PKIX_PL_Object *deletedValue = NULL; + PKIX_UInt32 hashCode; + PKIX_PL_EqualsCallback keyComp; + PKIX_UInt32 bucketSize = 0; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Add"); + +#if !defined(PKIX_OBJECT_LEAK_TEST) + PKIX_NULLCHECK_THREE(ht, key, value); +#else + PKIX_NULLCHECK_TWO(key, value); + + if (ht == NULL) { + PKIX_RETURN(HASHTABLE); + } +#endif + /* Insert into primitive hashtable */ + + PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext), + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback + (key, &keyComp, plContext), + PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED); + + PKIX_MUTEX_LOCK(ht->tableLock); + + PKIX_CHECK(pkix_pl_PrimHashTable_GetBucketSize + (ht->primHash, + hashCode, + &bucketSize, + plContext), + PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED); + + if (ht->maxEntriesPerBucket != 0 && + bucketSize >= ht->maxEntriesPerBucket) { + /* drop the last one in the bucket */ + PKIX_CHECK(pkix_pl_PrimHashTable_RemoveFIFO + (ht->primHash, + hashCode, + (void **) &deletedKey, + (void **) &deletedValue, + plContext), + PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED); + PKIX_DECREF(deletedKey); + PKIX_DECREF(deletedValue); + } + + PKIX_CHECK(pkix_pl_PrimHashTable_Add + (ht->primHash, + (void *)key, + (void *)value, + hashCode, + keyComp, + plContext), + PKIX_PRIMHASHTABLEADDFAILED); + + PKIX_INCREF(key); + PKIX_INCREF(value); + PKIX_MUTEX_UNLOCK(ht->tableLock); + + /* + * we don't call PKIX_PL_InvalidateCache here b/c we have + * not implemented toString or hashcode for this Object + */ + +cleanup: + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: PKIX_PL_HashTable_Remove (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Remove( + PKIX_PL_HashTable *ht, + PKIX_PL_Object *key, + void *plContext) +{ + PKIX_PL_Mutex *lockedMutex = NULL; + PKIX_PL_Object *origKey = NULL; + PKIX_PL_Object *value = NULL; + PKIX_UInt32 hashCode; + PKIX_PL_EqualsCallback keyComp; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Remove"); + +#if !defined(PKIX_OBJECT_LEAK_TEST) + PKIX_NULLCHECK_TWO(ht, key); +#else + PKIX_NULLCHECK_ONE(key); + + if (ht == NULL) { + PKIX_RETURN(HASHTABLE); + } +#endif + + PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext), + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback + (key, &keyComp, plContext), + PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED); + + PKIX_MUTEX_LOCK(ht->tableLock); + + /* Remove from primitive hashtable */ + PKIX_CHECK(pkix_pl_PrimHashTable_Remove + (ht->primHash, + (void *)key, + hashCode, + keyComp, + (void **)&origKey, + (void **)&value, + plContext), + PKIX_PRIMHASHTABLEREMOVEFAILED); + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_DECREF(origKey); + PKIX_DECREF(value); + + /* + * we don't call PKIX_PL_InvalidateCache here b/c we have + * not implemented toString or hashcode for this Object + */ + +cleanup: + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: PKIX_PL_HashTable_Lookup (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Lookup( + PKIX_PL_HashTable *ht, + PKIX_PL_Object *key, + PKIX_PL_Object **pResult, + void *plContext) +{ + PKIX_PL_Mutex *lockedMutex = NULL; + PKIX_UInt32 hashCode; + PKIX_PL_EqualsCallback keyComp; + PKIX_PL_Object *result = NULL; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Lookup"); + +#if !defined(PKIX_OBJECT_LEAK_TEST) + PKIX_NULLCHECK_THREE(ht, key, pResult); +#else + PKIX_NULLCHECK_TWO(key, pResult); + + if (ht == NULL) { + PKIX_RETURN(HASHTABLE); + } +#endif + + PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext), + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback + (key, &keyComp, plContext), + PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED); + + PKIX_MUTEX_LOCK(ht->tableLock); + + /* Lookup in primitive hashtable */ + PKIX_CHECK(pkix_pl_PrimHashTable_Lookup + (ht->primHash, + (void *)key, + hashCode, + keyComp, + (void **)&result, + plContext), + PKIX_PRIMHASHTABLELOOKUPFAILED); + + PKIX_INCREF(result); + PKIX_MUTEX_UNLOCK(ht->tableLock); + + *pResult = result; + +cleanup: + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_RETURN(HASHTABLE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h new file mode 100644 index 0000000000..479c623733 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_hashtable.h + * + * Hashtable Object Definition + * + */ + +#ifndef _PKIX_PL_HASHTABLE_H +#define _PKIX_PL_HASHTABLE_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_HashTable_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_HASHTABLE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c new file mode 100644 index 0000000000..70ed25d729 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c @@ -0,0 +1,279 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_lifecycle.c + * + * Lifecycle Functions for the PKIX PL library. + * + */ + +#include "pkix_pl_lifecycle.h" + +PKIX_Boolean pkix_pl_initialized = PKIX_FALSE; +pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; +PRLock *classTableLock; +PRLogModuleInfo *pkixLog = NULL; + +/* + * PKIX_ALLOC_ERROR is a special error object hard-coded into the + * pkix_error.o object file. It is thrown if system memory cannot be + * allocated. PKIX_ALLOC_ERROR is immutable. + * IncRef, DecRef, and Settor functions cannot be called. + */ + +/* Keep this structure definition here for its is used only once here */ +struct PKIX_Alloc_Error_ObjectStruct { + PKIX_PL_Object header; + PKIX_Error error; +}; +typedef struct PKIX_Alloc_Error_ObjectStruct PKIX_Alloc_Error_Object; + +static const PKIX_Alloc_Error_Object pkix_Alloc_Error_Data = { + { + PKIX_MAGIC_HEADER, /* PRUint64 magicHeader */ + (PKIX_UInt32)PKIX_ERROR_TYPE, /* PKIX_UInt32 type */ + (PKIX_UInt32)1, /* PKIX_UInt32 references */ + /* Warning! Cannot Ref Count with NULL lock */ + (void *)0, /* PRLock *lock */ + (PKIX_PL_String *)0, /* PKIX_PL_String *stringRep */ + (PKIX_UInt32)0, /* PKIX_UInt32 hashcode */ + (PKIX_Boolean)PKIX_FALSE, /* PKIX_Boolean hashcodeCached */ + }, { + (PKIX_ERRORCODE)0, /* PKIX_ERRORCODE errCode; */ + (PKIX_ERRORCLASS)PKIX_FATAL_ERROR,/* PKIX_ERRORCLASS errClass */ + (PKIX_UInt32)SEC_ERROR_LIBPKIX_INTERNAL, /* default PL Error Code */ + (PKIX_Error *)0, /* PKIX_Error *cause */ + (PKIX_PL_Object *)0, /* PKIX_PL_Object *info */ + } +}; + +PKIX_Error* PKIX_ALLOC_ERROR(void) +{ + return (PKIX_Error *)&pkix_Alloc_Error_Data.error; +} + +#ifdef PKIX_OBJECT_LEAK_TEST +SECStatus +pkix_pl_lifecycle_ObjectTableUpdate(int *objCountTable) +{ + int typeCounter = 0; + + for (; typeCounter < PKIX_NUMTYPES; typeCounter++) { + pkix_ClassTable_Entry *entry = &systemClasses[typeCounter]; + + objCountTable[typeCounter] = entry->objCounter; + } + + return SECSuccess; +} +#endif /* PKIX_OBJECT_LEAK_TEST */ + + +PKIX_UInt32 +pkix_pl_lifecycle_ObjectLeakCheck(int *initObjCountTable) +{ + unsigned int typeCounter = 0; + PKIX_UInt32 numObjects = 0; + char classNameBuff[128]; + char *className = NULL; + + for (; typeCounter < PKIX_NUMTYPES; typeCounter++) { + pkix_ClassTable_Entry *entry = &systemClasses[typeCounter]; + PKIX_UInt32 objCountDiff = entry->objCounter; + + if (initObjCountTable) { + PKIX_UInt32 initialCount = initObjCountTable[typeCounter]; + objCountDiff = (entry->objCounter > initialCount) ? + entry->objCounter - initialCount : 0; + } + + numObjects += objCountDiff; + + if (!pkixLog || !objCountDiff) { + continue; + } + className = entry->description; + if (!className) { + className = classNameBuff; + PR_snprintf(className, 128, "Unknown(ref %d)", + entry->objCounter); + } + + PR_LOG(pkixLog, 1, ("Class %s leaked %d objects of " + "size %d bytes, total = %d bytes\n", className, + objCountDiff, entry->typeObjectSize, + objCountDiff * entry->typeObjectSize)); + } + + return numObjects; +} + +/* + * PKIX_PL_Initialize (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Initialize( + PKIX_Boolean platformInitNeeded, + PKIX_Boolean useArenas, + void **pPlContext) +{ + void *plContext = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Initialize"); + + /* + * This function can only be called once. If it has already been + * called, we return a positive status. + */ + if (pkix_pl_initialized) { + PKIX_RETURN(OBJECT); + } + + classTableLock = PR_NewLock(); + if (classTableLock == NULL) { + return PKIX_ALLOC_ERROR(); + } + + if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) { + pkixLog = PR_NewLogModule("pkix"); + } + /* + * Register Object, it is the base object of all other objects. + */ + pkix_pl_Object_RegisterSelf(plContext); + + /* + * Register Error and String, since they will be needed if + * there is a problem in registering any other type. + */ + pkix_Error_RegisterSelf(plContext); + pkix_pl_String_RegisterSelf(plContext); + + + /* + * We register all other system types + * (They don't need to be in order, but it's + * easier to keep track of what types are registered + * if we register them in the same order as their + * numbers, defined in pkixt.h. + */ + pkix_pl_BigInt_RegisterSelf(plContext); /* 1-10 */ + pkix_pl_ByteArray_RegisterSelf(plContext); + pkix_pl_HashTable_RegisterSelf(plContext); + pkix_List_RegisterSelf(plContext); + pkix_Logger_RegisterSelf(plContext); + pkix_pl_Mutex_RegisterSelf(plContext); + pkix_pl_OID_RegisterSelf(plContext); + pkix_pl_RWLock_RegisterSelf(plContext); + + pkix_pl_CertBasicConstraints_RegisterSelf(plContext); /* 11-20 */ + pkix_pl_Cert_RegisterSelf(plContext); + pkix_pl_CRL_RegisterSelf(plContext); + pkix_pl_CRLEntry_RegisterSelf(plContext); + pkix_pl_Date_RegisterSelf(plContext); + pkix_pl_GeneralName_RegisterSelf(plContext); + pkix_pl_CertNameConstraints_RegisterSelf(plContext); + pkix_pl_PublicKey_RegisterSelf(plContext); + pkix_TrustAnchor_RegisterSelf(plContext); + + pkix_pl_X500Name_RegisterSelf(plContext); /* 21-30 */ + pkix_pl_HttpCertStoreContext_RegisterSelf(plContext); + pkix_BuildResult_RegisterSelf(plContext); + pkix_ProcessingParams_RegisterSelf(plContext); + pkix_ValidateParams_RegisterSelf(plContext); + pkix_ValidateResult_RegisterSelf(plContext); + pkix_CertStore_RegisterSelf(plContext); + pkix_CertChainChecker_RegisterSelf(plContext); + pkix_RevocationChecker_RegisterSelf(plContext); + pkix_CertSelector_RegisterSelf(plContext); + + pkix_ComCertSelParams_RegisterSelf(plContext); /* 31-40 */ + pkix_CRLSelector_RegisterSelf(plContext); + pkix_ComCRLSelParams_RegisterSelf(plContext); + pkix_pl_CertPolicyInfo_RegisterSelf(plContext); + pkix_pl_CertPolicyQualifier_RegisterSelf(plContext); + pkix_pl_CertPolicyMap_RegisterSelf(plContext); + pkix_PolicyNode_RegisterSelf(plContext); + pkix_TargetCertCheckerState_RegisterSelf(plContext); + pkix_BasicConstraintsCheckerState_RegisterSelf(plContext); + pkix_PolicyCheckerState_RegisterSelf(plContext); + + pkix_pl_CollectionCertStoreContext_RegisterSelf(plContext); /* 41-50 */ + pkix_CrlChecker_RegisterSelf(plContext); + pkix_ForwardBuilderState_RegisterSelf(plContext); + pkix_SignatureCheckerState_RegisterSelf(plContext); + pkix_NameConstraintsCheckerState_RegisterSelf(plContext); +#ifndef NSS_PKIX_NO_LDAP + pkix_pl_LdapRequest_RegisterSelf(plContext); + pkix_pl_LdapResponse_RegisterSelf(plContext); + pkix_pl_LdapDefaultClient_RegisterSelf(plContext); +#endif + pkix_pl_Socket_RegisterSelf(plContext); + + pkix_ResourceLimits_RegisterSelf(plContext); /* 51-59 */ + pkix_pl_MonitorLock_RegisterSelf(plContext); + pkix_pl_InfoAccess_RegisterSelf(plContext); + pkix_pl_AIAMgr_RegisterSelf(plContext); + pkix_OcspChecker_RegisterSelf(plContext); + pkix_pl_OcspCertID_RegisterSelf(plContext); + pkix_pl_OcspRequest_RegisterSelf(plContext); + pkix_pl_OcspResponse_RegisterSelf(plContext); + pkix_pl_HttpDefaultClient_RegisterSelf(plContext); + pkix_VerifyNode_RegisterSelf(plContext); + pkix_EkuChecker_RegisterSelf(plContext); + pkix_pl_CrlDp_RegisterSelf(plContext); + + if (pPlContext) { + PKIX_CHECK(PKIX_PL_NssContext_Create + (0, useArenas, NULL, &plContext), + PKIX_NSSCONTEXTCREATEFAILED); + + *pPlContext = plContext; + } + + pkix_pl_initialized = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * PKIX_PL_Shutdown (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Shutdown(void *plContext) +{ +#ifdef DEBUG + PKIX_UInt32 numLeakedObjects = 0; +#endif + + PKIX_ENTER(OBJECT, "PKIX_PL_Shutdown"); + + if (!pkix_pl_initialized) { + /* The library was not initilized */ + PKIX_RETURN(OBJECT); + } + + PR_DestroyLock(classTableLock); + + pkix_pl_HttpCertStore_Shutdown(plContext); + +#ifdef DEBUG + numLeakedObjects = pkix_pl_lifecycle_ObjectLeakCheck(NULL); + if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) { + PORT_Assert(numLeakedObjects == 0); + } +#else + pkix_pl_lifecycle_ObjectLeakCheck(NULL); +#endif + + if (plContext != NULL) { + PKIX_PL_NssContext_Destroy(plContext); + } + + pkix_pl_initialized = PKIX_FALSE; + + PKIX_RETURN(OBJECT); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h new file mode 100644 index 0000000000..9660af123d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_lifecycle.h + * + * Lifecycle Definitions + * + */ + +#ifndef _PKIX_PL_LIFECYCLE_H +#define _PKIX_PL_LIFECYCLE_H + +#include "pkix_pl_common.h" +#include "pkix_pl_oid.h" +#include "pkix_pl_aiamgr.h" +#include "pkix_pl_bigint.h" +#include "pkix_pl_bytearray.h" +#include "pkix_pl_hashtable.h" +#include "pkix_pl_mutex.h" +#include "pkix_pl_rwlock.h" +#include "pkix_pl_monitorlock.h" +#include "pkix_pl_string.h" +#include "pkix_pl_cert.h" +#include "pkix_pl_x500name.h" +#include "pkix_pl_generalname.h" +#include "pkix_pl_publickey.h" +#include "pkix_pl_date.h" +#include "pkix_pl_basicconstraints.h" +#include "pkix_pl_certpolicyinfo.h" +#include "pkix_pl_certpolicymap.h" +#include "pkix_pl_certpolicyqualifier.h" +#include "pkix_pl_crlentry.h" +#include "pkix_pl_crl.h" +#include "pkix_pl_colcertstore.h" +#ifndef NSS_PKIX_NO_LDAP +#include "pkix_pl_ldapcertstore.h" +#include "pkix_pl_ldapdefaultclient.h" +#include "pkix_pl_ldaprequest.h" +#include "pkix_pl_ldapresponse.h" +#endif /* !NSS_PKIX_NO_LDAP */ +#include "pkix_pl_socket.h" +#include "pkix_pl_infoaccess.h" +#include "pkix_store.h" +#include "pkix_error.h" +#include "pkix_logger.h" +#include "pkix_list.h" +#include "pkix_trustanchor.h" +#include "pkix_procparams.h" +#include "pkix_valparams.h" +#include "pkix_valresult.h" +#include "pkix_verifynode.h" +#include "pkix_resourcelimits.h" +#include "pkix_certchainchecker.h" +#include "pkix_revocationchecker.h" +#include "pkix_certselector.h" +#include "pkix_comcertselparams.h" +#include "pkix_crlselector.h" +#include "pkix_comcrlselparams.h" +#include "pkix_targetcertchecker.h" +#include "pkix_basicconstraintschecker.h" +#include "pkix_policynode.h" +#include "pkix_policychecker.h" +#include "pkix_crlchecker.h" +#include "pkix_signaturechecker.h" +#include "pkix_buildresult.h" +#include "pkix_build.h" +#include "pkix_pl_nameconstraints.h" +#include "pkix_nameconstraintschecker.h" +#include "pkix_ocspchecker.h" +#include "pkix_pl_ocspcertid.h" +#include "pkix_pl_ocsprequest.h" +#include "pkix_pl_ocspresponse.h" +#include "pkix_pl_httpdefaultclient.h" +#include "pkix_pl_httpcertstore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_InitializeParamsStruct { + PKIX_List *loggers; + PKIX_UInt32 majorVersion; + PKIX_UInt32 minorVersion; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_LIFECYCLE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c new file mode 100644 index 0000000000..d75c0be26e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c @@ -0,0 +1,168 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_mem.c + * + * Memory Management Functions + * + */ + +#include "pkix_pl_mem.h" + +/* + * FUNCTION: PKIX_PL_Malloc (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Malloc( + PKIX_UInt32 size, + void **pMemory, + void *plContext) +{ + PKIX_PL_NssContext *nssContext = NULL; + void *result = NULL; + + PKIX_ENTER(MEM, "PKIX_PL_Malloc"); + PKIX_NULLCHECK_ONE(pMemory); + + if (size == 0){ + *pMemory = NULL; + } else { + + nssContext = (PKIX_PL_NssContext *)plContext; + + if (nssContext != NULL && nssContext->arena != NULL) { + PKIX_MEM_DEBUG("\tCalling PORT_ArenaAlloc.\n"); + *pMemory = PORT_ArenaAlloc(nssContext->arena, size); + } else { + PKIX_MEM_DEBUG("\tCalling PR_Malloc.\n"); + result = (void *) PR_Malloc(size); + + if (result == NULL) { + PKIX_MEM_DEBUG("Fatal Error Occurred: " + "PR_Malloc failed.\n"); + PKIX_ERROR_ALLOC_ERROR(); + } else { + *pMemory = result; + } + } + } + +cleanup: + PKIX_RETURN(MEM); +} + +/* + * FUNCTION: PKIX_PL_Calloc (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Calloc( + PKIX_UInt32 nElem, + PKIX_UInt32 elSize, + void **pMemory, + void *plContext) +{ + PKIX_PL_NssContext *nssContext = NULL; + void *result = NULL; + + PKIX_ENTER(MEM, "PKIX_PL_Calloc"); + PKIX_NULLCHECK_ONE(pMemory); + + if ((nElem == 0) || (elSize == 0)){ + *pMemory = NULL; + } else { + + nssContext = (PKIX_PL_NssContext *)plContext; + + if (nssContext != NULL && nssContext->arena != NULL) { + PKIX_MEM_DEBUG("\tCalling PORT_ArenaAlloc.\n"); + *pMemory = PORT_ArenaAlloc(nssContext->arena, elSize); + } else { + PKIX_MEM_DEBUG("\tCalling PR_Calloc.\n"); + result = (void *) PR_Calloc(nElem, elSize); + + if (result == NULL) { + PKIX_MEM_DEBUG("Fatal Error Occurred: " + "PR_Calloc failed.\n"); + PKIX_ERROR_ALLOC_ERROR(); + } else { + *pMemory = result; + } + } + } + +cleanup: + + PKIX_RETURN(MEM); +} + +/* + * FUNCTION: PKIX_PL_Realloc (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Realloc( + void *ptr, + PKIX_UInt32 size, + void **pMemory, + void *plContext) +{ + PKIX_PL_NssContext *nssContext = NULL; + void *result = NULL; + + PKIX_ENTER(MEM, "PKIX_PL_Realloc"); + PKIX_NULLCHECK_ONE(pMemory); + + nssContext = (PKIX_PL_NssContext *)plContext; + + if (nssContext != NULL && nssContext->arena != NULL) { + PKIX_MEM_DEBUG("\tCalling PORT_ArenaAlloc.\n"); + result = PORT_ArenaAlloc(nssContext->arena, size); + + if (result){ + PKIX_MEM_DEBUG("\tCalling PORT_Memcpy.\n"); + PORT_Memcpy(result, ptr, size); + } + *pMemory = result; + } else { + PKIX_MEM_DEBUG("\tCalling PR_Realloc.\n"); + result = (void *) PR_Realloc(ptr, size); + + if (result == NULL) { + if (size == 0){ + *pMemory = NULL; + } else { + PKIX_MEM_DEBUG + ("Fatal Error Occurred: " + "PR_Realloc failed.\n"); + PKIX_ERROR_ALLOC_ERROR(); + } + } else { + *pMemory = result; + } + } + +cleanup: + + PKIX_RETURN(MEM); +} + +/* + * FUNCTION: PKIX_PL_Free (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Free( + void *ptr, + /* ARGSUSED */ void *plContext) +{ + PKIX_PL_NssContext *context = NULL; + + PKIX_ENTER(MEM, "PKIX_PL_Free"); + + context = (PKIX_PL_NssContext *) plContext; + if (context == NULL || context->arena == NULL) { + PKIX_MEM_DEBUG("\tCalling PR_Free.\n"); + (void) PR_Free(ptr); + } + + PKIX_RETURN(MEM); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h new file mode 100644 index 0000000000..eaec6246c9 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_mem.h + * + * Memory Management Definitions + * + */ + +#ifndef _PKIX_PL_MEM_H +#define _PKIX_PL_MEM_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_MEM_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c new file mode 100644 index 0000000000..a5d2fc9621 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c @@ -0,0 +1,136 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_monitorlock.c + * + * Read/Write Lock Functions + * + */ + +#include "pkix_pl_monitorlock.h" + +/* --Private-Functions-------------------------------------------- */ + +static PKIX_Error * +pkix_pl_MonitorLock_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_MonitorLock* monitorLock = NULL; + + PKIX_ENTER(MONITORLOCK, "pkix_pl_MonitorLock_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_MONITORLOCK_TYPE, plContext), + PKIX_OBJECTNOTMONITORLOCK); + + monitorLock = (PKIX_PL_MonitorLock*) object; + + PKIX_MONITORLOCK_DEBUG("Calling PR_DestroyMonitor)\n"); + PR_DestroyMonitor(monitorLock->lock); + monitorLock->lock = NULL; + +cleanup: + + PKIX_RETURN(MONITORLOCK); +} + +/* + * FUNCTION: pkix_pl_MonitorLock_RegisterSelf + * DESCRIPTION: + * Registers PKIX_MONITORLOCK_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_MonitorLock_RegisterSelf( + void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(MONITORLOCK, "pkix_pl_MonitorLock_RegisterSelf"); + + entry.description = "MonitorLock"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_MonitorLock); + entry.destructor = pkix_pl_MonitorLock_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_MONITORLOCK_TYPE] = entry; + + PKIX_RETURN(MONITORLOCK); +} + +/* --Public-Functions--------------------------------------------- */ + +PKIX_Error * +PKIX_PL_MonitorLock_Create( + PKIX_PL_MonitorLock **pNewLock, + void *plContext) +{ + PKIX_PL_MonitorLock *monitorLock = NULL; + + PKIX_ENTER(MONITORLOCK, "PKIX_PL_MonitorLock_Create"); + PKIX_NULLCHECK_ONE(pNewLock); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_MONITORLOCK_TYPE, + sizeof (PKIX_PL_MonitorLock), + (PKIX_PL_Object **)&monitorLock, + plContext), + PKIX_ERRORALLOCATINGMONITORLOCK); + + PKIX_MONITORLOCK_DEBUG("\tCalling PR_NewMonitor)\n"); + monitorLock->lock = PR_NewMonitor(); + + if (monitorLock->lock == NULL) { + PKIX_DECREF(monitorLock); + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + *pNewLock = monitorLock; + +cleanup: + + PKIX_RETURN(MONITORLOCK); +} + +PKIX_Error * +PKIX_PL_MonitorLock_Enter( + PKIX_PL_MonitorLock *monitorLock, + void *plContext) +{ + PKIX_ENTER_NO_LOGGER(MONITORLOCK, "PKIX_PL_MonitorLock_Enter"); + PKIX_NULLCHECK_ONE(monitorLock); + + PKIX_MONITORLOCK_DEBUG("\tCalling PR_EnterMonitor)\n"); + (void) PR_EnterMonitor(monitorLock->lock); + + PKIX_RETURN_NO_LOGGER(MONITORLOCK); +} + +PKIX_Error * +PKIX_PL_MonitorLock_Exit( + PKIX_PL_MonitorLock *monitorLock, + void *plContext) +{ + PKIX_ENTER_NO_LOGGER(MONITORLOCK, "PKIX_PL_MonitorLock_Exit"); + PKIX_NULLCHECK_ONE(monitorLock); + + PKIX_MONITORLOCK_DEBUG("\tCalling PR_ExitMonitor)\n"); + PR_ExitMonitor(monitorLock->lock); + + PKIX_RETURN_NO_LOGGER(MONITORLOCK); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h new file mode 100644 index 0000000000..76ac539ad8 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_monitorlock.h + * + * Read/Write Lock Definition + * + */ + +#ifndef _PKIX_PL_MONITORLOCK_H +#define _PKIX_PL_MONITORLOCK_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_MonitorLockStruct { + PRMonitor* lock; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_MonitorLock_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_MONITORLOCK_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c new file mode 100644 index 0000000000..07d13695b5 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c @@ -0,0 +1,163 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_mutex.c + * + * Mutual Exclusion (Lock) Object Functions + * + */ + +#include "pkix_pl_mutex.h" + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_Mutex_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Mutex_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Mutex *mutex = NULL; + + PKIX_ENTER(MUTEX, "pkix_pl_Mutex_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Sanity check: Test that "object" is a mutex */ + PKIX_CHECK(pkix_CheckType(object, PKIX_MUTEX_TYPE, plContext), + PKIX_OBJECTNOTMUTEX); + + mutex = (PKIX_PL_Mutex*) object; + + PKIX_MUTEX_DEBUG("\tCalling PR_DestroyLock).\n"); + PR_DestroyLock(mutex->lock); + mutex->lock = NULL; + +cleanup: + + PKIX_RETURN(MUTEX); +} + +/* + * FUNCTION: pkix_pl_Mutex_RegisterSelf + * DESCRIPTION: + * Registers PKIX_MUTEX_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_Mutex_RegisterSelf( + /* ARGSUSED */ void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(MUTEX, "pkix_pl_Mutex_RegisterSelf"); + + entry.description = "Mutex"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_Mutex); + entry.destructor = pkix_pl_Mutex_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_MUTEX_TYPE] = entry; + + PKIX_RETURN(MUTEX); +} + +/* --Public-Functions--------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_Mutex_Create (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Mutex_Create( + PKIX_PL_Mutex **pNewLock, + void *plContext) +{ + PKIX_PL_Mutex *mutex = NULL; + + PKIX_ENTER(MUTEX, "PKIX_PL_Mutex_Create"); + PKIX_NULLCHECK_ONE(pNewLock); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_MUTEX_TYPE, + sizeof (PKIX_PL_Mutex), + (PKIX_PL_Object **)&mutex, + plContext), + PKIX_COULDNOTCREATELOCKOBJECT); + + PKIX_MUTEX_DEBUG("\tCalling PR_NewLock).\n"); + mutex->lock = PR_NewLock(); + + /* If an error occurred in NSPR, report it here */ + if (mutex->lock == NULL) { + PKIX_DECREF(mutex); + PKIX_ERROR_ALLOC_ERROR(); + } + + *pNewLock = mutex; + +cleanup: + + PKIX_RETURN(MUTEX); +} + +/* + * FUNCTION: PKIX_PL_Mutex_Lock (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Mutex_Lock( + PKIX_PL_Mutex *mutex, + void *plContext) +{ + PKIX_ENTER(MUTEX, "PKIX_PL_Mutex_Lock"); + PKIX_NULLCHECK_ONE(mutex); + + PKIX_MUTEX_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(mutex->lock); + + PKIX_MUTEX_DEBUG_ARG("(Thread %u just acquired the lock)\n", + (PKIX_UInt32)PR_GetCurrentThread()); + + PKIX_RETURN(MUTEX); +} + +/* + * FUNCTION: PKIX_PL_Mutex_Unlock (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Mutex_Unlock( + PKIX_PL_Mutex *mutex, + void *plContext) +{ + PRStatus result; + + PKIX_ENTER(MUTEX, "PKIX_PL_Mutex_Unlock"); + PKIX_NULLCHECK_ONE(mutex); + + PKIX_MUTEX_DEBUG("\tCalling PR_Unlock).\n"); + result = PR_Unlock(mutex->lock); + + PKIX_MUTEX_DEBUG_ARG("(Thread %u just released the lock)\n", + (PKIX_UInt32)PR_GetCurrentThread()); + + if (result == PR_FAILURE) { + PKIX_ERROR_FATAL(PKIX_ERRORUNLOCKINGMUTEX); + } + +cleanup: + PKIX_RETURN(MUTEX); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h new file mode 100644 index 0000000000..baf16fea92 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_mutex.h + * + * Mutual Exclusion (Lock) Object Type Definition + * + */ + +#ifndef _PKIX_PL_MUTEX_H +#define _PKIX_PL_MUTEX_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_MutexStruct { + PRLock* lock; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_Mutex_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_MUTEX_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c new file mode 100644 index 0000000000..7dafa0b204 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c @@ -0,0 +1,1440 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_object.c + * + * Object Construction, Destruction and Callback Functions + * + */ + +#include "pkix_pl_object.h" + +#ifdef PKIX_USER_OBJECT_TYPE +/* --Class-Table-Initializers------------------------------------ */ + +/* + * Create storage space for 20 Class Table buckets. + * These are only for user-defined types. System types are registered + * separately by PKIX_PL_Initialize. + */ + +static pkix_pl_HT_Elem* +pkix_Raw_ClassTable_Buckets[] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +/* + * Allocate static memory for a ClassTable. + * XXX This assumes the bucket pointer will fit into a PKIX_UInt32 + */ +static pkix_pl_PrimHashTable pkix_Raw_ClassTable = { + (void *)pkix_Raw_ClassTable_Buckets, /* Buckets */ + 20 /* Number of Buckets */ +}; +static pkix_pl_PrimHashTable * classTable = &pkix_Raw_ClassTable; +#endif /* PKIX_USER_OBJECT_TYPE */ + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_Object_GetHeader + * DESCRIPTION: + * + * Shifts Object pointed to by "object" by the sizeof(PKIX_PL_Object) and + * stores the value at "pObjectHeader". + * + * PARAMETERS: + * "object" + * Address of Object to shift. Must be non-NULL. + * "pObjectHeader" + * 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 Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Object_GetHeader( + PKIX_PL_Object *object, + PKIX_PL_Object **pObjectHeader, + void *plContext) +{ + PKIX_PL_Object *header = NULL; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_GetHeader"); + PKIX_NULLCHECK_TWO(object, pObjectHeader); + + PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); + + /* The header is sizeof(PKIX_PL_Object) before the object pointer */ + header = (PKIX_PL_Object *)((char *)object - sizeof(PKIX_PL_Object)); + + objType = header->type; + + if (objType >= PKIX_NUMTYPES) { /* if this is a user-defined type */ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + + PKIX_CHECK(pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext), + PKIX_ERRORGETTINGCLASSTABLEENTRY); + + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (ctEntry == NULL) { + PKIX_ERROR_FATAL(PKIX_UNKNOWNOBJECTTYPE); + } +#else + PORT_Assert(objType < PKIX_NUMTYPES); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } + +#ifdef PKIX_OBJECT_LEAK_TEST + PORT_Assert(header && header->magicHeader == PKIX_MAGIC_HEADER); +#endif /* PKIX_OBJECT_LEAK_TEST */ + + if ((header == NULL)|| + (header->magicHeader != PKIX_MAGIC_HEADER)) { + PKIX_ERROR_ALLOC_ERROR(); + } + + *pObjectHeader = header; + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_Destroy_Object + * DESCRIPTION: + * + * Destroys and deallocates Object pointed to by "object". The caller is + * assumed to hold the Object's lock, which is acquired in + * PKIX_PL_Object_DecRef(). + * + * PARAMETERS: + * "object" + * Address of Object to destroy. 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. + */ +static PKIX_Error * +pkix_pl_Object_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_Destroy"); + PKIX_NULLCHECK_ONE(object); + +#ifdef PKIX_OBJECT_LEAK_TEST + PKIX_CHECK_FATAL(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); +#else + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); +#endif /* PKIX_OBJECT_LEAK_TEST */ + + /* Attempt to delete an object still being used */ + if (objectHeader->references != 0) { + PKIX_ERROR_FATAL(PKIX_OBJECTSTILLREFERENCED); + } + + PKIX_DECREF(objectHeader->stringRep); + + /* Destroy this object's lock */ + PKIX_OBJECT_DEBUG("\tCalling PR_DestroyLock).\n"); + PR_DestroyLock(objectHeader->lock); + objectHeader->lock = NULL; + object = NULL; + + objectHeader->magicHeader = PKIX_MAGIC_HEADER_DESTROYED; + +#ifdef PKIX_OBJECT_LEAK_TEST + memset(objectHeader, 0xbf, systemClasses[PKIX_OBJECT_TYPE].typeObjectSize); +#endif + + PKIX_FREE(objectHeader); + +cleanup: +#ifdef PKIX_OBJECT_LEAK_TEST +fatal: +#endif + + PKIX_RETURN(OBJECT); +} + +/* --Default-Callbacks-------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_Object_Equals_Default + * DESCRIPTION: + * + * Default Object_Equals callback: Compares the address of the Object pointed + * to by "firstObject" with the address of the Object pointed to by + * "secondObject" and stores the Boolean result at "pResult". + * + * PARAMETERS: + * "firstObject" + * Address of first Object to compare. Must be non-NULL. + * "secondObject" + * Address of second Object to compare. Must be non-NULL. + * "pResult" + * Address where Boolean result 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. + */ +static PKIX_Error * +pkix_pl_Object_Equals_Default( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_ENTER(OBJECT, "pkix_pl_Object_Equals_Default"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* Just compare pointer values */ + *pResult = (firstObject == secondObject)?PKIX_TRUE:PKIX_FALSE; + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_ToString_Default + * DESCRIPTION: + * + * Default Object_ToString callback: Creates a string consisting of the + * typename and address of the Object pointed to by "object" and stores + * the result at "pString". The format for the string is + * "TypeName@Address: <address>", where the default typename is "Object". + * + * PARAMETERS: + * "object" + * Address of Object to convert to a string. Must be non-NULL. + * "pString" + * 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 an Object 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_Object_ToString_Default( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *descString = NULL; + char *format = "%s@Address: %x"; + char *description = NULL; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_ToString_Default"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(PKIX_PL_Object_GetType(object, &objType, plContext), + PKIX_OBJECTGETTYPEFAILED); + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if (ctEntry == NULL){ + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCLASSTABLEENTRY); + } else { + description = ctEntry->description; + if (description == NULL) { + description = "User Type Object"; + } + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + description = systemClasses[objType].description; + } + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + (void *)format, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + (void *)description, + 0, + &descString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (pString, + plContext, + formatString, + descString, + object), + PKIX_SPRINTFFAILED); + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(descString); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_Hashcode_Default + * DESCRIPTION: + * + * Default Object_Hashcode callback. Creates the a hashcode value using the + * address of the Object pointed to by "object" and stores the result at + * "pValue". + * + * XXX This isn't great since addresses are not uniformly distributed. + * + * PARAMETERS: + * "object" + * Address of Object to compute hashcode for. Must be non-NULL. + * "pValue" + * Address where PKIX_UInt32 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. + */ +static PKIX_Error * +pkix_pl_Object_Hashcode_Default( + PKIX_PL_Object *object, + PKIX_UInt32 *pValue, + void *plContext) +{ + PKIX_ENTER(OBJECT, "pkix_pl_Object_Hashcode_Default"); + PKIX_NULLCHECK_TWO(object, pValue); + + *pValue = (PKIX_UInt32)((char *)object - (char *)NULL); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_RetrieveEqualsCallback + * DESCRIPTION: + * + * Retrieves Equals callback function of Object pointed to by "object and + * stores it at "pEqualsCallback". If the object's type is one of the system + * types, its callback function is retrieved from the systemClasses array; + * otherwise, its callback function is retrieve from the classTable hash + * table where user-defined types are stored. + * + * PARAMETERS: + * "object" + * Address of Object whose equals callback is desired. Must be non-NULL. + * "pEqualsCallback" + * Address where EqualsCallback function 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 an Object 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_Object_RetrieveEqualsCallback( + PKIX_PL_Object *object, + PKIX_PL_EqualsCallback *pEqualsCallback, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_EqualsCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_RetrieveEqualsCallback"); + PKIX_NULLCHECK_TWO(object, pEqualsCallback); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + objType = objectHeader->type; + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) { + PKIX_ERROR(PKIX_UNDEFINEDEQUALSCALLBACK); + } else { + *pEqualsCallback = ctEntry->equalsFunction; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.equalsFunction; + if (func == NULL){ + func = pkix_pl_Object_Equals_Default; + } + *pEqualsCallback = func; + } + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OBJECT_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_PL_Object should have all function pointes to be to NULL: they + * work as proxy function to a real objects. + * + */ +PKIX_Error * +pkix_pl_Object_RegisterSelf(void *plContext) +{ + pkix_ClassTable_Entry entry; + + PKIX_ENTER(ERROR, "pkix_pl_Object_RegisterSelf"); + + entry.description = "Object"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_Object); + entry.destructor = NULL; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_OBJECT_TYPE] = entry; + + PKIX_RETURN(ERROR); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_Object_Alloc (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Alloc( + PKIX_TYPENUM objType, + PKIX_UInt32 size, + PKIX_PL_Object **pObject, + void *plContext) +{ + PKIX_PL_Object *object = NULL; + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Alloc"); + PKIX_NULLCHECK_ONE(pObject); + + /* + * We need to ensure that user-defined types have been registered. + * All system types have already been registered by PKIX_PL_Initialize. + */ + + if (objType >= PKIX_NUMTYPES) { /* i.e. if this is a user-defined type */ +#ifdef PKIX_USER_OBJECT_TYPE + PKIX_Boolean typeRegistered; + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE); + } + + typeRegistered = (ctEntry != NULL); + + if (!typeRegistered) { + PKIX_ERROR_FATAL(PKIX_UNKNOWNTYPEARGUMENT); + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + ctEntry = &systemClasses[objType]; + } + + PORT_Assert(size == ctEntry->typeObjectSize); + + /* Allocate space for the object header and the requested size */ +#ifdef PKIX_OBJECT_LEAK_TEST + PKIX_CHECK(PKIX_PL_Calloc + (1, + ((PKIX_UInt32)sizeof (PKIX_PL_Object))+size, + (void **)&object, + plContext), + PKIX_MALLOCFAILED); +#else + PKIX_CHECK(PKIX_PL_Malloc + (((PKIX_UInt32)sizeof (PKIX_PL_Object))+size, + (void **)&object, + plContext), + PKIX_MALLOCFAILED); +#endif /* PKIX_OBJECT_LEAK_TEST */ + + /* Initialize all object fields */ + object->magicHeader = PKIX_MAGIC_HEADER; + object->type = objType; + object->references = 1; /* Default to a single reference */ + object->stringRep = NULL; + object->hashcode = 0; + object->hashcodeCached = 0; + + /* Cannot use PKIX_PL_Mutex because it depends on Object */ + /* Using NSPR Locks instead */ + PKIX_OBJECT_DEBUG("\tCalling PR_NewLock).\n"); + object->lock = PR_NewLock(); + if (object->lock == NULL) { + PKIX_ERROR_ALLOC_ERROR(); + } + + PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); + + + /* Return a pointer to the user data. Need to offset by object size */ + *pObject = object + 1; + object = NULL; + + /* Atomically increment object counter */ + PR_ATOMIC_INCREMENT((PRInt32*)&ctEntry->objCounter); + +cleanup: + + PKIX_FREE(object); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_IsTypeRegistered (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_IsTypeRegistered( + PKIX_UInt32 objType, + PKIX_Boolean *pBool, + void *plContext) +{ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; +#endif + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_IsTypeRegistered"); + PKIX_NULLCHECK_ONE(pBool); + + /* first, we handle the system types */ + if (objType < PKIX_NUMTYPES) { + *pBool = PKIX_TRUE; + goto cleanup; + } + +#ifndef PKIX_USER_OBJECT_TYPE + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; +#else + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE); + } + + *pBool = (ctEntry != NULL); +#endif /* PKIX_USER_OBJECT_TYPE */ + +cleanup: + + PKIX_RETURN(OBJECT); +} + +#ifdef PKIX_USER_OBJECT_TYPE +/* + * FUNCTION: PKIX_PL_Object_RegisterType (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_RegisterType( + PKIX_UInt32 objType, + char *description, + PKIX_PL_DestructorCallback destructor, + PKIX_PL_EqualsCallback equalsFunction, + PKIX_PL_HashcodeCallback hashcodeFunction, + PKIX_PL_ToStringCallback toStringFunction, + PKIX_PL_ComparatorCallback comparator, + PKIX_PL_DuplicateCallback duplicateFunction, + void *plContext) +{ + pkix_ClassTable_Entry *ctEntry = NULL; + pkix_pl_Integer *key = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_RegisterType"); + + /* + * System types are registered on startup by PKIX_PL_Initialize. + * These can not be overwritten. + */ + + if (objType < PKIX_NUMTYPES) { /* if this is a system type */ + PKIX_ERROR(PKIX_CANTREREGISTERSYSTEMTYPE); + } + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + PKIX_CHECK(pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext), + PKIX_PRIMHASHTABLELOOKUPFAILED); + + /* If the type is already registered, throw an error */ + if (ctEntry) { + PKIX_ERROR(PKIX_TYPEALREADYREGISTERED); + } + + PKIX_CHECK(PKIX_PL_Malloc + (((PKIX_UInt32)sizeof (pkix_ClassTable_Entry)), + (void **)&ctEntry, + plContext), + PKIX_MALLOCFAILED); + + /* Set Default Values if none specified */ + + if (description == NULL){ + description = "Object"; + } + + if (equalsFunction == NULL) { + equalsFunction = pkix_pl_Object_Equals_Default; + } + + if (toStringFunction == NULL) { + toStringFunction = pkix_pl_Object_ToString_Default; + } + + if (hashcodeFunction == NULL) { + hashcodeFunction = pkix_pl_Object_Hashcode_Default; + } + + ctEntry->destructor = destructor; + ctEntry->equalsFunction = equalsFunction; + ctEntry->toStringFunction = toStringFunction; + ctEntry->hashcodeFunction = hashcodeFunction; + ctEntry->comparator = comparator; + ctEntry->duplicateFunction = duplicateFunction; + ctEntry->description = description; + + PKIX_CHECK(PKIX_PL_Malloc + (((PKIX_UInt32)sizeof (pkix_pl_Integer)), + (void **)&key, + plContext), + PKIX_COULDNOTMALLOCNEWKEY); + + key->ht_int = objType; + + PKIX_CHECK(pkix_pl_PrimHashTable_Add + (classTable, + (void *)key, + (void *)ctEntry, + objType, + NULL, + plContext), + PKIX_PRIMHASHTABLEADDFAILED); + +cleanup: + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + PKIX_RETURN(OBJECT); +} +#endif /* PKIX_USER_OBJECT_TYPE */ + +/* + * FUNCTION: PKIX_PL_Object_IncRef (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_IncRef( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_NssContext *context = NULL; + PKIX_Int32 refCount = 0; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_IncRef"); + PKIX_NULLCHECK_ONE(object); + + if (plContext){ + /* + * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't + * have a header therefore we cannot verify its type before + * casting. + */ + context = (PKIX_PL_NssContext *) plContext; + if (context->arena != NULL) { + goto cleanup; + } + } + + if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) { + goto cleanup; + } + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* This object should never have zero references */ + refCount = PR_ATOMIC_INCREMENT(&objectHeader->references); + + if (refCount <= 1) { + PKIX_THROW(FATAL, PKIX_OBJECTWITHNONPOSITIVEREFERENCES); + } + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_DecRef (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_DecRef( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_Int32 refCount = 0; + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_NssContext *context = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_DecRef"); + PKIX_NULLCHECK_ONE(object); + + if (plContext){ + /* + * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't + * have a header therefore we cannot verify its type before + * casting. + */ + context = (PKIX_PL_NssContext *) plContext; + if (context->arena != NULL) { + goto cleanup; + } + } + + if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) { + goto cleanup; + } + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + refCount = PR_ATOMIC_DECREMENT(&objectHeader->references); + + if (refCount == 0) { + PKIX_PL_DestructorCallback destructor = NULL; + pkix_ClassTable_Entry *ctEntry = NULL; + PKIX_UInt32 objType = objectHeader->type; + + /* first, special handling for system types */ + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG + ("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL + (PKIX_ERRORINGETTINGDESTRUCTOR); + } + + if (ctEntry != NULL){ + destructor = ctEntry->destructor; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + ctEntry = &systemClasses[objType]; + destructor = ctEntry->destructor; + } + + if (destructor != NULL){ + /* Call destructor on user data if necessary */ + pkixErrorResult = destructor(object, plContext); + if (pkixErrorResult) { + pkixErrorClass = PKIX_FATAL_ERROR; + PKIX_DoAddError(stdVarsPtr, pkixErrorResult, plContext); + pkixErrorResult = NULL; + } + } + + /* Atomically decrement object counter */ + PR_ATOMIC_DECREMENT((PRInt32*)&ctEntry->objCounter); + + /* pkix_pl_Object_Destroy assumes the lock is held */ + /* It will call unlock and destroy the object */ + pkixErrorResult = pkix_pl_Object_Destroy(object, plContext); + goto cleanup; + } + + if (refCount < 0) { + PKIX_ERROR_ALLOC_ERROR(); + } + +cleanup: + + PKIX_RETURN(OBJECT); +} + + + +/* + * FUNCTION: PKIX_PL_Object_Equals (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_Object *firstObjectHeader = NULL; + PKIX_PL_Object *secondObjectHeader = NULL; + PKIX_PL_EqualsCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (firstObject, &firstObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (secondObject, &secondObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* if hashcodes are cached but not equal, objects can't be equal */ + if (firstObjectHeader->hashcodeCached && + secondObjectHeader->hashcodeCached){ + if (firstObjectHeader->hashcode != + secondObjectHeader->hashcode){ + *pResult = PKIX_FALSE; + goto cleanup; + } + } + + objType = firstObjectHeader->type; + + if (objType >= PKIX_NUMTYPES) { +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&firstObjectHeader->type, + firstObjectHeader->type, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } else { + func = ctEntry->equalsFunction; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.equalsFunction; + if (func == NULL){ + func = pkix_pl_Object_Equals_Default; + } + } + + PKIX_CHECK(func(firstObject, secondObject, pResult, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Duplicate (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Duplicate( + PKIX_PL_Object *firstObject, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_PL_Object *firstObjectHeader = NULL; + PKIX_PL_DuplicateCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Duplicate"); + PKIX_NULLCHECK_TWO(firstObject, pNewObject); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (firstObject, &firstObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + objType = firstObjectHeader->type; + + if (objType >= PKIX_NUMTYPES) { +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->duplicateFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } else { + func = ctEntry->duplicateFunction; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.duplicateFunction; + if (!func){ + PKIX_ERROR_FATAL(PKIX_UNDEFINEDDUPLICATEFUNCTION); + } + } + + PKIX_CHECK(func(firstObject, pNewObject, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Hashcode (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pValue, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_HashcodeCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objectHash; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Hashcode"); + PKIX_NULLCHECK_TWO(object, pValue); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* if we don't have a cached copy from before, we create one */ + if (!objectHeader->hashcodeCached){ + + PKIX_UInt32 objType = objectHeader->type; + + /* first, special handling for system types */ + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL + (PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || + (ctEntry->hashcodeFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } + + func = ctEntry->hashcodeFunction; +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.hashcodeFunction; + if (func == NULL){ + func = pkix_pl_Object_Hashcode_Default; + } + } + + PKIX_CHECK(func(object, &objectHash, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + + if (!objectHeader->hashcodeCached){ + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_ERRORLOCKINGOBJECT); + + if (!objectHeader->hashcodeCached){ + /* save cached copy in case we need it again */ + objectHeader->hashcode = objectHash; + objectHeader->hashcodeCached = PKIX_TRUE; + } + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_ERRORUNLOCKINGOBJECT); + } + } + + *pValue = objectHeader->hashcode; + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_ToString (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_ToStringCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_PL_String *objectString = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* if we don't have a cached copy from before, we create one */ + if (!objectHeader->stringRep){ + + PKIX_UInt32 objType = objectHeader->type; + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL + (PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || + (ctEntry->toStringFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } + + func = ctEntry->toStringFunction; +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.toStringFunction; + if (func == NULL){ + func = pkix_pl_Object_ToString_Default; + } + } + + PKIX_CHECK(func(object, &objectString, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + + if (!objectHeader->stringRep){ + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_ERRORLOCKINGOBJECT); + + if (!objectHeader->stringRep){ + /* save a cached copy */ + objectHeader->stringRep = objectString; + objectString = NULL; + } + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_ERRORUNLOCKINGOBJECT); + } + } + + + *pString = objectHeader->stringRep; + objectHeader->stringRep = NULL; + +cleanup: + if (objectHeader) { + PKIX_DECREF(objectHeader->stringRep); + } + PKIX_DECREF(objectString); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_InvalidateCache (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_InvalidateCache( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_InvalidateCache"); + PKIX_NULLCHECK_ONE(object); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_ERRORLOCKINGOBJECT); + + /* invalidate hashcode */ + objectHeader->hashcode = 0; + objectHeader->hashcodeCached = PKIX_FALSE; + + PKIX_DECREF(objectHeader->stringRep); + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_ERRORUNLOCKINGOBJECT); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Compare (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Compare( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_PL_Object *firstObjectHeader = NULL; + PKIX_PL_Object *secondObjectHeader = NULL; + PKIX_PL_ComparatorCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Compare"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader + (firstObject, &firstObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader + (secondObject, &secondObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + objType = firstObjectHeader->type; + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->comparator == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCOMPARATOR); + } + + func = ctEntry->comparator; +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + /* special handling for system types */ + entry = systemClasses[objType]; + func = entry.comparator; + if (!func){ + PKIX_ERROR(PKIX_UNDEFINEDCOMPARATOR); + } + } + + PKIX_CHECK(func(firstObject, secondObject, pResult, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Lock (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Lock( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Lock"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_LOCKOBJECTFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Unlock (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Unlock( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Unlock"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_UNLOCKOBJECTFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + + +/* + * FUNCTION: PKIX_PL_Object_GetType (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_GetType( + PKIX_PL_Object *object, + PKIX_UInt32 *pType, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_GetType"); + PKIX_NULLCHECK_TWO(object, pType); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + *pType = objectHeader->type; + +cleanup: + + PKIX_RETURN(OBJECT); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h new file mode 100644 index 0000000000..0133c43eeb --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h @@ -0,0 +1,76 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_object.h + * + * Object Construction, Destruction and Callback Definitions + * + */ + +#ifndef _PKIX_PL_OBJECT_H +#define _PKIX_PL_OBJECT_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Object Implementation Notes: + * + * Allocating a new object creates an object header and a block of + * uninitialized user data. A pointer to this uninitialized data is + * returned to the user. The structure looks as follows: + * + * +--------------------+ + * | MAGIC HEADER | + * | (object header) | + * +--------------------+ + * | user data | -- pointer returned from PKIX_PL_Object_Alloc + * +--------------------+ + * + * Object operations receive a pointer to raw user data as an argument. + * The macro HEADER(object) returns a pointer to the object header. + * An assertion then verifies that the first field is the MAGIC_HEADER. + */ + +/* PKIX_PL_Object Structure Definition */ +struct PKIX_PL_ObjectStruct { + PRUint64 magicHeader; + PKIX_UInt32 type; + PKIX_Int32 references; + PRLock *lock; + PKIX_PL_String *stringRep; + PKIX_UInt32 hashcode; + PKIX_Boolean hashcodeCached; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_Object_RetrieveEqualsCallback( + PKIX_PL_Object *object, + PKIX_PL_EqualsCallback *equalsCallback, + void *plContext); + +extern PKIX_Boolean initializing; +extern PKIX_Boolean initialized; + +#ifdef PKIX_USER_OBJECT_TYPE + +extern PRLock *classTableLock; + +#endif + +extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + +PKIX_Error * +pkix_pl_Object_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OBJECT_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c new file mode 100644 index 0000000000..a6e0503850 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c @@ -0,0 +1,316 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_oid.c + * + * OID Object Functions + * + */ + +#include "pkix_pl_oid.h" + +/* --Private-OID-Functions---------------------------------------- */ + + /* + * FUNCTION: pkix_pl_OID_Comparator + * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OID_Comparator( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pRes, + void *plContext) +{ + PKIX_PL_OID *firstOID = NULL; + PKIX_PL_OID *secondOID = NULL; + + PKIX_ENTER(OID, "pkix_pl_OID_Comparator"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pRes); + + PKIX_CHECK(pkix_CheckTypes + (firstObject, secondObject, PKIX_OID_TYPE, plContext), + PKIX_ARGUMENTSNOTOIDS); + + firstOID = (PKIX_PL_OID*)firstObject; + secondOID = (PKIX_PL_OID*)secondObject; + + *pRes = (PKIX_Int32)SECITEM_CompareItem(&firstOID->derOid, + &secondOID->derOid); +cleanup: + PKIX_RETURN(OID); +} + +/* + * FUNCTION: pkix_pl_OID_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OID_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_OID *oid = NULL; + + PKIX_ENTER(OID, "pkix_pl_OID_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OID_TYPE, plContext), + PKIX_OBJECTNOTANOID); + oid = (PKIX_PL_OID*)object; + SECITEM_FreeItem(&oid->derOid, PR_FALSE); + +cleanup: + PKIX_RETURN(OID); +} + +/* + * FUNCTION: pkix_pl_OID_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OID_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_OID *oid = NULL; + + PKIX_ENTER(OID, "pkix_pl_OID_HashCode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OID_TYPE, plContext), + PKIX_OBJECTNOTANOID); + + oid = (PKIX_PL_OID *)object; + + PKIX_CHECK(pkix_hash + ((unsigned char *)oid->derOid.data, + oid->derOid.len * sizeof (char), + pHashcode, + plContext), + PKIX_HASHFAILED); +cleanup: + + PKIX_RETURN(OID); +} + +/* + * FUNCTION: pkix_pl_OID_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OID_Equals( + PKIX_PL_Object *first, + PKIX_PL_Object *second, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_Int32 cmpResult; + + PKIX_ENTER(OID, "pkix_pl_OID_Equals"); + PKIX_NULLCHECK_THREE(first, second, pResult); + + PKIX_CHECK(pkix_pl_OID_Comparator + (first, second, &cmpResult, plContext), + PKIX_OIDCOMPARATORFAILED); + + *pResult = (cmpResult == 0); +cleanup: + + PKIX_RETURN(OID); +} + +/* + * FUNCTION: pkix_pl_OID_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + * Use this function only for printing OIDs and not to make any + * critical security decision. + */ +static PKIX_Error * +pkix_pl_OID_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_OID *oid = NULL; + char *oidString = NULL; + + PKIX_ENTER(OID, "pkix_pl_OID_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OID_TYPE, plContext), + PKIX_OBJECTNOTANOID); + oid = (PKIX_PL_OID*)object; + oidString = CERT_GetOidString(&oid->derOid); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, oidString , 0, pString, plContext), + PKIX_STRINGCREATEFAILED); +cleanup: + PR_smprintf_free(oidString); + + PKIX_RETURN(OID); +} + +/* + * FUNCTION: pkix_pl_OID_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OID_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_OID_RegisterSelf( + void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_OID_TYPE]; + + PKIX_ENTER(OID, "pkix_pl_OID_RegisterSelf"); + + entry->description = "OID"; + entry->typeObjectSize = sizeof(PKIX_PL_OID); + entry->destructor = pkix_pl_OID_Destroy; + entry->equalsFunction = pkix_pl_OID_Equals; + entry->hashcodeFunction = pkix_pl_OID_Hashcode; + entry->toStringFunction = pkix_pl_OID_ToString; + entry->comparator = pkix_pl_OID_Comparator; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(OID); +} + +/* + * FUNCTION: pkix_pl_OID_GetCriticalExtensionOIDs + * DESCRIPTION: + * + * Converts the extensions in "extensions" array that are critical to + * PKIX_PL_OID and returns the result as a PKIX_List in "pPidList". + * If there is no critical extension, an empty list is returned. + * + * PARAMETERS + * "extension" + * an array of extension pointers. May be NULL. + * "pOidsList" + * Address where the list of OIDs is returned. 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 CRL 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_OID_GetCriticalExtensionOIDs( + CERTCertExtension **extensions, + PKIX_List **pOidsList, + void *plContext) +{ + PKIX_List *oidsList = NULL; + PKIX_PL_OID *pkixOID = NULL; + + PKIX_ENTER(OID, "pkix_pl_OID_GetCriticalExtensionOIDs"); + PKIX_NULLCHECK_ONE(pOidsList); + + PKIX_CHECK(PKIX_List_Create(&oidsList, plContext), + PKIX_LISTCREATEFAILED); + + if (extensions) { + while (*extensions) { + CERTCertExtension *extension = NULL; + SECItem *critical = NULL; + SECItem *oid = NULL; + + extension = *extensions++; + /* extension is critical ? */ + critical = &extension->critical; + if (critical->len == 0 || critical->data[0] == 0) { + continue; + } + oid = &extension->id; + PKIX_CHECK( + PKIX_PL_OID_CreateBySECItem(oid, &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + PKIX_CHECK( + PKIX_List_AppendItem(oidsList, (PKIX_PL_Object *)pkixOID, + plContext), + PKIX_LISTAPPENDITEMFAILED); + PKIX_DECREF(pkixOID); + } + } + + *pOidsList = oidsList; + oidsList = NULL; + +cleanup: + PKIX_DECREF(oidsList); + PKIX_DECREF(pkixOID); + PKIX_RETURN(OID); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_OID_CreateBySECItem (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_OID_CreateBySECItem( + SECItem *derOid, + PKIX_PL_OID **pOID, + void *plContext) +{ + PKIX_PL_OID *oid = NULL; + SECStatus rv; + + PKIX_ENTER(OID, "PKIX_PL_OID_CreateBySECItem"); + PKIX_NULLCHECK_TWO(pOID, derOid); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OID_TYPE, + sizeof (PKIX_PL_OID), + (PKIX_PL_Object **)&oid, + plContext), + PKIX_COULDNOTCREATEOBJECT); + rv = SECITEM_CopyItem(NULL, &oid->derOid, derOid); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + *pOID = oid; + oid = NULL; + +cleanup: + PKIX_DECREF(oid); + + PKIX_RETURN(OID); +} + +/* + * FUNCTION: PKIX_PL_OID_Create (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_OID_Create( + SECOidTag idtag, + PKIX_PL_OID **pOID, + void *plContext) +{ + SECOidData *oidData = NULL; + + PKIX_ENTER(OID, "PKIX_PL_OID_Create"); + PKIX_NULLCHECK_ONE(pOID); + + oidData = SECOID_FindOIDByTag((SECOidTag)idtag); + if (!oidData) { + PKIX_ERROR(PKIX_SECOIDFINDOIDTAGDESCRIPTIONFAILED); + } + + pkixErrorResult = + PKIX_PL_OID_CreateBySECItem(&oidData->oid, pOID, plContext); +cleanup: + PKIX_RETURN(OID); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h new file mode 100644 index 0000000000..0229194d84 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_oid.h + * + * OID Object Definitions + * + */ + +#ifndef _PKIX_PL_OID_H +#define _PKIX_PL_OID_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_OIDStruct { + SECItem derOid; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_OID_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_OID_GetCriticalExtensionOIDs( + CERTCertExtension **extensions, + PKIX_List **pOidsList, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OID_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c new file mode 100644 index 0000000000..c920533d37 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c @@ -0,0 +1,584 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_primhash.c + * + * Primitive (non-object) Hashtable Functions + * + */ + +#include "pkix_pl_primhash.h" + +/* --Private-Functions---------------------------------------- */ + +/* + * FUNCTION: pkix_pl_KeyComparator_Default + * DESCRIPTION: + * + * Compares the integer pointed to by "firstKey" with the integer pointed to + * by "secondKey" for equality and stores the Boolean result at "pResult". + * This default key comparator assumes each key is a PKIX_UInt32, and it + * simply tests them for equality. + * + * PARAMETERS: + * "firstKey" + * Address of the first integer key to compare. Must be non-NULL. + * The EqualsCallback for this Object will be called. + * "secondKey" + * Address of the second integer key to compare. Must be non-NULL. + * "pResult" + * Address where Boolean 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. + */ +static PKIX_Error * +pkix_pl_KeyComparator_Default( + PKIX_UInt32 *firstKey, + PKIX_UInt32 *secondKey, + PKIX_Boolean *pResult, + void *plContext) +{ + /* Assume both keys are pointers to PKIX_UInt32 */ + PKIX_UInt32 firstInt, secondInt; + + PKIX_ENTER(HASHTABLE, "pkix_pl_KeyComparator_Default"); + PKIX_NULLCHECK_THREE(firstKey, secondKey, pResult); + + firstInt = *firstKey; + secondInt = *secondKey; + + *pResult = (firstInt == secondInt)?PKIX_TRUE:PKIX_FALSE; + + PKIX_RETURN(HASHTABLE); +} + + +/* + * FUNCTION: pkix_pl_PrimHashTable_Create + * DESCRIPTION: + * + * Creates a new PrimHashtable object with a number of buckets equal to + * "numBuckets" and stores the result at "pResult". + * + * PARAMETERS: + * "numBuckets" + * The number of hash table buckets. Must be non-zero. + * "pResult" + * Address where PrimHashTable 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_PrimHashTable_Create( + PKIX_UInt32 numBuckets, + pkix_pl_PrimHashTable **pResult, + void *plContext) +{ + pkix_pl_PrimHashTable *primHashTable = NULL; + PKIX_UInt32 i; + + PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Create"); + PKIX_NULLCHECK_ONE(pResult); + + if (numBuckets == 0) { + PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO); + } + + /* Allocate a new hashtable */ + PKIX_CHECK(PKIX_PL_Malloc + (sizeof (pkix_pl_PrimHashTable), + (void **)&primHashTable, + plContext), + PKIX_MALLOCFAILED); + + primHashTable->size = numBuckets; + + /* Allocate space for the buckets */ + PKIX_CHECK(PKIX_PL_Malloc + (numBuckets * sizeof (pkix_pl_HT_Elem*), + (void **)&primHashTable->buckets, + plContext), + PKIX_MALLOCFAILED); + + for (i = 0; i < numBuckets; i++) { + primHashTable->buckets[i] = NULL; + } + + *pResult = primHashTable; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_FREE(primHashTable); + } + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: pkix_pl_PrimHashTable_Add + * DESCRIPTION: + * + * Adds the value pointed to by "value" to the PrimHashTable pointed to by + * "ht" using the key pointed to by "key" and the hashCode value equal to + * "hashCode", using the function pointed to by "keyComp" to compare keys. + * Assumes the key is either a PKIX_UInt32 or a PKIX_PL_Object. If the value + * already exists in the hashtable, this function returns a non-fatal error. + * + * PARAMETERS: + * "ht" + * Address of PrimHashtable to insert into. Must be non-NULL. + * "key" + * Address of key. Typically a PKIX_UInt32 or PKIX_PL_Object. + * Must be non-NULL. + * "value" + * Address of Object to be added to PrimHashtable. Must be non-NULL. + * "hashCode" + * Hashcode value of the key. + * "keyComp" + * Address of function used to determine if two keys are equal. + * If NULL, pkix_pl_KeyComparator_Default is used. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "ht" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HashTable 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_PrimHashTable_Add( + pkix_pl_PrimHashTable *ht, + void *key, + void *value, + PKIX_UInt32 hashCode, + PKIX_PL_EqualsCallback keyComp, + void *plContext) +{ + pkix_pl_HT_Elem **elemPtr = NULL; + pkix_pl_HT_Elem *element = NULL; + PKIX_Boolean compResult = PKIX_FALSE; + + PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Add"); + PKIX_NULLCHECK_THREE(ht, key, value); + + for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr; + element != NULL; elemPtr = &(element->next), element = *elemPtr) { + + if (element->hashCode != hashCode){ + /* no possibility of a match */ + continue; + } + + if (keyComp == NULL){ + PKIX_CHECK(pkix_pl_KeyComparator_Default + ((PKIX_UInt32 *)key, + (PKIX_UInt32 *)(element->key), + &compResult, + plContext), + PKIX_COULDNOTTESTWHETHERKEYSEQUAL); + } else { + PKIX_CHECK(keyComp + ((PKIX_PL_Object *)key, + (PKIX_PL_Object *)(element->key), + &compResult, + plContext), + PKIX_COULDNOTTESTWHETHERKEYSEQUAL); + } + + if ((element->hashCode == hashCode) && + (compResult == PKIX_TRUE)){ + /* Same key already exists in the table */ + PKIX_ERROR(PKIX_ATTEMPTTOADDDUPLICATEKEY); + } + } + + /* Next Element should be NULL at this point */ + if (element != NULL) { + PKIX_ERROR(PKIX_ERRORTRAVERSINGBUCKET); + } + + /* Create a new HT_Elem */ + PKIX_CHECK(PKIX_PL_Malloc + (sizeof (pkix_pl_HT_Elem), (void **)elemPtr, plContext), + PKIX_MALLOCFAILED); + + element = *elemPtr; + + element->key = key; + element->value = value; + element->hashCode = hashCode; + element->next = NULL; + +cleanup: + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: pkix_pl_PrimHashTable_Remove + * DESCRIPTION: + * + * Removes any objects with the key pointed to by "key" and hashCode value + * equal to "hashCode" from the PrimHashtable pointed to by "ht", using the + * function pointed to by "keyComp" to compare keys, and stores the object's + * value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object. + * This function sets "pResult" to NULL if the key is not in the hashtable. + * + * PARAMETERS: + * "ht" + * Address of PrimHashtable to remove object. Must be non-NULL. + * "key" + * Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object. + * Must be non-NULL. + * "value" + * Address of Object to be added to PrimHashtable. Must be non-NULL. + * "hashCode" + * Hashcode value of the key. + * "keyComp" + * Address of function used to determine if two keys are equal. + * If NULL, pkix_pl_KeyComparator_Default is used. + * "pResult" + * Address where value will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "ht" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HashTable 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_PrimHashTable_Remove( + pkix_pl_PrimHashTable *ht, + void *key, + PKIX_UInt32 hashCode, + PKIX_PL_EqualsCallback keyComp, + void **pKey, + void **pValue, + void *plContext) +{ + pkix_pl_HT_Elem *element = NULL; + pkix_pl_HT_Elem *prior = NULL; + PKIX_Boolean compResult; + + PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove"); + PKIX_NULLCHECK_FOUR(ht, key, pKey, pValue); + + *pKey = NULL; + *pValue = NULL; + + for (element = ht->buckets[hashCode%ht->size], prior = element; + (element != NULL); + prior = element, element = element->next) { + + if (element->hashCode != hashCode){ + /* no possibility of a match */ + continue; + } + + if (keyComp == NULL){ + PKIX_CHECK(pkix_pl_KeyComparator_Default + ((PKIX_UInt32 *)key, + (PKIX_UInt32 *)(element->key), + &compResult, + plContext), + PKIX_COULDNOTTESTWHETHERKEYSEQUAL); + } else { + PKIX_CHECK(keyComp + ((PKIX_PL_Object *)key, + (PKIX_PL_Object *)(element->key), + &compResult, + plContext), + PKIX_COULDNOTTESTWHETHERKEYSEQUAL); + } + + if ((element->hashCode == hashCode) && + (compResult == PKIX_TRUE)){ + if (element != prior) { + prior->next = element->next; + } else { + ht->buckets[hashCode%ht->size] = element->next; + } + *pKey = element->key; + *pValue = element->value; + element->key = NULL; + element->value = NULL; + element->next = NULL; + PKIX_FREE(element); + goto cleanup; + } + } + +cleanup: + + PKIX_RETURN(HASHTABLE); +} + + +/* + * FUNCTION: pkix_pl_HashTableLookup + * DESCRIPTION: + * + * Looks up object using the key pointed to by "key" and hashCode value + * equal to "hashCode" from the PrimHashtable pointed to by "ht", using the + * function pointed to by "keyComp" to compare keys, and stores the object's + * value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object. + * This function sets "pResult" to NULL if the key is not in the hashtable. + * + * PARAMETERS: + * "ht" + * Address of PrimHashtable to lookup object from. Must be non-NULL. + * "key" + * Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object. + * Must be non-NULL. + * "keyComp" + * Address of function used to determine if two keys are equal. + * If NULL, pkix_pl_KeyComparator_Default is used. + * "hashCode" + * Hashcode value of the key. + * "pResult" + * Address where value will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally 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_PrimHashTable_Lookup( + pkix_pl_PrimHashTable *ht, + void *key, + PKIX_UInt32 hashCode, + PKIX_PL_EqualsCallback keyComp, + void **pResult, + void *plContext) +{ + pkix_pl_HT_Elem *element = NULL; + PKIX_Boolean compResult = PKIX_FALSE; + + PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Lookup"); + PKIX_NULLCHECK_THREE(ht, key, pResult); + + *pResult = NULL; + + for (element = (ht->buckets)[hashCode%ht->size]; + (element != NULL) && (*pResult == NULL); + element = element->next) { + + if (element->hashCode != hashCode){ + /* no possibility of a match */ + continue; + } + + if (keyComp == NULL){ + PKIX_CHECK(pkix_pl_KeyComparator_Default + ((PKIX_UInt32 *)key, + (PKIX_UInt32 *)(element->key), + &compResult, + plContext), + PKIX_COULDNOTTESTWHETHERKEYSEQUAL); + } else { + pkixErrorResult = + keyComp((PKIX_PL_Object *)key, + (PKIX_PL_Object *)(element->key), + &compResult, + plContext); + if (pkixErrorResult) { + pkixErrorClass = PKIX_FATAL_ERROR; + pkixErrorCode = PKIX_COULDNOTTESTWHETHERKEYSEQUAL; + goto cleanup; + } + } + + if ((element->hashCode == hashCode) && + (compResult == PKIX_TRUE)){ + *pResult = element->value; + goto cleanup; + } + } + + /* if we've reached here, specified key doesn't exist in hashtable */ + *pResult = NULL; + +cleanup: + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: pkix_pl_PrimHashTable_Destroy + * + * Destroys PrimHashTable pointed to by "ht". + * + * PARAMETERS: + * "ht" + * Address of PrimHashtable to free. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "ht" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS + * Returns NULL if the function succeeds. + * Returns a HashTable 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_PrimHashTable_Destroy( + pkix_pl_PrimHashTable *ht, + void *plContext) +{ + pkix_pl_HT_Elem *element = NULL; + pkix_pl_HT_Elem *temp = NULL; + PKIX_UInt32 i; + + PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Destroy"); + PKIX_NULLCHECK_ONE(ht); + + /* Free each element (list) */ + for (i = 0; i < ht->size; i++) { + for (element = ht->buckets[i]; + element != NULL; + element = temp) { + temp = element->next; + element->value = NULL; + element->key = NULL; + element->hashCode = 0; + element->next = NULL; + PKIX_FREE(element); + } + } + + /* Free the pointer to the list array */ + PKIX_FREE(ht->buckets); + ht->size = 0; + + /* Free the table itself */ + PKIX_FREE(ht); + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: pkix_pl_PrimHashTable_GetBucketSize + * DESCRIPTION: + * + * Retruns number of entries in the bucket the "hashCode" is designated in + * the hashtable "ht" in the address "pBucketSize". + * + * PARAMETERS: + * "ht" + * Address of PrimHashtable to get entries count. Must be non-NULL. + * "hashCode" + * Hashcode value of the key. + * "pBucketSize" + * Address that an PKIX_UInt32 is returned for number of entries in the + * bucket associated with the hashCode. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "ht" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HashTable 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_PrimHashTable_GetBucketSize( + pkix_pl_PrimHashTable *ht, + PKIX_UInt32 hashCode, + PKIX_UInt32 *pBucketSize, + void *plContext) +{ + pkix_pl_HT_Elem **elemPtr = NULL; + pkix_pl_HT_Elem *element = NULL; + PKIX_UInt32 bucketSize = 0; + + PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_GetBucketSize"); + PKIX_NULLCHECK_TWO(ht, pBucketSize); + + for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr; + element != NULL; elemPtr = &(element->next), element = *elemPtr) { + bucketSize++; + } + + *pBucketSize = bucketSize; + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: pkix_pl_PrimHashTable_RemoveFIFO + * DESCRIPTION: + * + * Remove the first entry in the bucket the "hashCode" is designated in + * the hashtable "ht". Since new entry is added at end of the link list + * the first one is the oldest (FI) therefore removed first (FO). + * + * PARAMETERS: + * "ht" + * Address of PrimHashtable to get entries count. Must be non-NULL. + * "hashCode" + * Hashcode value of the key. + * "pKey" + * Address of key of the entry deleted. Must be non-NULL. + * "pValue" + * Address of Value of the entry deleted. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "ht" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a HashTable 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_PrimHashTable_RemoveFIFO( + pkix_pl_PrimHashTable *ht, + PKIX_UInt32 hashCode, + void **pKey, + void **pValue, + void *plContext) +{ + pkix_pl_HT_Elem *element = NULL; + + PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove"); + PKIX_NULLCHECK_THREE(ht, pKey, pValue); + + element = (ht->buckets)[hashCode%ht->size]; + + if (element != NULL) { + + *pKey = element->key; + *pValue = element->value; + ht->buckets[hashCode%ht->size] = element->next; + element->key = NULL; + element->value = NULL; + element->next = NULL; + PKIX_FREE(element); + } + + PKIX_RETURN(HASHTABLE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h new file mode 100644 index 0000000000..b889e2e91e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h @@ -0,0 +1,102 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_primhash.h + * + * Primitive Hashtable Definition + * + */ + +#ifndef _PKIX_PL_PRIMHASH_H +#define _PKIX_PL_PRIMHASH_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkix_pl_HT_Elem pkix_pl_HT_Elem; + +typedef struct pkix_pl_PrimHashTable pkix_pl_PrimHashTable; + +typedef struct pkix_pl_Integer pkix_pl_Integer; + +struct pkix_pl_Integer{ + PKIX_UInt32 ht_int; +}; + +struct pkix_pl_HT_Elem { + void *key; + void *value; + PKIX_UInt32 hashCode; + pkix_pl_HT_Elem *next; +}; + +struct pkix_pl_PrimHashTable { + pkix_pl_HT_Elem **buckets; + PKIX_UInt32 size; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_PrimHashTable_Create( + PKIX_UInt32 numBuckets, + pkix_pl_PrimHashTable **pResult, + void *plContext); + +PKIX_Error * +pkix_pl_PrimHashTable_Add( + pkix_pl_PrimHashTable *ht, + void *key, + void *value, + PKIX_UInt32 hashCode, + PKIX_PL_EqualsCallback keyComp, + void *plContext); + +PKIX_Error * +pkix_pl_PrimHashTable_Remove( + pkix_pl_PrimHashTable *ht, + void *key, + PKIX_UInt32 hashCode, + PKIX_PL_EqualsCallback keyComp, + void **pKey, + void **pValue, + void *plContext); + +PKIX_Error * +pkix_pl_PrimHashTable_Lookup( + pkix_pl_PrimHashTable *ht, + void *key, + PKIX_UInt32 hashCode, + PKIX_PL_EqualsCallback keyComp, + void **pResult, + void *plContext); + +PKIX_Error* +pkix_pl_PrimHashTable_Destroy( + pkix_pl_PrimHashTable *ht, + void *plContext); + +PKIX_Error * +pkix_pl_PrimHashTable_GetBucketSize( + pkix_pl_PrimHashTable *ht, + PKIX_UInt32 hashCode, + PKIX_UInt32 *pBucketSize, + void *plContext); + +PKIX_Error * +pkix_pl_PrimHashTable_RemoveFIFO( + pkix_pl_PrimHashTable *ht, + PKIX_UInt32 hashCode, + void **pKey, + void **pValue, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_PRIMHASH_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c new file mode 100644 index 0000000000..662931e981 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c @@ -0,0 +1,217 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_rwlock.c + * + * Read/Write Lock Functions + * + */ + +#include "pkix_pl_rwlock.h" + +/* --Private-Functions-------------------------------------------- */ + +static PKIX_Error * +pkix_pl_RWLock_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_RWLock* rwlock = NULL; + + PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_RWLOCK_TYPE, plContext), + PKIX_OBJECTNOTRWLOCK); + + rwlock = (PKIX_PL_RWLock*) object; + + PKIX_RWLOCK_DEBUG("Calling PR_DestroyRWLock)\n"); + PR_DestroyRWLock(rwlock->lock); + rwlock->lock = NULL; + +cleanup: + + PKIX_RETURN(RWLOCK); +} + +/* + * FUNCTION: pkix_pl_RWLock_RegisterSelf + * DESCRIPTION: + * Registers PKIX_RWLOCK_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_RWLock_RegisterSelf( + void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_RegisterSelf"); + + entry.description = "RWLock"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_RWLock); + entry.destructor = pkix_pl_RWLock_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_RWLOCK_TYPE] = entry; + + PKIX_RETURN(RWLOCK); +} + +/* --Public-Functions--------------------------------------------- */ + +PKIX_Error * +PKIX_PL_RWLock_Create( + PKIX_PL_RWLock **pNewLock, + void *plContext) +{ + PKIX_PL_RWLock *rwLock = NULL; + + PKIX_ENTER(RWLOCK, "PKIX_PL_RWLock_Create"); + PKIX_NULLCHECK_ONE(pNewLock); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_RWLOCK_TYPE, + sizeof (PKIX_PL_RWLock), + (PKIX_PL_Object **)&rwLock, + plContext), + PKIX_ERRORALLOCATINGRWLOCK); + + PKIX_RWLOCK_DEBUG("\tCalling PR_NewRWLock)\n"); + rwLock->lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "PKIX RWLock"); + + if (rwLock->lock == NULL) { + PKIX_DECREF(rwLock); + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + rwLock->readCount = 0; + rwLock->writeLocked = PKIX_FALSE; + + *pNewLock = rwLock; + +cleanup: + + PKIX_RETURN(RWLOCK); +} + +PKIX_Error * +PKIX_PL_AcquireReaderLock( + PKIX_PL_RWLock *lock, + void *plContext) +{ + PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireReaderLock"); + PKIX_NULLCHECK_ONE(lock); + + PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Rlock)\n"); + (void) PR_RWLock_Rlock(lock->lock); + + lock->readCount++; + + PKIX_RETURN(RWLOCK); +} + +PKIX_Error * +PKIX_PL_ReleaseReaderLock( + PKIX_PL_RWLock *lock, + void *plContext) +{ + PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseReaderLock"); + PKIX_NULLCHECK_ONE(lock); + + PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n"); + (void) PR_RWLock_Unlock(lock->lock); + + lock->readCount--; + + PKIX_RETURN(RWLOCK); +} + +PKIX_Error * +PKIX_PL_IsReaderLockHeld( + PKIX_PL_RWLock *lock, + PKIX_Boolean *pIsHeld, + void *plContext) +{ + PKIX_ENTER(RWLOCK, "PKIX_PL_IsReaderLockHeld"); + PKIX_NULLCHECK_TWO(lock, pIsHeld); + + *pIsHeld = (lock->readCount > 0)?PKIX_TRUE:PKIX_FALSE; + + PKIX_RETURN(RWLOCK); +} + +PKIX_Error * +PKIX_PL_AcquireWriterLock( + PKIX_PL_RWLock *lock, + void *plContext) +{ + PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireWriterLock"); + PKIX_NULLCHECK_ONE(lock); + + PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Wlock\n"); + (void) PR_RWLock_Wlock(lock->lock); + + if (lock->readCount > 0) { + PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT); + } + + /* We should never acquire a write lock if the lock is held */ + lock->writeLocked = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(RWLOCK); +} + +PKIX_Error * +PKIX_PL_ReleaseWriterLock( + PKIX_PL_RWLock *lock, + void *plContext) +{ + PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseWriterLock"); + PKIX_NULLCHECK_ONE(lock); + + if (lock->readCount > 0) { + PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT); + } + + PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n"); + (void) PR_RWLock_Unlock(lock->lock); + + /* XXX Need to think about thread safety here */ + /* There should be a single lock holder */ + lock->writeLocked = PKIX_FALSE; + +cleanup: + + PKIX_RETURN(RWLOCK); +} + +PKIX_Error * +PKIX_PL_IsWriterLockHeld( + PKIX_PL_RWLock *lock, + PKIX_Boolean *pIsHeld, + void *plContext) +{ + PKIX_ENTER(RWLOCK, "PKIX_PL_IsWriterLockHeld"); + PKIX_NULLCHECK_TWO(lock, pIsHeld); + + *pIsHeld = lock->writeLocked; + + PKIX_RETURN(RWLOCK); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h new file mode 100644 index 0000000000..fd64659506 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_rwlock.h + * + * Read/Write Lock Definition + * + */ + +#ifndef _PKIX_PL_RWLOCK_H +#define _PKIX_PL_RWLOCK_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_RWLockStruct { + PRRWLock* lock; + PKIX_UInt32 readCount; + PKIX_Boolean writeLocked; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_RWLock_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_RWLOCK_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c new file mode 100644 index 0000000000..167382466e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c @@ -0,0 +1,628 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_string.c + * + * String Object Functions + * + */ + +#include "pkix_pl_string.h" + +/* --Private-String-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_String_Comparator + * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) + * + * NOTE: + * This function is a utility function called by pkix_pl_String_Equals(). + * It is not officially registered as a comparator. + */ +static PKIX_Error * +pkix_pl_String_Comparator( + PKIX_PL_String *firstString, + PKIX_PL_String *secondString, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_UInt32 i; + PKIX_Int32 result; + unsigned char *p1 = NULL; + unsigned char *p2 = NULL; + + PKIX_ENTER(STRING, "pkix_pl_String_Comparator"); + PKIX_NULLCHECK_THREE(firstString, secondString, pResult); + + result = 0; + + p1 = (unsigned char*) firstString->utf16String; + p2 = (unsigned char*) secondString->utf16String; + + /* Compare characters until you find a difference */ + for (i = 0; ((i < firstString->utf16Length) && + (i < secondString->utf16Length) && + result == 0); i++, p1++, p2++) { + if (*p1 < *p2){ + result = -1; + } else if (*p1 > *p2){ + result = 1; + } + } + + /* If two arrays are identical so far, the longer one is greater */ + if (result == 0) { + if (firstString->utf16Length < secondString->utf16Length) { + result = -1; + } else if (firstString->utf16Length > + secondString->utf16Length) { + result = 1; + } + } + + *pResult = result; + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_pl_String_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_String_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_String *string = NULL; + + PKIX_ENTER(STRING, "pkix_pl_String_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), + PKIX_ARGUMENTNOTSTRING); + + string = (PKIX_PL_String*)object; + + /* XXX For debugging Destroy EscASCII String */ + if (string->escAsciiString != NULL) { + PKIX_FREE(string->escAsciiString); + string->escAsciiString = NULL; + string->escAsciiLength = 0; + } + + /* Destroy UTF16 String */ + if (string->utf16String != NULL) { + PKIX_FREE(string->utf16String); + string->utf16String = NULL; + string->utf16Length = 0; + } + +cleanup: + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_pl_String_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_String_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *string = NULL; + char *ascii = NULL; + PKIX_UInt32 length; + + PKIX_ENTER(STRING, "pkix_pl_String_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), + PKIX_ARGUMENTNOTSTRING); + + string = (PKIX_PL_String*)object; + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, ascii, 0, pString, plContext), + PKIX_STRINGCREATEFAILED); + + goto cleanup; + +cleanup: + + PKIX_FREE(ascii); + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_pl_String_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_String_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType; + PKIX_Int32 cmpResult = 0; + + PKIX_ENTER(STRING, "pkix_pl_String_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* Sanity check: Test that "firstObject" is a Strings */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_STRING_TYPE, plContext), + PKIX_FIRSTOBJECTNOTSTRING); + + /* "SecondObject" doesn't have to be a string */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + + /* If types differ, then we will return false */ + *pResult = PKIX_FALSE; + + if (secondType != PKIX_STRING_TYPE) goto cleanup; + + /* It's safe to cast here */ + PKIX_CHECK(pkix_pl_String_Comparator + ((PKIX_PL_String*)firstObject, + (PKIX_PL_String*)secondObject, + &cmpResult, + plContext), + PKIX_STRINGCOMPARATORFAILED); + + /* Strings are equal iff Comparator Result is 0 */ + *pResult = (cmpResult == 0); + +cleanup: + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_pl_String_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_String_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_String *string = NULL; + + PKIX_ENTER(STRING, "pkix_pl_String_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), + PKIX_OBJECTNOTSTRING); + + string = (PKIX_PL_String*)object; + + PKIX_CHECK(pkix_hash + ((const unsigned char *)string->utf16String, + string->utf16Length, + pHashcode, + plContext), + PKIX_HASHFAILED); + +cleanup: + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: pkix_pl_String_RegisterSelf + * DESCRIPTION: + * Registers PKIX_STRING_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_String_RegisterSelf( + void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(STRING, "pkix_pl_String_RegisterSelf"); + + entry.description = "String"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_String); + entry.destructor = pkix_pl_String_Destroy; + entry.equalsFunction = pkix_pl_String_Equals; + entry.hashcodeFunction = pkix_pl_String_Hashcode; + entry.toStringFunction = pkix_pl_String_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_STRING_TYPE] = entry; + + PKIX_RETURN(STRING); +} + + +/* --Public-String-Functions----------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_String_Create( + PKIX_UInt32 fmtIndicator, + const void *stringRep, + PKIX_UInt32 stringLen, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *string = NULL; + unsigned char *utf16Char = NULL; + PKIX_UInt32 i; + + PKIX_ENTER(STRING, "PKIX_PL_String_Create"); + PKIX_NULLCHECK_TWO(pString, stringRep); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_STRING_TYPE, + sizeof (PKIX_PL_String), + (PKIX_PL_Object **)&string, + plContext), + PKIX_COULDNOTALLOCATENEWSTRINGOBJECT); + + string->utf16String = NULL; + string->utf16Length = 0; + + /* XXX For Debugging */ + string->escAsciiString = NULL; + string->escAsciiLength = 0; + + switch (fmtIndicator) { + case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG: + PKIX_STRING_DEBUG("\tCalling PL_strlen).\n"); + string->escAsciiLength = PL_strlen(stringRep); + + /* XXX Cache for Debugging */ + PKIX_CHECK(PKIX_PL_Malloc + ((string->escAsciiLength)+1, + (void **)&string->escAsciiString, + plContext), + PKIX_MALLOCFAILED); + + (void) PORT_Memcpy + (string->escAsciiString, + (void *)((char *)stringRep), + (string->escAsciiLength)+1); + + /* Convert the EscASCII string to UTF16 */ + PKIX_CHECK(pkix_EscASCII_to_UTF16 + (string->escAsciiString, + string->escAsciiLength, + (fmtIndicator == PKIX_ESCASCII_DEBUG), + &string->utf16String, + &string->utf16Length, + plContext), + PKIX_ESCASCIITOUTF16FAILED); + break; + case PKIX_UTF8: + /* Convert the UTF8 string to UTF16 */ + PKIX_CHECK(pkix_UTF8_to_UTF16 + (stringRep, + stringLen, + &string->utf16String, + &string->utf16Length, + plContext), + PKIX_UTF8TOUTF16FAILED); + break; + case PKIX_UTF16: + /* UTF16 Strings must be even in length */ + if (stringLen%2 == 1) { + PKIX_DECREF(string); + PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR); + } + + utf16Char = (unsigned char *)stringRep; + + /* Make sure this is a valid UTF-16 String */ + for (i = 0; \ + (i < stringLen) && (pkixErrorResult == NULL); \ + i += 2) { + /* Check that surrogate pairs are valid */ + if ((utf16Char[i] >= 0xD8)&& + (utf16Char[i] <= 0xDB)) { + if ((i+2) >= stringLen) { + PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR); + /* Second pair should be DC00-DFFF */ + } else if (!((utf16Char[i+2] >= 0xDC)&& + (utf16Char[i+2] <= 0xDF))) { + PKIX_ERROR(PKIX_UTF16LOWZONEERROR); + } else { + /* Surrogate quartet is valid. */ + i += 2; + } + } + } + + /* Create UTF16 String */ + string->utf16Length = stringLen; + + /* Alloc space for string */ + PKIX_CHECK(PKIX_PL_Malloc + (stringLen, &string->utf16String, plContext), + PKIX_MALLOCFAILED); + + PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n"); + (void) PORT_Memcpy + (string->utf16String, stringRep, stringLen); + break; + + default: + PKIX_ERROR(PKIX_UNKNOWNFORMAT); + } + + *pString = string; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(string); + } + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Sprintf( + PKIX_PL_String **pOut, + void *plContext, + const PKIX_PL_String *fmt, + ...) +{ + PKIX_PL_String *tempString = NULL; + PKIX_UInt32 tempUInt = 0; + void *pArg = NULL; + char *asciiText = NULL; + char *asciiFormat = NULL; + char *convertedAsciiFormat = NULL; + char *convertedAsciiFormatBase = NULL; + va_list args; + PKIX_UInt32 length, i, j, dummyLen; + + PKIX_ENTER(STRING, "PKIX_PL_Sprintf"); + PKIX_NULLCHECK_TWO(pOut, fmt); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + ((PKIX_PL_String *)fmt, + PKIX_ESCASCII, + (void **)&asciiFormat, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_STRING_DEBUG("\tCalling PR_Malloc).\n"); + convertedAsciiFormat = PR_Malloc(length + 1); + if (convertedAsciiFormat == NULL) + PKIX_ERROR_ALLOC_ERROR(); + + convertedAsciiFormatBase = convertedAsciiFormat; + + PKIX_STRING_DEBUG("\tCalling va_start).\n"); + va_start(args, fmt); + + i = 0; + j = 0; + while (i < length) { + if ((asciiFormat[i] == '%')&&((i+1) < length)) { + switch (asciiFormat[i+1]) { + case 's': + convertedAsciiFormat[j++] = asciiFormat[i++]; + convertedAsciiFormat[j++] = asciiFormat[i++]; + convertedAsciiFormat[j] = '\0'; + + tempString = va_arg(args, PKIX_PL_String *); + if (tempString != NULL) { + PKIX_CHECK_NO_GOTO( + PKIX_PL_String_GetEncoded + ((PKIX_PL_String*) + tempString, + PKIX_ESCASCII, + &pArg, + &dummyLen, + plContext), + PKIX_STRINGGETENCODEDFAILED); + /* need to cleanup var args before + * we ditch out to cleanup. */ + if (pkixErrorResult) { + va_end(args); + goto cleanup; + } + } else { + /* there may be a NULL in var_args */ + pArg = NULL; + } + if (asciiText != NULL) { + asciiText = PR_sprintf_append(asciiText, + (const char *)convertedAsciiFormat, + pArg); + } else { + asciiText = PR_smprintf + ((const char *)convertedAsciiFormat, + pArg); + } + if (pArg != NULL) { + PKIX_PL_Free(pArg, plContext); + pArg = NULL; + } + convertedAsciiFormat += j; + j = 0; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + convertedAsciiFormat[j++] = asciiFormat[i++]; + convertedAsciiFormat[j++] = asciiFormat[i++]; + convertedAsciiFormat[j] = '\0'; + + tempUInt = va_arg(args, PKIX_UInt32); + if (asciiText != NULL) { + asciiText = PR_sprintf_append(asciiText, + (const char *)convertedAsciiFormat, + tempUInt); + } else { + asciiText = PR_smprintf + ((const char *)convertedAsciiFormat, + tempUInt); + } + convertedAsciiFormat += j; + j = 0; + break; + default: + convertedAsciiFormat[j++] = asciiFormat[i++]; + convertedAsciiFormat[j++] = asciiFormat[i++]; + break; + } + } else { + convertedAsciiFormat[j++] = asciiFormat[i++]; + } + } + + /* for constant string value at end of fmt */ + if (j > 0) { + convertedAsciiFormat[j] = '\0'; + if (asciiText != NULL) { + asciiText = PR_sprintf_append(asciiText, + (const char *)convertedAsciiFormat); + } else { + asciiText = PR_smprintf((const char *)convertedAsciiFormat); + } + } + + va_end(args); + + /* Copy temporary char * into a string object */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, (void *)asciiText, 0, pOut, plContext), + PKIX_STRINGCREATEFAILED); + +cleanup: + + PKIX_FREE(asciiFormat); + + if (convertedAsciiFormatBase){ + PR_Free(convertedAsciiFormatBase); + } + + if (asciiText){ + PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n"); + PR_smprintf_free(asciiText); + } + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_GetString( + /* ARGSUSED */ PKIX_UInt32 stringID, + char *defaultString, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_ENTER(STRING, "PKIX_PL_GetString"); + PKIX_NULLCHECK_TWO(pString, defaultString); + + /* XXX Optimization - use stringID for caching */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, defaultString, 0, pString, plContext), + PKIX_STRINGCREATEFAILED); + +cleanup: + + PKIX_RETURN(STRING); +} + +/* + * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_String_GetEncoded( + PKIX_PL_String *string, + PKIX_UInt32 fmtIndicator, + void **pStringRep, + PKIX_UInt32 *pLength, + void *plContext) +{ + PKIX_ENTER(STRING, "PKIX_PL_String_GetEncoded"); + PKIX_NULLCHECK_THREE(string, pStringRep, pLength); + + switch (fmtIndicator) { + case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG: + PKIX_CHECK(pkix_UTF16_to_EscASCII + (string->utf16String, + string->utf16Length, + (fmtIndicator == PKIX_ESCASCII_DEBUG), + (char **)pStringRep, + pLength, + plContext), + PKIX_UTF16TOESCASCIIFAILED); + break; + case PKIX_UTF8: + PKIX_CHECK(pkix_UTF16_to_UTF8 + (string->utf16String, + string->utf16Length, + PKIX_FALSE, + pStringRep, + pLength, + plContext), + PKIX_UTF16TOUTF8FAILED); + break; + case PKIX_UTF8_NULL_TERM: + PKIX_CHECK(pkix_UTF16_to_UTF8 + (string->utf16String, + string->utf16Length, + PKIX_TRUE, + pStringRep, + pLength, + plContext), + PKIX_UTF16TOUTF8FAILED); + break; + case PKIX_UTF16: + *pLength = string->utf16Length; + + PKIX_CHECK(PKIX_PL_Malloc(*pLength, pStringRep, plContext), + PKIX_MALLOCFAILED); + + PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n"); + (void) PORT_Memcpy(*pStringRep, string->utf16String, *pLength); + break; + default: + PKIX_ERROR(PKIX_UNKNOWNFORMAT); + } + +cleanup: + + PKIX_RETURN(STRING); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h new file mode 100644 index 0000000000..9270e4c567 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_string.h + * + * String Object Definitions + * + */ + +#ifndef _PKIX_PL_STRING_H +#define _PKIX_PL_STRING_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_StringStruct { + void* utf16String; + PKIX_UInt32 utf16Length; + /* XXX For Debugging */ + char* escAsciiString; + PKIX_UInt32 escAsciiLength; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_String_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_STRING_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/system.gyp b/security/nss/lib/libpkix/pkix_pl_nss/system/system.gyp new file mode 100644 index 0000000000..32daec93d6 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/system.gyp @@ -0,0 +1,36 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'pkixsystem', + 'type': 'static_library', + 'sources': [ + 'pkix_pl_bigint.c', + 'pkix_pl_bytearray.c', + 'pkix_pl_common.c', + 'pkix_pl_error.c', + 'pkix_pl_hashtable.c', + 'pkix_pl_lifecycle.c', + 'pkix_pl_mem.c', + 'pkix_pl_monitorlock.c', + 'pkix_pl_mutex.c', + 'pkix_pl_object.c', + 'pkix_pl_oid.c', + 'pkix_pl_primhash.c', + 'pkix_pl_rwlock.c', + 'pkix_pl_string.c' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports' + ] + } + ], + 'variables': { + 'module': 'nss' + } +}
\ No newline at end of file |