| /* 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) { |
| for (thisName = 0; thisName < numNames; thisName++) { |
| PKIX_CHECK(PKIX_List_GetItem |
| (issuerNames, |
| thisName, |
| (PKIX_PL_Object **)&issuer, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK |
| (pkix_pl_LdapCertStore_MakeNameAVAList |
| (requestArena, |
| issuer, |
| &(requestParams.nc), |
| plContext), |
| PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED); |
| |
| PKIX_DECREF(issuer); |
| |
| if (*requestParams.nc == NULL) { |
| /* |
| * The issuer may not include any |
| * components that we know how to |
| * encode. We do not return an error, |
| * because the caller did not |
| * necessarily do anything wrong, but |
| * we return an empty List. |
| */ |
| PKIX_PL_NSSCALL |
| (CERTSTORE, PORT_FreeArena, |
| (requestArena, PR_FALSE)); |
| |
| PKIX_CHECK(PKIX_List_Create |
| (&filteredCRLs, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_SetImmutable |
| (filteredCRLs, plContext), |
| PKIX_LISTSETIMMUTABLEFAILED); |
| |
| *pNBIOContext = NULL; |
| *pCrlList = filteredCRLs; |
| goto cleanup; |
| } |
| |
| /* |
| * LDAP Servers don't seem to be able to handle |
| * requests with more than more than one name. |
| */ |
| break; |
| } |
| } else { |
| PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY); |
| } |
| } else { |
| PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY); |
| } |
| |
| /* All request fields are done */ |
| |
| PKIX_CHECK(PKIX_CertStore_GetCertStoreContext |
| (store, (PKIX_PL_Object **)&lcs, plContext), |
| PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); |
| |
| PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest |
| ((PKIX_PL_LdapClient *)lcs, |
| &requestParams, |
| &pollDesc, |
| &responses, |
| plContext), |
| PKIX_LDAPCLIENTINITIATEREQUESTFAILED); |
| |
| PKIX_CHECK(pkix_pl_LdapCertStore_DestroyAVAList |
| (requestParams.nc, plContext), |
| PKIX_LDAPCERTSTOREDESTROYAVALISTFAILED); |
| |
| if (requestArena) { |
| PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena, |
| (requestArena, PR_FALSE)); |
| } |
| |
| if (pollDesc != NULL) { |
| /* client is waiting for non-blocking I/O to complete */ |
| *pNBIOContext = (void *)pollDesc; |
| *pCrlList = NULL; |
| goto cleanup; |
| } |
| /* client has finished! */ |
| |
| if (responses) { |
| |
| /* |
| * We have a List of LdapResponse objects that still have to be |
| * turned into Crls. |
| */ |
| PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList |
| (responses, &unfilteredCRLs, plContext), |
| PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED); |
| |
| PKIX_CHECK(pkix_CRLSelector_Select |
| (selector, unfilteredCRLs, &filteredCRLs, plContext), |
| PKIX_CRLSELECTORSELECTFAILED); |
| |
| } |
| |
| /* Don't throw away the list if one CRL was bad! */ |
| pkixTempErrorReceived = PKIX_FALSE; |
| |
| *pNBIOContext = NULL; |
| *pCrlList = filteredCRLs; |
| |
| cleanup: |
| |
| if (PKIX_ERROR_RECEIVED) { |
| PKIX_DECREF(filteredCRLs); |
| } |
| |
| PKIX_DECREF(params); |
| PKIX_DECREF(issuerNames); |
| PKIX_DECREF(issuer); |
| PKIX_DECREF(candidate); |
| PKIX_DECREF(responses); |
| PKIX_DECREF(unfilteredCRLs); |
| PKIX_DECREF(lcs); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |
| /* |
| * FUNCTION: pkix_pl_LdapCertStore_GetCRLContinue |
| * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h) |
| */ |
| PKIX_Error * |
| pkix_pl_LdapCertStore_GetCRLContinue( |
| PKIX_CertStore *store, |
| PKIX_CRLSelector *selector, |
| void **pNBIOContext, |
| PKIX_List **pCrlList, |
| void *plContext) |
| { |
| void *nbio = NULL; |
| PKIX_PL_CRL *candidate = NULL; |
| PKIX_List *responses = NULL; |
| PKIX_PL_LdapCertStoreContext *lcs = NULL; |
| PKIX_List *filteredCRLs = NULL; |
| PKIX_List *unfilteredCRLs = NULL; |
| |
| PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRLContinue"); |
| PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList); |
| |
| PKIX_CHECK(PKIX_CertStore_GetCertStoreContext |
| (store, (PKIX_PL_Object **)&lcs, plContext), |
| PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED); |
| |
| PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest |
| ((PKIX_PL_LdapClient *)lcs, &nbio, &responses, plContext), |
| PKIX_LDAPCLIENTRESUMEREQUESTFAILED); |
| |
| if (nbio != NULL) { |
| /* client is waiting for non-blocking I/O to complete */ |
| *pNBIOContext = (void *)nbio; |
| *pCrlList = NULL; |
| goto cleanup; |
| } |
| /* client has finished! */ |
| |
| if (responses) { |
| |
| /* |
| * We have a List of LdapResponse objects that still have to be |
| * turned into Crls. |
| */ |
| PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList |
| (responses, &unfilteredCRLs, plContext), |
| PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED); |
| |
| PKIX_CHECK(pkix_CRLSelector_Select |
| (selector, unfilteredCRLs, &filteredCRLs, plContext), |
| PKIX_CRLSELECTORSELECTFAILED); |
| |
| PKIX_CHECK(PKIX_List_SetImmutable(filteredCRLs, plContext), |
| PKIX_LISTSETIMMUTABLEFAILED); |
| |
| } |
| |
| /* Don't throw away the list if one CRL was bad! */ |
| pkixTempErrorReceived = PKIX_FALSE; |
| |
| *pCrlList = filteredCRLs; |
| |
| cleanup: |
| if (PKIX_ERROR_RECEIVED) { |
| PKIX_DECREF(filteredCRLs); |
| } |
| |
| PKIX_DECREF(candidate); |
| PKIX_DECREF(responses); |
| PKIX_DECREF(unfilteredCRLs); |
| PKIX_DECREF(lcs); |
| |
| PKIX_RETURN(CERTSTORE); |
| } |
| |
| /* --Public-LdapCertStore-Functions----------------------------------- */ |
| |
| /* |
| * FUNCTION: PKIX_PL_LdapCertStore_Create |
| * (see comments in pkix_samples_modules.h) |
| */ |
| PKIX_Error * |
| PKIX_PL_LdapCertStore_Create( |
| PKIX_PL_LdapClient *client, |
| PKIX_CertStore **pCertStore, |
| void *plContext) |
| { |
| PKIX_CertStore *certStore = NULL; |
| |
| PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapCertStore_Create"); |
| PKIX_NULLCHECK_TWO(client, pCertStore); |
| |
| PKIX_CHECK(PKIX_CertStore_Create |
| (pkix_pl_LdapCertStore_GetCert, |
| pkix_pl_LdapCertStore_GetCRL, |
| pkix_pl_LdapCertStore_GetCertContinue, |
| pkix_pl_LdapCertStore_GetCRLContinue, |
| NULL, /* don't support trust */ |
| NULL, /* can not store crls */ |
| NULL, /* can not do revocation check */ |
| (PKIX_PL_Object *)client, |
| PKIX_TRUE, /* cache flag */ |
| PKIX_FALSE, /* not local */ |
| &certStore, |
| plContext), |
| PKIX_CERTSTORECREATEFAILED); |
| |
| *pCertStore = certStore; |
| |
| cleanup: |
| |
| PKIX_RETURN(CERTSTORE); |
| } |