diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c | 1113 |
1 files changed, 1113 insertions, 0 deletions
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); +} |