1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5  * pkix_pl_aiamgr.c
6  *
7  * AIAMgr Object Definitions
8  *
9  */
10 
11 #include "pkix_pl_aiamgr.h"
12 extern PKIX_PL_HashTable *aiaConnectionCache;
13 
14 #ifndef NSS_PKIX_NO_LDAP
15 /* --Virtual-LdapClient-Functions------------------------------------ */
16 
17 PKIX_Error *
PKIX_PL_LdapClient_InitiateRequest(PKIX_PL_LdapClient * client,LDAPRequestParams * requestParams,void ** pNBIO,PKIX_List ** pResponse,void * plContext)18 PKIX_PL_LdapClient_InitiateRequest(
19         PKIX_PL_LdapClient *client,
20         LDAPRequestParams *requestParams,
21         void **pNBIO,
22         PKIX_List **pResponse,
23         void *plContext)
24 {
25         PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_InitiateRequest");
26         PKIX_NULLCHECK_TWO(client, client->initiateFcn);
27 
28         PKIX_CHECK(client->initiateFcn
29                 (client, requestParams, pNBIO, pResponse, plContext),
30                 PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
31 cleanup:
32 
33         PKIX_RETURN(LDAPCLIENT);
34 
35 }
36 
37 PKIX_Error *
PKIX_PL_LdapClient_ResumeRequest(PKIX_PL_LdapClient * client,void ** pNBIO,PKIX_List ** pResponse,void * plContext)38 PKIX_PL_LdapClient_ResumeRequest(
39         PKIX_PL_LdapClient *client,
40         void **pNBIO,
41         PKIX_List **pResponse,
42         void *plContext)
43 {
44         PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_ResumeRequest");
45         PKIX_NULLCHECK_TWO(client, client->resumeFcn);
46 
47         PKIX_CHECK(client->resumeFcn
48                 (client, pNBIO, pResponse, plContext),
49                 PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
50 cleanup:
51 
52         PKIX_RETURN(LDAPCLIENT);
53 
54 }
55 #endif /* !NSS_PKIX_NO_LDAP */
56 
57 /* --Private-AIAMgr-Functions----------------------------------*/
58 
59 /*
60  * FUNCTION: pkix_pl_AIAMgr_Destroy
61  * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
62  */
63 static PKIX_Error *
pkix_pl_AIAMgr_Destroy(PKIX_PL_Object * object,void * plContext)64 pkix_pl_AIAMgr_Destroy(
65         PKIX_PL_Object *object,
66         void *plContext)
67 {
68         PKIX_PL_AIAMgr *aiaMgr = NULL;
69 
70         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_Destroy");
71         PKIX_NULLCHECK_ONE(object);
72 
73         PKIX_CHECK(pkix_CheckType(object, PKIX_AIAMGR_TYPE, plContext),
74                 PKIX_OBJECTNOTAIAMGR);
75 
76         aiaMgr = (PKIX_PL_AIAMgr *)object;
77 
78         /* pointer to cert cache */
79         /* pointer to crl cache */
80         aiaMgr->method = 0;
81         aiaMgr->aiaIndex = 0;
82         aiaMgr->numAias = 0;
83         PKIX_DECREF(aiaMgr->aia);
84         PKIX_DECREF(aiaMgr->location);
85         PKIX_DECREF(aiaMgr->results);
86 #ifndef NSS_PKIX_NO_LDAP
87         PKIX_DECREF(aiaMgr->client.ldapClient);
88 #endif
89 
90 cleanup:
91 
92         PKIX_RETURN(AIAMGR);
93 }
94 
95 /*
96  * FUNCTION: pkix_pl_AIAMgr_RegisterSelf
97  * DESCRIPTION:
98  *  Registers PKIX_AIAMGR_TYPE and its related functions with systemClasses[]
99  * THREAD SAFETY:
100  *  Not Thread Safe - for performance and complexity reasons
101  *
102  *  Since this function is only called by PKIX_PL_Initialize, which should
103  *  only be called once, it is acceptable that this function is not
104  *  thread-safe.
105  */
106 PKIX_Error *
pkix_pl_AIAMgr_RegisterSelf(void * plContext)107 pkix_pl_AIAMgr_RegisterSelf(void *plContext)
108 {
109         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
110         pkix_ClassTable_Entry *entry = &systemClasses[PKIX_AIAMGR_TYPE];
111 
112         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_RegisterSelf");
113 
114         entry->description = "AIAMgr";
115         entry->typeObjectSize = sizeof(PKIX_PL_AIAMgr);
116         entry->destructor = pkix_pl_AIAMgr_Destroy;
117 
118         PKIX_RETURN(AIAMGR);
119 }
120 
121 #ifndef NSS_PKIX_NO_LDAP
122 /*
123  * FUNCTION: pkix_pl_AiaMgr_FindLDAPClient
124  * DESCRIPTION:
125  *
126  *  This function checks the collection of LDAPClient connections held by the
127  *  AIAMgr pointed to by "aiaMgr" for one matching the domain name given by
128  *  "domainName". The string may include a port number: e.g., "betty.nist.gov"
129  *  or "nss.red.iplanet.com:1389". If a match is found, that LDAPClient is
130  *  stored at "pClient". Otherwise, an LDAPClient is created and added to the
131  *  collection, and then stored at "pClient".
132  *
133  * PARAMETERS:
134  *  "aiaMgr"
135  *      The AIAMgr whose LDAPClient connected are to be managed. Must be
136  *      non-NULL.
137  *  "domainName"
138  *      Address of a string pointing to a server name. Must be non-NULL.
139  *      An empty string (which means no <host> is given in the LDAP URL) is
140  *      not supported.
141  *  "pClient"
142  *      Address at which the returned LDAPClient is stored. Must be non-NULL.
143  *  "plContext"
144  *      Platform-specific context pointer.
145  * THREAD SAFETY:
146  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
147  * RETURNS:
148  *  Returns NULL if the function succeeds.
149  *  Returns an AIAMgr Error if the function fails in a non-fatal way
150  *  Returns a Fatal Error if the function fails in an unrecoverable way.
151  */
152 static PKIX_Error *
pkix_pl_AiaMgr_FindLDAPClient(PKIX_PL_AIAMgr * aiaMgr,char * domainName,PKIX_PL_LdapClient ** pClient,void * plContext)153 pkix_pl_AiaMgr_FindLDAPClient(
154         PKIX_PL_AIAMgr *aiaMgr,
155         char *domainName,
156         PKIX_PL_LdapClient **pClient,
157         void *plContext)
158 {
159         PKIX_PL_String *domainString = NULL;
160         PKIX_PL_LdapDefaultClient *client = NULL;
161 
162         PKIX_ENTER(AIAMGR, "pkix_pl_AiaMgr_FindLDAPClient");
163         PKIX_NULLCHECK_THREE(aiaMgr, domainName, pClient);
164 
165         /*
166          * An LDAP URL may not have a <host> part, for example,
167          *     ldap:///o=University%20of%20Michigan,c=US
168          * PKIX_PL_LdapDefaultClient doesn't know how to discover the default
169          * LDAP server, so we don't support this kind of LDAP URL.
170          */
171         if (*domainName == '\0') {
172                 /* Simulate a PKIX_PL_LdapDefaultClient_CreateByName failure. */
173                 PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
174         }
175 
176         /* create PKIX_PL_String from domain name */
177         PKIX_CHECK(PKIX_PL_String_Create
178                 (PKIX_ESCASCII, domainName, 0, &domainString, plContext),
179                 PKIX_STRINGCREATEFAILED);
180 
181         /* Is this domainName already in cache? */
182         PKIX_CHECK(PKIX_PL_HashTable_Lookup
183                 (aiaConnectionCache,
184                 (PKIX_PL_Object *)domainString,
185                 (PKIX_PL_Object **)&client,
186                 plContext),
187                 PKIX_HASHTABLELOOKUPFAILED);
188 
189         if (client == NULL) {
190 
191                 /* No, create a connection (and cache it) */
192                 PKIX_CHECK(PKIX_PL_LdapDefaultClient_CreateByName
193                         (domainName,
194                          /* Do not use NBIO until we verify, that
195                           * it is working. For now use 1 min timeout. */
196                         PR_SecondsToInterval(
197                             ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
198                         NULL,
199                         &client,
200                         plContext),
201                         PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
202 
203                 PKIX_CHECK(PKIX_PL_HashTable_Add
204                         (aiaConnectionCache,
205                         (PKIX_PL_Object *)domainString,
206                         (PKIX_PL_Object *)client,
207                         plContext),
208                         PKIX_HASHTABLEADDFAILED);
209 
210         }
211 
212         *pClient = (PKIX_PL_LdapClient *)client;
213 
214 cleanup:
215 
216         PKIX_DECREF(domainString);
217 
218         PKIX_RETURN(AIAMGR);
219 }
220 #endif /* !NSS_PKIX_NO_LDAP */
221 
222 PKIX_Error *
pkix_pl_AIAMgr_GetHTTPCerts(PKIX_PL_AIAMgr * aiaMgr,PKIX_PL_InfoAccess * ia,void ** pNBIOContext,PKIX_List ** pCerts,void * plContext)223 pkix_pl_AIAMgr_GetHTTPCerts(
224         PKIX_PL_AIAMgr *aiaMgr,
225 	PKIX_PL_InfoAccess *ia,
226 	void **pNBIOContext,
227 	PKIX_List **pCerts,
228         void *plContext)
229 {
230         PKIX_PL_GeneralName *location = NULL;
231         PKIX_PL_String *locationString = NULL;
232 	PKIX_UInt32 len = 0;
233 	PRUint16 port = 0;
234 	const SEC_HttpClientFcn *httpClient = NULL;
235 	const SEC_HttpClientFcnV1 *hcv1 = NULL;
236 	SECStatus rv = SECFailure;
237 	SEC_HTTP_SERVER_SESSION serverSession = NULL;
238 	SEC_HTTP_REQUEST_SESSION requestSession = NULL;
239 	char *path = NULL;
240 	char *hostname = NULL;
241 	char *locationAscii = NULL;
242 	void *nbio = NULL;
243 	PRUint16 responseCode = 0;
244 	const char *responseContentType = NULL;
245 	const char *responseData = NULL;
246 
247         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts");
248         PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);
249 
250         nbio = *pNBIOContext;
251         *pNBIOContext = NULL;
252         *pCerts = NULL;
253 
254         if (nbio == NULL) { /* a new request */
255 
256                 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
257                         (ia, &location, plContext),
258                        PKIX_INFOACCESSGETLOCATIONFAILED);
259 
260                 /* find or create httpClient = default client */
261 		httpClient = SEC_GetRegisteredHttpClient();
262 		aiaMgr->client.hdata.httpClient = httpClient;
263 		if (!httpClient)
264 		    PKIX_ERROR(PKIX_OUTOFMEMORY);
265 
266 		if (httpClient->version == 1) {
267 
268                         PKIX_UInt32 timeout =
269                              ((PKIX_PL_NssContext*)plContext)->timeoutSeconds;
270 
271 			hcv1 = &(httpClient->fcnTable.ftable1);
272 
273 			/* create server session */
274 			PKIX_TOSTRING(location, &locationString, plContext,
275 				PKIX_GENERALNAMETOSTRINGFAILED);
276 
277 			PKIX_CHECK(PKIX_PL_String_GetEncoded
278 				(locationString,
279 				PKIX_ESCASCII,
280 				(void **)&locationAscii,
281 				&len,
282 				plContext),
283 				PKIX_STRINGGETENCODEDFAILED);
284 
285                         rv = CERT_ParseURL(locationAscii, &hostname, &port,
286                                             &path);
287 			if ((rv != SECSuccess) ||
288 			    (hostname == NULL) ||
289 			    (path == NULL)) {
290 				PKIX_ERROR(PKIX_URLPARSINGFAILED);
291 			}
292 
293                         rv = (*hcv1->createSessionFcn)(hostname, port,
294                                                        &serverSession);
295 	                if (rv != SECSuccess) {
296 				PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED);
297 			}
298 
299 			aiaMgr->client.hdata.serverSession = serverSession;
300 
301 			/* create request session */
302                         rv = (*hcv1->createFcn)(serverSession, "http", path,
303                         	"GET", PR_SecondsToInterval(timeout),
304                                  &requestSession);
305                 	if (rv != SECSuccess) {
306                         	PKIX_ERROR(PKIX_HTTPSERVERERROR);
307                 	}
308 
309 			aiaMgr->client.hdata.requestSession = requestSession;
310 		} else {
311 			PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
312 		}
313 	}
314 
315 	httpClient = aiaMgr->client.hdata.httpClient;
316 
317 	if (httpClient->version == 1) {
318                 PRUint32 responseDataLen =
319                    ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
320 
321 		hcv1 = &(httpClient->fcnTable.ftable1);
322 		requestSession = aiaMgr->client.hdata.requestSession;
323 
324 		/* trySendAndReceive */
325                 rv = (*hcv1->trySendAndReceiveFcn)(requestSession,
326                                  (PRPollDesc **)&nbio,
327                                  &responseCode,
328                                  (const char **)&responseContentType,
329                                  NULL, /* &responseHeaders */
330                                  (const char **)&responseData,
331                                  &responseDataLen);
332 
333                 if (rv != SECSuccess) {
334                         PKIX_ERROR(PKIX_HTTPSERVERERROR);
335                 }
336 
337                 if (nbio != 0) {
338                         *pNBIOContext = nbio;
339                         goto cleanup;
340                 }
341 
342 		PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
343 	                (responseCode,
344 	                responseContentType,
345 	                responseData,
346 	                responseDataLen,
347 	                pCerts,
348 	                plContext),
349 	                PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
350 
351                 /* Session and request cleanup in case of success */
352                 if (aiaMgr->client.hdata.requestSession != NULL) {
353                     (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
354                     aiaMgr->client.hdata.requestSession = NULL;
355                 }
356                 if (aiaMgr->client.hdata.serverSession != NULL) {
357                     (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
358                     aiaMgr->client.hdata.serverSession = NULL;
359                 }
360                 aiaMgr->client.hdata.httpClient = 0; /* callback fn */
361 
362         } else  {
363 		PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
364 	}
365 
366 cleanup:
367         /* Session and request cleanup in case of error. Passing through without cleanup
368          * if interrupted by blocked IO. */
369         if (PKIX_ERROR_RECEIVED) {
370             if (aiaMgr->client.hdata.requestSession != NULL) {
371                 (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
372                 aiaMgr->client.hdata.requestSession = NULL;
373             }
374             if (aiaMgr->client.hdata.serverSession != NULL) {
375                 (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
376                 aiaMgr->client.hdata.serverSession = NULL;
377             }
378             aiaMgr->client.hdata.httpClient = 0; /* callback fn */
379         }
380 
381         PKIX_DECREF(location);
382         PKIX_DECREF(locationString);
383 
384         if (locationAscii) {
385             PORT_Free(locationAscii);
386         }
387         if (hostname) {
388             PORT_Free(hostname);
389         }
390         if (path) {
391             PORT_Free(path);
392         }
393 
394         PKIX_RETURN(AIAMGR);
395 }
396 
397 #ifndef NSS_PKIX_NO_LDAP
398 PKIX_Error *
pkix_pl_AIAMgr_GetLDAPCerts(PKIX_PL_AIAMgr * aiaMgr,PKIX_PL_InfoAccess * ia,void ** pNBIOContext,PKIX_List ** pCerts,void * plContext)399 pkix_pl_AIAMgr_GetLDAPCerts(
400         PKIX_PL_AIAMgr *aiaMgr,
401 	PKIX_PL_InfoAccess *ia,
402 	void **pNBIOContext,
403 	PKIX_List **pCerts,
404         void *plContext)
405 {
406         PKIX_List *result = NULL;
407         PKIX_PL_GeneralName *location = NULL;
408         PKIX_PL_LdapClient *client = NULL;
409         LDAPRequestParams request;
410         PLArenaPool *arena = NULL;
411         char *domainName = NULL;
412 	void *nbio = NULL;
413 
414         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts");
415         PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);
416 
417         nbio = *pNBIOContext;
418         *pNBIOContext = NULL;
419         *pCerts = NULL;
420 
421         if (nbio == NULL) { /* a new request */
422 
423                 /* Initiate an LDAP request */
424 
425                 request.scope = WHOLE_SUBTREE;
426                 request.derefAliases = NEVER_DEREF;
427                 request.sizeLimit = 0;
428                 request.timeLimit = 0;
429 
430                 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
431                         (ia, &location, plContext),
432                         PKIX_INFOACCESSGETLOCATIONFAILED);
433 
434                 /*
435                  * Get a short-lived arena. We'll be done with
436                  * this space once the request is encoded.
437                  */
438                 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
439                 if (!arena) {
440                         PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
441                 }
442 
443                 PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation
444                         (location, arena, &request, &domainName, plContext),
445                         PKIX_INFOACCESSPARSELOCATIONFAILED);
446 
447                 PKIX_DECREF(location);
448 
449                 /* Find or create a connection to LDAP server */
450                 PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient
451                         (aiaMgr, domainName, &client, plContext),
452                         PKIX_AIAMGRFINDLDAPCLIENTFAILED);
453 
454                 aiaMgr->client.ldapClient = client;
455 
456                 PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
457                         (aiaMgr->client.ldapClient,
458 			&request,
459 			&nbio,
460 			&result,
461 			plContext),
462                         PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
463 
464                 PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
465 
466         } else {
467 
468                 PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
469                         (aiaMgr->client.ldapClient, &nbio, &result, plContext),
470                         PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
471 
472         }
473 
474         if (nbio != NULL) { /* WOULDBLOCK */
475                 *pNBIOContext = nbio;
476                 *pCerts = NULL;
477                 goto cleanup;
478         }
479 
480 	PKIX_DECREF(aiaMgr->client.ldapClient);
481 
482 	if (result == NULL) {
483 		*pCerts = NULL;
484 	} else {
485 		PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
486 			(result, pCerts, plContext),
487 			PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
488 	}
489 
490 	*pNBIOContext = nbio;
491 
492 cleanup:
493 
494         if (arena && (PKIX_ERROR_RECEIVED)) {
495                 PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
496         }
497 
498         if (PKIX_ERROR_RECEIVED) {
499 	        PKIX_DECREF(aiaMgr->client.ldapClient);
500 	}
501 
502         PKIX_DECREF(location);
503 
504         PKIX_RETURN(AIAMGR);
505 }
506 #endif /* !NSS_PKIX_NO_LDAP */
507 
508 /*
509  * FUNCTION: PKIX_PL_AIAMgr_Create
510  * DESCRIPTION:
511  *
512  *  This function creates an AIAMgr, storing the result at "pAIAMgr".
513  *
514  * PARAMETERS:
515  *  "pAIAMGR"
516  *      Address at which the returned AIAMgr is stored. Must be non-NULL.
517  *  "plContext"
518  *      Platform-specific context pointer.
519  * THREAD SAFETY:
520  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
521  * RETURNS:
522  *  Returns NULL if the function succeeds.
523  *  Returns an AIAMgr Error if the function fails in a non-fatal way
524  *  Returns a Fatal Error if the function fails in an unrecoverable way.
525  */
526 PKIX_Error *
PKIX_PL_AIAMgr_Create(PKIX_PL_AIAMgr ** pAIAMgr,void * plContext)527 PKIX_PL_AIAMgr_Create(
528         PKIX_PL_AIAMgr **pAIAMgr,
529         void *plContext)
530 {
531         PKIX_PL_AIAMgr *aiaMgr = NULL;
532 
533         PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_Create");
534         PKIX_NULLCHECK_ONE(pAIAMgr);
535 
536         PKIX_CHECK(PKIX_PL_Object_Alloc
537                 (PKIX_AIAMGR_TYPE,
538                 sizeof(PKIX_PL_AIAMgr),
539                 (PKIX_PL_Object **)&aiaMgr,
540                 plContext),
541                 PKIX_COULDNOTCREATEAIAMGROBJECT);
542         /* pointer to cert cache */
543         /* pointer to crl cache */
544         aiaMgr->method = 0;
545         aiaMgr->aiaIndex = 0;
546         aiaMgr->numAias = 0;
547         aiaMgr->aia = NULL;
548         aiaMgr->location = NULL;
549         aiaMgr->results = NULL;
550         aiaMgr->client.hdata.httpClient = NULL;
551 	aiaMgr->client.hdata.serverSession = NULL;
552 	aiaMgr->client.hdata.requestSession = NULL;
553 
554         *pAIAMgr = aiaMgr;
555 
556 cleanup:
557 
558         PKIX_RETURN(AIAMGR);
559 }
560 
561 /* --Public-Functions------------------------------------------------------- */
562 
563 /*
564  * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h)
565  */
566 PKIX_Error *
PKIX_PL_AIAMgr_GetAIACerts(PKIX_PL_AIAMgr * aiaMgr,PKIX_PL_Cert * prevCert,void ** pNBIOContext,PKIX_List ** pCerts,void * plContext)567 PKIX_PL_AIAMgr_GetAIACerts(
568         PKIX_PL_AIAMgr *aiaMgr,
569         PKIX_PL_Cert *prevCert,
570         void **pNBIOContext,
571         PKIX_List **pCerts,
572         void *plContext)
573 {
574         PKIX_UInt32 numAias = 0;
575         PKIX_UInt32 aiaIndex = 0;
576         PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN;
577         PKIX_List *certs = NULL;
578         PKIX_PL_InfoAccess *ia = NULL;
579         void *nbio = NULL;
580 
581         PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts");
582         PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts);
583 
584         nbio = *pNBIOContext;
585         *pCerts = NULL;
586         *pNBIOContext = NULL;
587 
588         if (nbio == NULL) { /* a new request */
589 
590                 /* Does this Cert have an AIA extension? */
591                 PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
592                         (prevCert, &aiaMgr->aia, plContext),
593                         PKIX_CERTGETAUTHORITYINFOACCESSFAILED);
594 
595                 if (aiaMgr->aia != NULL) {
596                         PKIX_CHECK(PKIX_List_GetLength
597                                 (aiaMgr->aia, &numAias, plContext),
598                                 PKIX_LISTGETLENGTHFAILED);
599                 }
600 
601                 /* And if so, does it have any entries? */
602                 if ((aiaMgr->aia == NULL) || (numAias == 0)) {
603                         *pCerts = NULL;
604                         goto cleanup;
605                 }
606 
607                 aiaMgr->aiaIndex = 0;
608                 aiaMgr->numAias = numAias;
609                 aiaMgr->results = NULL;
610 
611         }
612 
613         for (aiaIndex = aiaMgr->aiaIndex;
614                 aiaIndex < aiaMgr->numAias;
615                 aiaIndex ++) {
616                 PKIX_UInt32 method = 0;
617 
618                 PKIX_CHECK(PKIX_List_GetItem
619                         (aiaMgr->aia,
620                         aiaIndex,
621                         (PKIX_PL_Object **)&ia,
622                         plContext),
623                         PKIX_LISTGETITEMFAILED);
624 
625                 PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod
626                         (ia, &method, plContext),
627                         PKIX_INFOACCESSGETMETHODFAILED);
628 
629                 if (method != PKIX_INFOACCESS_CA_ISSUERS &&
630                     method != PKIX_INFOACCESS_CA_REPOSITORY) {
631                     PKIX_DECREF(ia);
632                     continue;
633                 }
634 
635                 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType
636                         (ia, &iaType, plContext),
637                         PKIX_INFOACCESSGETLOCATIONTYPEFAILED);
638 
639                 if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) {
640 			PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts
641 				(aiaMgr, ia, &nbio, &certs, plContext),
642 				PKIX_AIAMGRGETHTTPCERTSFAILED);
643 #ifndef NSS_PKIX_NO_LDAP
644                 } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) {
645 			PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts
646 				(aiaMgr, ia, &nbio, &certs, plContext),
647 				PKIX_AIAMGRGETLDAPCERTSFAILED);
648 #endif
649                 } else {
650                         /* We only support http and ldap requests. */
651                         PKIX_DECREF(ia);
652                         continue;
653                 }
654 
655                 if (nbio != NULL) { /* WOULDBLOCK */
656                         aiaMgr->aiaIndex = aiaIndex;
657                         *pNBIOContext = nbio;
658                         *pCerts = NULL;
659                         goto cleanup;
660                 }
661 
662                 /*
663                  * We can't just use and modify the List we received.
664                  * Because it's cached, it's set immutable.
665                  */
666                 if (aiaMgr->results == NULL) {
667                         PKIX_CHECK(PKIX_List_Create
668                                 (&(aiaMgr->results), plContext),
669                                 PKIX_LISTCREATEFAILED);
670                 }
671                 PKIX_CHECK(pkix_List_AppendList
672                         (aiaMgr->results, certs, plContext),
673                         PKIX_APPENDLISTFAILED);
674                 PKIX_DECREF(certs);
675 
676                 PKIX_DECREF(ia);
677         }
678 
679         PKIX_DECREF(aiaMgr->aia);
680 
681         *pNBIOContext = NULL;
682         *pCerts = aiaMgr->results;
683         aiaMgr->results = NULL;
684 
685 cleanup:
686 
687         if (PKIX_ERROR_RECEIVED) {
688                 PKIX_DECREF(aiaMgr->aia);
689                 PKIX_DECREF(aiaMgr->results);
690 #ifndef NSS_PKIX_NO_LDAP
691                 PKIX_DECREF(aiaMgr->client.ldapClient);
692 #endif
693         }
694 
695         PKIX_DECREF(certs);
696         PKIX_DECREF(ia);
697 
698         PKIX_RETURN(AIAMGR);
699 }
700