andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * pkix_pl_aiamgr.c andre@0: * andre@0: * AIAMgr Object Definitions andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_pl_aiamgr.h" andre@0: extern PKIX_PL_HashTable *aiaConnectionCache; andre@0: andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: /* --Virtual-LdapClient-Functions------------------------------------ */ andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_LdapClient_InitiateRequest( andre@0: PKIX_PL_LdapClient *client, andre@0: LDAPRequestParams *requestParams, andre@0: void **pNBIO, andre@0: PKIX_List **pResponse, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_InitiateRequest"); andre@0: PKIX_NULLCHECK_TWO(client, client->initiateFcn); andre@0: andre@0: PKIX_CHECK(client->initiateFcn andre@0: (client, requestParams, pNBIO, pResponse, plContext), andre@0: PKIX_LDAPCLIENTINITIATEREQUESTFAILED); andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPCLIENT); andre@0: andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_LdapClient_ResumeRequest( andre@0: PKIX_PL_LdapClient *client, andre@0: void **pNBIO, andre@0: PKIX_List **pResponse, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_ResumeRequest"); andre@0: PKIX_NULLCHECK_TWO(client, client->resumeFcn); andre@0: andre@0: PKIX_CHECK(client->resumeFcn andre@0: (client, pNBIO, pResponse, plContext), andre@0: PKIX_LDAPCLIENTRESUMEREQUESTFAILED); andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPCLIENT); andre@0: andre@0: } andre@0: #endif /* !NSS_PKIX_NO_LDAP */ andre@0: andre@0: /* --Private-AIAMgr-Functions----------------------------------*/ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_AIAMgr_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_AIAMgr_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_AIAMgr *aiaMgr = NULL; andre@0: andre@0: PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_Destroy"); andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_AIAMGR_TYPE, plContext), andre@0: PKIX_OBJECTNOTAIAMGR); andre@0: andre@0: aiaMgr = (PKIX_PL_AIAMgr *)object; andre@0: andre@0: /* pointer to cert cache */ andre@0: /* pointer to crl cache */ andre@0: aiaMgr->method = 0; andre@0: aiaMgr->aiaIndex = 0; andre@0: aiaMgr->numAias = 0; andre@0: PKIX_DECREF(aiaMgr->aia); andre@0: PKIX_DECREF(aiaMgr->location); andre@0: PKIX_DECREF(aiaMgr->results); andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: PKIX_DECREF(aiaMgr->client.ldapClient); andre@0: #endif andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(AIAMGR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_AIAMgr_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_AIAMGR_TYPE and its related functions with systemClasses[] andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, which should andre@0: * only be called once, it is acceptable that this function is not andre@0: * thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_AIAMgr_RegisterSelf(void *plContext) andre@0: { andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry *entry = &systemClasses[PKIX_AIAMGR_TYPE]; andre@0: andre@0: PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_RegisterSelf"); andre@0: andre@0: entry->description = "AIAMgr"; andre@0: entry->typeObjectSize = sizeof(PKIX_PL_AIAMgr); andre@0: entry->destructor = pkix_pl_AIAMgr_Destroy; andre@0: andre@0: PKIX_RETURN(AIAMGR); andre@0: } andre@0: andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: /* andre@0: * FUNCTION: pkix_pl_AiaMgr_FindLDAPClient andre@0: * DESCRIPTION: andre@0: * andre@0: * This function checks the collection of LDAPClient connections held by the andre@0: * AIAMgr pointed to by "aiaMgr" for one matching the domain name given by andre@0: * "domainName". The string may include a port number: e.g., "betty.nist.gov" andre@0: * or "nss.red.iplanet.com:1389". If a match is found, that LDAPClient is andre@0: * stored at "pClient". Otherwise, an LDAPClient is created and added to the andre@0: * collection, and then stored at "pClient". andre@0: * andre@0: * PARAMETERS: andre@0: * "aiaMgr" andre@0: * The AIAMgr whose LDAPClient connected are to be managed. Must be andre@0: * non-NULL. andre@0: * "domainName" andre@0: * Address of a string pointing to a server name. Must be non-NULL. andre@0: * An empty string (which means no is given in the LDAP URL) is andre@0: * not supported. andre@0: * "pClient" andre@0: * Address at which the returned LDAPClient is stored. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an AIAMgr Error if the function fails in a non-fatal way andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_AiaMgr_FindLDAPClient( andre@0: PKIX_PL_AIAMgr *aiaMgr, andre@0: char *domainName, andre@0: PKIX_PL_LdapClient **pClient, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *domainString = NULL; andre@0: PKIX_PL_LdapDefaultClient *client = NULL; andre@0: andre@0: PKIX_ENTER(AIAMGR, "pkix_pl_AiaMgr_FindLDAPClient"); andre@0: PKIX_NULLCHECK_THREE(aiaMgr, domainName, pClient); andre@0: andre@0: /* andre@0: * An LDAP URL may not have a part, for example, andre@0: * ldap:///o=University%20of%20Michigan,c=US andre@0: * PKIX_PL_LdapDefaultClient doesn't know how to discover the default andre@0: * LDAP server, so we don't support this kind of LDAP URL. andre@0: */ andre@0: if (*domainName == '\0') { andre@0: /* Simulate a PKIX_PL_LdapDefaultClient_CreateByName failure. */ andre@0: PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED); andre@0: } andre@0: andre@0: /* create PKIX_PL_String from domain name */ andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, domainName, 0, &domainString, plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: /* Is this domainName already in cache? */ andre@0: PKIX_CHECK(PKIX_PL_HashTable_Lookup andre@0: (aiaConnectionCache, andre@0: (PKIX_PL_Object *)domainString, andre@0: (PKIX_PL_Object **)&client, andre@0: plContext), andre@0: PKIX_HASHTABLELOOKUPFAILED); andre@0: andre@0: if (client == NULL) { andre@0: andre@0: /* No, create a connection (and cache it) */ andre@0: PKIX_CHECK(PKIX_PL_LdapDefaultClient_CreateByName andre@0: (domainName, andre@0: /* Do not use NBIO until we verify, that andre@0: * it is working. For now use 1 min timeout. */ andre@0: PR_SecondsToInterval( andre@0: ((PKIX_PL_NssContext*)plContext)->timeoutSeconds), andre@0: NULL, andre@0: &client, andre@0: plContext), andre@0: PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_HashTable_Add andre@0: (aiaConnectionCache, andre@0: (PKIX_PL_Object *)domainString, andre@0: (PKIX_PL_Object *)client, andre@0: plContext), andre@0: PKIX_HASHTABLEADDFAILED); andre@0: andre@0: } andre@0: andre@0: *pClient = (PKIX_PL_LdapClient *)client; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_DECREF(domainString); andre@0: andre@0: PKIX_RETURN(AIAMGR); andre@0: } andre@0: #endif /* !NSS_PKIX_NO_LDAP */ andre@0: andre@0: PKIX_Error * andre@0: pkix_pl_AIAMgr_GetHTTPCerts( andre@0: PKIX_PL_AIAMgr *aiaMgr, andre@0: PKIX_PL_InfoAccess *ia, andre@0: void **pNBIOContext, andre@0: PKIX_List **pCerts, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_GeneralName *location = NULL; andre@0: PKIX_PL_String *locationString = NULL; andre@0: PKIX_UInt32 len = 0; andre@0: PRUint16 port = 0; andre@0: const SEC_HttpClientFcn *httpClient = NULL; andre@0: const SEC_HttpClientFcnV1 *hcv1 = NULL; andre@0: SECStatus rv = SECFailure; andre@0: SEC_HTTP_SERVER_SESSION serverSession = NULL; andre@0: SEC_HTTP_REQUEST_SESSION requestSession = NULL; andre@0: char *path = NULL; andre@0: char *hostname = NULL; andre@0: char *locationAscii = NULL; andre@0: void *nbio = NULL; andre@0: PRUint16 responseCode = 0; andre@0: const char *responseContentType = NULL; andre@0: const char *responseData = NULL; andre@0: andre@0: PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts"); andre@0: PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts); andre@0: andre@0: nbio = *pNBIOContext; andre@0: *pNBIOContext = NULL; andre@0: *pCerts = NULL; andre@0: andre@0: if (nbio == NULL) { /* a new request */ andre@0: andre@0: PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation andre@0: (ia, &location, plContext), andre@0: PKIX_INFOACCESSGETLOCATIONFAILED); andre@0: andre@0: /* find or create httpClient = default client */ andre@0: httpClient = SEC_GetRegisteredHttpClient(); andre@0: aiaMgr->client.hdata.httpClient = httpClient; andre@0: if (!httpClient) andre@0: PKIX_ERROR(PKIX_OUTOFMEMORY); andre@0: andre@0: if (httpClient->version == 1) { andre@0: andre@0: PKIX_UInt32 timeout = andre@0: ((PKIX_PL_NssContext*)plContext)->timeoutSeconds; andre@0: andre@0: hcv1 = &(httpClient->fcnTable.ftable1); andre@0: andre@0: /* create server session */ andre@0: PKIX_TOSTRING(location, &locationString, plContext, andre@0: PKIX_GENERALNAMETOSTRINGFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_GetEncoded andre@0: (locationString, andre@0: PKIX_ESCASCII, andre@0: (void **)&locationAscii, andre@0: &len, andre@0: plContext), andre@0: PKIX_STRINGGETENCODEDFAILED); andre@0: andre@0: rv = CERT_ParseURL(locationAscii, &hostname, &port, andre@0: &path); andre@0: if ((rv != SECSuccess) || andre@0: (hostname == NULL) || andre@0: (path == NULL)) { andre@0: PKIX_ERROR(PKIX_URLPARSINGFAILED); andre@0: } andre@0: andre@0: rv = (*hcv1->createSessionFcn)(hostname, port, andre@0: &serverSession); andre@0: if (rv != SECSuccess) { andre@0: PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED); andre@0: } andre@0: andre@0: aiaMgr->client.hdata.serverSession = serverSession; andre@0: andre@0: /* create request session */ andre@0: rv = (*hcv1->createFcn)(serverSession, "http", path, andre@0: "GET", PR_SecondsToInterval(timeout), andre@0: &requestSession); andre@0: if (rv != SECSuccess) { andre@0: PKIX_ERROR(PKIX_HTTPSERVERERROR); andre@0: } andre@0: andre@0: aiaMgr->client.hdata.requestSession = requestSession; andre@0: } else { andre@0: PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); andre@0: } andre@0: } andre@0: andre@0: httpClient = aiaMgr->client.hdata.httpClient; andre@0: andre@0: if (httpClient->version == 1) { andre@0: PRUint32 responseDataLen = andre@0: ((PKIX_PL_NssContext*)plContext)->maxResponseLength; andre@0: andre@0: hcv1 = &(httpClient->fcnTable.ftable1); andre@0: requestSession = aiaMgr->client.hdata.requestSession; andre@0: andre@0: /* trySendAndReceive */ andre@0: rv = (*hcv1->trySendAndReceiveFcn)(requestSession, andre@0: (PRPollDesc **)&nbio, andre@0: &responseCode, andre@0: (const char **)&responseContentType, andre@0: NULL, /* &responseHeaders */ andre@0: (const char **)&responseData, andre@0: &responseDataLen); andre@0: andre@0: if (rv != SECSuccess) { andre@0: PKIX_ERROR(PKIX_HTTPSERVERERROR); andre@0: } andre@0: andre@0: if (nbio != 0) { andre@0: *pNBIOContext = nbio; andre@0: goto cleanup; andre@0: } andre@0: andre@0: PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse andre@0: (responseCode, andre@0: responseContentType, andre@0: responseData, andre@0: responseDataLen, andre@0: pCerts, andre@0: plContext), andre@0: PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED); andre@0: andre@0: /* Session and request cleanup in case of success */ andre@0: if (aiaMgr->client.hdata.requestSession != NULL) { andre@0: (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); andre@0: aiaMgr->client.hdata.requestSession = NULL; andre@0: } andre@0: if (aiaMgr->client.hdata.serverSession != NULL) { andre@0: (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); andre@0: aiaMgr->client.hdata.serverSession = NULL; andre@0: } andre@0: aiaMgr->client.hdata.httpClient = 0; /* callback fn */ andre@0: andre@0: } else { andre@0: PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT); andre@0: } andre@0: andre@0: cleanup: andre@0: /* Session and request cleanup in case of error. Passing through without cleanup andre@0: * if interrupted by blocked IO. */ andre@0: if (PKIX_ERROR_RECEIVED && aiaMgr) { andre@0: if (aiaMgr->client.hdata.requestSession != NULL) { andre@0: (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession); andre@0: aiaMgr->client.hdata.requestSession = NULL; andre@0: } andre@0: if (aiaMgr->client.hdata.serverSession != NULL) { andre@0: (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession); andre@0: aiaMgr->client.hdata.serverSession = NULL; andre@0: } andre@0: aiaMgr->client.hdata.httpClient = 0; /* callback fn */ andre@0: } andre@0: andre@0: PKIX_DECREF(location); andre@0: PKIX_DECREF(locationString); andre@0: andre@0: if (locationAscii) { andre@0: PORT_Free(locationAscii); andre@0: } andre@0: if (hostname) { andre@0: PORT_Free(hostname); andre@0: } andre@0: if (path) { andre@0: PORT_Free(path); andre@0: } andre@0: andre@0: PKIX_RETURN(AIAMGR); andre@0: } andre@0: andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: PKIX_Error * andre@0: pkix_pl_AIAMgr_GetLDAPCerts( andre@0: PKIX_PL_AIAMgr *aiaMgr, andre@0: PKIX_PL_InfoAccess *ia, andre@0: void **pNBIOContext, andre@0: PKIX_List **pCerts, andre@0: void *plContext) andre@0: { andre@0: PKIX_List *result = NULL; andre@0: PKIX_PL_GeneralName *location = NULL; andre@0: PKIX_PL_LdapClient *client = NULL; andre@0: LDAPRequestParams request; andre@0: PLArenaPool *arena = NULL; andre@0: char *domainName = NULL; andre@0: void *nbio = NULL; andre@0: andre@0: PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts"); andre@0: PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts); andre@0: andre@0: nbio = *pNBIOContext; andre@0: *pNBIOContext = NULL; andre@0: *pCerts = NULL; andre@0: andre@0: if (nbio == NULL) { /* a new request */ andre@0: andre@0: /* Initiate an LDAP request */ andre@0: andre@0: request.scope = WHOLE_SUBTREE; andre@0: request.derefAliases = NEVER_DEREF; andre@0: request.sizeLimit = 0; andre@0: request.timeLimit = 0; andre@0: andre@0: PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation andre@0: (ia, &location, plContext), andre@0: PKIX_INFOACCESSGETLOCATIONFAILED); andre@0: andre@0: /* andre@0: * Get a short-lived arena. We'll be done with andre@0: * this space once the request is encoded. andre@0: */ andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (!arena) { andre@0: PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY); andre@0: } andre@0: andre@0: PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation andre@0: (location, arena, &request, &domainName, plContext), andre@0: PKIX_INFOACCESSPARSELOCATIONFAILED); andre@0: andre@0: PKIX_DECREF(location); andre@0: andre@0: /* Find or create a connection to LDAP server */ andre@0: PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient andre@0: (aiaMgr, domainName, &client, plContext), andre@0: PKIX_AIAMGRFINDLDAPCLIENTFAILED); andre@0: andre@0: aiaMgr->client.ldapClient = client; andre@0: andre@0: PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest andre@0: (aiaMgr->client.ldapClient, andre@0: &request, andre@0: &nbio, andre@0: &result, andre@0: plContext), andre@0: PKIX_LDAPCLIENTINITIATEREQUESTFAILED); andre@0: andre@0: PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE)); andre@0: andre@0: } else { andre@0: andre@0: PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest andre@0: (aiaMgr->client.ldapClient, &nbio, &result, plContext), andre@0: PKIX_LDAPCLIENTRESUMEREQUESTFAILED); andre@0: andre@0: } andre@0: andre@0: if (nbio != NULL) { /* WOULDBLOCK */ andre@0: *pNBIOContext = nbio; andre@0: *pCerts = NULL; andre@0: goto cleanup; andre@0: } andre@0: andre@0: PKIX_DECREF(aiaMgr->client.ldapClient); andre@0: andre@0: if (result == NULL) { andre@0: *pCerts = NULL; andre@0: } else { andre@0: PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList andre@0: (result, pCerts, plContext), andre@0: PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED); andre@0: } andre@0: andre@0: *pNBIOContext = nbio; andre@0: andre@0: cleanup: andre@0: andre@0: if (arena && (PKIX_ERROR_RECEIVED)) { andre@0: PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE)); andre@0: } andre@0: andre@0: if (PKIX_ERROR_RECEIVED) { andre@0: PKIX_DECREF(aiaMgr->client.ldapClient); andre@0: } andre@0: andre@0: PKIX_DECREF(location); andre@0: andre@0: PKIX_RETURN(AIAMGR); andre@0: } andre@0: #endif /* !NSS_PKIX_NO_LDAP */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_AIAMgr_Create andre@0: * DESCRIPTION: andre@0: * andre@0: * This function creates an AIAMgr, storing the result at "pAIAMgr". andre@0: * andre@0: * PARAMETERS: andre@0: * "pAIAMGR" andre@0: * Address at which the returned AIAMgr is stored. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an AIAMgr Error if the function fails in a non-fatal way andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_AIAMgr_Create( andre@0: PKIX_PL_AIAMgr **pAIAMgr, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_AIAMgr *aiaMgr = NULL; andre@0: andre@0: PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_Create"); andre@0: PKIX_NULLCHECK_ONE(pAIAMgr); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_AIAMGR_TYPE, andre@0: sizeof(PKIX_PL_AIAMgr), andre@0: (PKIX_PL_Object **)&aiaMgr, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEAIAMGROBJECT); andre@0: /* pointer to cert cache */ andre@0: /* pointer to crl cache */ andre@0: aiaMgr->method = 0; andre@0: aiaMgr->aiaIndex = 0; andre@0: aiaMgr->numAias = 0; andre@0: aiaMgr->aia = NULL; andre@0: aiaMgr->location = NULL; andre@0: aiaMgr->results = NULL; andre@0: aiaMgr->client.hdata.httpClient = NULL; andre@0: aiaMgr->client.hdata.serverSession = NULL; andre@0: aiaMgr->client.hdata.requestSession = NULL; andre@0: andre@0: *pAIAMgr = aiaMgr; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(AIAMGR); andre@0: } andre@0: andre@0: /* --Public-Functions------------------------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_AIAMgr_GetAIACerts( andre@0: PKIX_PL_AIAMgr *aiaMgr, andre@0: PKIX_PL_Cert *prevCert, andre@0: void **pNBIOContext, andre@0: PKIX_List **pCerts, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 numAias = 0; andre@0: PKIX_UInt32 aiaIndex = 0; andre@0: PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN; andre@0: PKIX_List *certs = NULL; andre@0: PKIX_PL_InfoAccess *ia = NULL; andre@0: void *nbio = NULL; andre@0: andre@0: PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts"); andre@0: PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts); andre@0: andre@0: nbio = *pNBIOContext; andre@0: *pCerts = NULL; andre@0: *pNBIOContext = NULL; andre@0: andre@0: if (nbio == NULL) { /* a new request */ andre@0: andre@0: /* Does this Cert have an AIA extension? */ andre@0: PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess andre@0: (prevCert, &aiaMgr->aia, plContext), andre@0: PKIX_CERTGETAUTHORITYINFOACCESSFAILED); andre@0: andre@0: if (aiaMgr->aia != NULL) { andre@0: PKIX_CHECK(PKIX_List_GetLength andre@0: (aiaMgr->aia, &numAias, plContext), andre@0: PKIX_LISTGETLENGTHFAILED); andre@0: } andre@0: andre@0: /* And if so, does it have any entries? */ andre@0: if ((aiaMgr->aia == NULL) || (numAias == 0)) { andre@0: *pCerts = NULL; andre@0: goto cleanup; andre@0: } andre@0: andre@0: aiaMgr->aiaIndex = 0; andre@0: aiaMgr->numAias = numAias; andre@0: aiaMgr->results = NULL; andre@0: andre@0: } andre@0: andre@0: for (aiaIndex = aiaMgr->aiaIndex; andre@0: aiaIndex < aiaMgr->numAias; andre@0: aiaIndex ++) { andre@0: PKIX_UInt32 method = 0; andre@0: andre@0: PKIX_CHECK(PKIX_List_GetItem andre@0: (aiaMgr->aia, andre@0: aiaIndex, andre@0: (PKIX_PL_Object **)&ia, andre@0: plContext), andre@0: PKIX_LISTGETITEMFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod andre@0: (ia, &method, plContext), andre@0: PKIX_INFOACCESSGETMETHODFAILED); andre@0: andre@0: if (method != PKIX_INFOACCESS_CA_ISSUERS && andre@0: method != PKIX_INFOACCESS_CA_REPOSITORY) { andre@0: PKIX_DECREF(ia); andre@0: continue; andre@0: } andre@0: andre@0: PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType andre@0: (ia, &iaType, plContext), andre@0: PKIX_INFOACCESSGETLOCATIONTYPEFAILED); andre@0: andre@0: if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) { andre@0: PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts andre@0: (aiaMgr, ia, &nbio, &certs, plContext), andre@0: PKIX_AIAMGRGETHTTPCERTSFAILED); andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) { andre@0: PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts andre@0: (aiaMgr, ia, &nbio, &certs, plContext), andre@0: PKIX_AIAMGRGETLDAPCERTSFAILED); andre@0: #endif andre@0: } else { andre@0: /* We only support http and ldap requests. */ andre@0: PKIX_DECREF(ia); andre@0: continue; andre@0: } andre@0: andre@0: if (nbio != NULL) { /* WOULDBLOCK */ andre@0: aiaMgr->aiaIndex = aiaIndex; andre@0: *pNBIOContext = nbio; andre@0: *pCerts = NULL; andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * We can't just use and modify the List we received. andre@0: * Because it's cached, it's set immutable. andre@0: */ andre@0: if (aiaMgr->results == NULL) { andre@0: PKIX_CHECK(PKIX_List_Create andre@0: (&(aiaMgr->results), plContext), andre@0: PKIX_LISTCREATEFAILED); andre@0: } andre@0: PKIX_CHECK(pkix_List_AppendList andre@0: (aiaMgr->results, certs, plContext), andre@0: PKIX_APPENDLISTFAILED); andre@0: PKIX_DECREF(certs); andre@0: andre@0: PKIX_DECREF(ia); andre@0: } andre@0: andre@0: PKIX_DECREF(aiaMgr->aia); andre@0: andre@0: *pNBIOContext = NULL; andre@0: *pCerts = aiaMgr->results; andre@0: aiaMgr->results = NULL; andre@0: andre@0: cleanup: andre@0: andre@0: if (PKIX_ERROR_RECEIVED) { andre@0: PKIX_DECREF(aiaMgr->aia); andre@0: PKIX_DECREF(aiaMgr->results); andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: PKIX_DECREF(aiaMgr->client.ldapClient); andre@0: #endif andre@0: } andre@0: andre@0: PKIX_DECREF(certs); andre@0: PKIX_DECREF(ia); andre@0: andre@0: PKIX_RETURN(AIAMGR); andre@0: }