1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the PKIX-C library.
16 * The Initial Developer of the Original Code is
17 * Sun Microsystems, Inc.
18 * Portions created by the Initial Developer are
19 * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
22 * Sun Microsystems, Inc.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 * AIAMgr Object Definitions
44 #include "pkix_pl_aiamgr.h"
45 extern PKIX_PL_HashTable
*aiaConnectionCache
;
47 /* --Virtual-LdapClient-Functions------------------------------------ */
50 PKIX_PL_LdapClient_InitiateRequest(
51 PKIX_PL_LdapClient
*client
,
52 LDAPRequestParams
*requestParams
,
54 PKIX_List
**pResponse
,
57 PKIX_ENTER(LDAPCLIENT
, "PKIX_PL_LdapClient_InitiateRequest");
58 PKIX_NULLCHECK_TWO(client
, client
->initiateFcn
);
60 PKIX_CHECK(client
->initiateFcn
61 (client
, requestParams
, pNBIO
, pResponse
, plContext
),
62 PKIX_LDAPCLIENTINITIATEREQUESTFAILED
);
65 PKIX_RETURN(LDAPCLIENT
);
70 PKIX_PL_LdapClient_ResumeRequest(
71 PKIX_PL_LdapClient
*client
,
73 PKIX_List
**pResponse
,
76 PKIX_ENTER(LDAPCLIENT
, "PKIX_PL_LdapClient_ResumeRequest");
77 PKIX_NULLCHECK_TWO(client
, client
->resumeFcn
);
79 PKIX_CHECK(client
->resumeFcn
80 (client
, pNBIO
, pResponse
, plContext
),
81 PKIX_LDAPCLIENTRESUMEREQUESTFAILED
);
84 PKIX_RETURN(LDAPCLIENT
);
88 /* --Private-AIAMgr-Functions----------------------------------*/
91 * FUNCTION: pkix_pl_AIAMgr_Destroy
92 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
95 pkix_pl_AIAMgr_Destroy(
96 PKIX_PL_Object
*object
,
99 PKIX_PL_AIAMgr
*aiaMgr
= NULL
;
101 PKIX_ENTER(AIAMGR
, "pkix_pl_AIAMgr_Destroy");
102 PKIX_NULLCHECK_ONE(object
);
104 PKIX_CHECK(pkix_CheckType(object
, PKIX_AIAMGR_TYPE
, plContext
),
105 PKIX_OBJECTNOTAIAMGR
);
107 aiaMgr
= (PKIX_PL_AIAMgr
*)object
;
109 /* pointer to cert cache */
110 /* pointer to crl cache */
112 aiaMgr
->aiaIndex
= 0;
114 PKIX_DECREF(aiaMgr
->aia
);
115 PKIX_DECREF(aiaMgr
->location
);
116 PKIX_DECREF(aiaMgr
->results
);
117 PKIX_DECREF(aiaMgr
->client
.ldapClient
);
125 * FUNCTION: pkix_pl_AIAMgr_RegisterSelf
127 * Registers PKIX_AIAMGR_TYPE and its related functions with systemClasses[]
129 * Not Thread Safe - for performance and complexity reasons
131 * Since this function is only called by PKIX_PL_Initialize, which should
132 * only be called once, it is acceptable that this function is not
136 pkix_pl_AIAMgr_RegisterSelf(void *plContext
)
138 extern pkix_ClassTable_Entry systemClasses
[PKIX_NUMTYPES
];
139 pkix_ClassTable_Entry entry
;
142 "pkix_pl_AIAMgr_RegisterSelf");
144 entry
.description
= "AIAMgr";
145 entry
.objCounter
= 0;
146 entry
.typeObjectSize
= sizeof(PKIX_PL_AIAMgr
);
147 entry
.destructor
= pkix_pl_AIAMgr_Destroy
;
148 entry
.equalsFunction
= NULL
;
149 entry
.hashcodeFunction
= NULL
;
150 entry
.toStringFunction
= NULL
;
151 entry
.comparator
= NULL
;
152 entry
.duplicateFunction
= NULL
;
154 systemClasses
[PKIX_AIAMGR_TYPE
] = entry
;
160 * FUNCTION: pkix_pl_AiaMgr_FindLDAPClient
163 * This function checks the collection of LDAPClient connections held by the
164 * AIAMgr pointed to by "aiaMgr" for one matching the domain name given by
165 * "domainName". The string may include a port number: e.g., "betty.nist.gov"
166 * or "nss.red.iplanet.com:1389". If a match is found, that LDAPClient is
167 * stored at "pClient". Otherwise, an LDAPClient is created and added to the
168 * collection, and then stored at "pClient".
172 * The AIAMgr whose LDAPClient connected are to be managed. Must be
175 * Address of a string pointing to a server name. Must be non-NULL.
177 * Address at which the returned LDAPClient is stored. Must be non-NULL.
179 * Platform-specific context pointer.
181 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
183 * Returns NULL if the function succeeds.
184 * Returns an AIAMgr Error if the function fails in a non-fatal way
185 * Returns a Fatal Error if the function fails in an unrecoverable way.
188 pkix_pl_AiaMgr_FindLDAPClient(
189 PKIX_PL_AIAMgr
*aiaMgr
,
191 PKIX_PL_LdapClient
**pClient
,
194 PKIX_PL_String
*domainString
= NULL
;
195 PKIX_PL_LdapDefaultClient
*client
= NULL
;
197 PKIX_ENTER(AIAMGR
, "pkix_pl_AiaMgr_FindLDAPClient");
198 PKIX_NULLCHECK_THREE(aiaMgr
, domainName
, pClient
);
200 /* create PKIX_PL_String from domain name */
201 PKIX_CHECK(PKIX_PL_String_Create
202 (PKIX_ESCASCII
, domainName
, 0, &domainString
, plContext
),
203 PKIX_STRINGCREATEFAILED
);
205 /* Is this domainName already in cache? */
206 PKIX_CHECK(PKIX_PL_HashTable_Lookup
208 (PKIX_PL_Object
*)domainString
,
209 (PKIX_PL_Object
**)&client
,
211 PKIX_HASHTABLELOOKUPFAILED
);
213 if (client
== NULL
) {
215 /* No, create a connection (and cache it) */
216 PKIX_CHECK(PKIX_PL_LdapDefaultClient_CreateByName
218 /* Do not use NBIO until we verify, that
220 PR_INTERVAL_NO_TIMEOUT
, /* PR_INTERVAL_NO_WAIT, */
224 PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED
);
226 PKIX_CHECK(PKIX_PL_HashTable_Add
228 (PKIX_PL_Object
*)domainString
,
229 (PKIX_PL_Object
*)client
,
231 PKIX_HASHTABLEADDFAILED
);
235 *pClient
= (PKIX_PL_LdapClient
*)client
;
239 PKIX_DECREF(domainString
);
245 pkix_pl_AIAMgr_GetHTTPCerts(
246 PKIX_PL_AIAMgr
*aiaMgr
,
247 PKIX_PL_InfoAccess
*ia
,
252 PKIX_PL_GeneralName
*location
= NULL
;
253 PKIX_PL_String
*locationString
= NULL
;
256 const SEC_HttpClientFcn
*httpClient
= NULL
;
257 const SEC_HttpClientFcnV1
*hcv1
= NULL
;
258 SECStatus rv
= SECFailure
;
259 SEC_HTTP_SERVER_SESSION serverSession
= NULL
;
260 SEC_HTTP_REQUEST_SESSION requestSession
= NULL
;
262 char *hostname
= NULL
;
263 char *locationAscii
= NULL
;
265 PRUint16 responseCode
= 0;
266 const char *responseContentType
= NULL
;
267 const char *responseData
= NULL
;
268 PRUint32 responseDataLen
= 0;
270 PKIX_ENTER(AIAMGR
, "pkix_pl_AIAMgr_GetHTTPCerts");
271 PKIX_NULLCHECK_FOUR(aiaMgr
, ia
, pNBIOContext
, pCerts
);
273 nbio
= *pNBIOContext
;
274 *pNBIOContext
= NULL
;
277 if (nbio
== NULL
) { /* a new request */
279 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
280 (ia
, &location
, plContext
),
281 PKIX_INFOACCESSGETLOCATIONFAILED
);
283 /* find or create httpClient = default client */
284 httpClient
= SEC_GetRegisteredHttpClient();
285 aiaMgr
->client
.hdata
.httpClient
= httpClient
;
287 if (httpClient
->version
== 1) {
289 hcv1
= &(httpClient
->fcnTable
.ftable1
);
291 /* create server session */
292 PKIX_TOSTRING(location
, &locationString
, plContext
,
293 PKIX_GENERALNAMETOSTRINGFAILED
);
295 PKIX_CHECK(PKIX_PL_String_GetEncoded
298 (void **)&locationAscii
,
301 PKIX_STRINGGETENCODEDFAILED
);
304 (AIAMGR
, rv
, CERT_ParseURL
,
305 (locationAscii
, &hostname
, &port
, &path
));
307 if ((rv
!= SECSuccess
) ||
308 (hostname
== NULL
) ||
310 PKIX_ERROR(PKIX_URLPARSINGFAILED
);
314 (AIAMGR
, rv
, hcv1
->createSessionFcn
,
315 (hostname
, port
, &serverSession
));
317 if (rv
!= SECSuccess
) {
318 PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED
);
321 aiaMgr
->client
.hdata
.serverSession
= serverSession
;
323 /* create request session */
325 (AIAMGR
, rv
, hcv1
->createFcn
,
330 PR_TicksPerSecond() * 60,
333 if (rv
!= SECSuccess
) {
337 PKIX_ERROR(PKIX_HTTPSERVERERROR
);
340 aiaMgr
->client
.hdata
.requestSession
= requestSession
;
342 PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT
);
346 httpClient
= aiaMgr
->client
.hdata
.httpClient
;
348 if (httpClient
->version
== 1) {
350 hcv1
= &(httpClient
->fcnTable
.ftable1
);
351 requestSession
= aiaMgr
->client
.hdata
.requestSession
;
353 /* trySendAndReceive */
355 (AIAMGR
, rv
, hcv1
->trySendAndReceiveFcn
,
357 (PRPollDesc
**)&nbio
,
359 (const char **)&responseContentType
,
360 NULL
, /* &responseHeaders */
361 (const char **)&responseData
,
364 if (rv
!= SECSuccess
) {
365 PKIX_ERROR(PKIX_HTTPSERVERERROR
);
369 *pNBIOContext
= nbio
;
373 PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
380 PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED
);
382 /* Session and request cleanup in case of success */
383 if (aiaMgr
->client
.hdata
.requestSession
!= NULL
) {
384 (*hcv1
->freeFcn
)(aiaMgr
->client
.hdata
.requestSession
);
385 aiaMgr
->client
.hdata
.requestSession
= NULL
;
387 if (aiaMgr
->client
.hdata
.serverSession
!= NULL
) {
388 (*hcv1
->freeSessionFcn
)(aiaMgr
->client
.hdata
.serverSession
);
389 aiaMgr
->client
.hdata
.serverSession
= NULL
;
391 aiaMgr
->client
.hdata
.httpClient
= 0; /* callback fn */
394 PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT
);
398 /* Session and request cleanup in case of error. Passing through without cleanup
399 * if interrupted by blocked IO. */
400 if (PKIX_ERROR_RECEIVED
&& aiaMgr
) {
401 if (aiaMgr
->client
.hdata
.requestSession
!= NULL
) {
402 (*hcv1
->freeFcn
)(aiaMgr
->client
.hdata
.requestSession
);
403 aiaMgr
->client
.hdata
.requestSession
= NULL
;
405 if (aiaMgr
->client
.hdata
.serverSession
!= NULL
) {
406 (*hcv1
->freeSessionFcn
)(aiaMgr
->client
.hdata
.serverSession
);
407 aiaMgr
->client
.hdata
.serverSession
= NULL
;
409 aiaMgr
->client
.hdata
.httpClient
= 0; /* callback fn */
412 PKIX_DECREF(location
);
413 PKIX_DECREF(locationString
);
416 PORT_Free(locationAscii
);
423 pkix_pl_AIAMgr_GetLDAPCerts(
424 PKIX_PL_AIAMgr
*aiaMgr
,
425 PKIX_PL_InfoAccess
*ia
,
430 PKIX_List
*result
= NULL
;
431 PKIX_PL_GeneralName
*location
= NULL
;
432 PKIX_PL_LdapClient
*client
= NULL
;
433 LDAPRequestParams request
;
434 PRArenaPool
*arena
= NULL
;
435 char *domainName
= NULL
;
438 PKIX_ENTER(AIAMGR
, "pkix_pl_AIAMgr_GetLDAPCerts");
439 PKIX_NULLCHECK_FOUR(aiaMgr
, ia
, pNBIOContext
, pCerts
);
441 nbio
= *pNBIOContext
;
442 *pNBIOContext
= NULL
;
445 if (nbio
== NULL
) { /* a new request */
447 /* Initiate an LDAP request */
449 request
.scope
= WHOLE_SUBTREE
;
450 request
.derefAliases
= NEVER_DEREF
;
451 request
.sizeLimit
= 0;
452 request
.timeLimit
= 0;
454 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
455 (ia
, &location
, plContext
),
456 PKIX_INFOACCESSGETLOCATIONFAILED
);
459 * Get a short-lived arena. We'll be done with
460 * this space once the request is encoded.
462 PKIX_PL_NSSCALLRV(AIAMGR
, arena
, PORT_NewArena
,
463 (DER_DEFAULT_CHUNKSIZE
));
466 PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY
);
469 PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation
470 (location
, arena
, &request
, &domainName
, plContext
),
471 PKIX_INFOACCESSPARSELOCATIONFAILED
);
473 PKIX_DECREF(location
);
475 /* Find or create a connection to LDAP server */
476 PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient
477 (aiaMgr
, domainName
, &client
, plContext
),
478 PKIX_AIAMGRFINDLDAPCLIENTFAILED
);
480 aiaMgr
->client
.ldapClient
= client
;
482 PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
483 (aiaMgr
->client
.ldapClient
,
488 PKIX_LDAPCLIENTINITIATEREQUESTFAILED
);
490 PKIX_PL_NSSCALL(AIAMGR
, PORT_FreeArena
, (arena
, PR_FALSE
));
494 PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
495 (aiaMgr
->client
.ldapClient
, &nbio
, &result
, plContext
),
496 PKIX_LDAPCLIENTRESUMEREQUESTFAILED
);
500 if (nbio
!= NULL
) { /* WOULDBLOCK */
501 *pNBIOContext
= nbio
;
506 PKIX_DECREF(aiaMgr
->client
.ldapClient
);
508 if (result
== NULL
) {
511 PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
512 (result
, pCerts
, plContext
),
513 PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED
);
516 *pNBIOContext
= nbio
;
520 if (arena
&& (PKIX_ERROR_RECEIVED
)) {
521 PKIX_PL_NSSCALL(AIAMGR
, PORT_FreeArena
, (arena
, PR_FALSE
));
524 if (PKIX_ERROR_RECEIVED
) {
525 PKIX_DECREF(aiaMgr
->client
.ldapClient
);
528 PKIX_DECREF(location
);
534 * FUNCTION: PKIX_PL_AIAMgr_Create
537 * This function creates an AIAMgr, storing the result at "pAIAMgr".
541 * Address at which the returned AIAMgr is stored. Must be non-NULL.
543 * Platform-specific context pointer.
545 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
547 * Returns NULL if the function succeeds.
548 * Returns an AIAMgr Error if the function fails in a non-fatal way
549 * Returns a Fatal Error if the function fails in an unrecoverable way.
552 PKIX_PL_AIAMgr_Create(
553 PKIX_PL_AIAMgr
**pAIAMgr
,
556 PKIX_PL_AIAMgr
*aiaMgr
= NULL
;
558 PKIX_ENTER(AIAMGR
, "PKIX_PL_AIAMgr_Create");
559 PKIX_NULLCHECK_ONE(pAIAMgr
);
561 PKIX_CHECK(PKIX_PL_Object_Alloc
563 sizeof(PKIX_PL_AIAMgr
),
564 (PKIX_PL_Object
**)&aiaMgr
,
566 PKIX_COULDNOTCREATEAIAMGROBJECT
);
567 /* pointer to cert cache */
568 /* pointer to crl cache */
570 aiaMgr
->aiaIndex
= 0;
573 aiaMgr
->location
= NULL
;
574 aiaMgr
->results
= NULL
;
575 aiaMgr
->client
.hdata
.httpClient
= NULL
;
576 aiaMgr
->client
.hdata
.serverSession
= NULL
;
577 aiaMgr
->client
.hdata
.requestSession
= NULL
;
586 /* --Public-Functions------------------------------------------------------- */
589 * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h)
592 PKIX_PL_AIAMgr_GetAIACerts(
593 PKIX_PL_AIAMgr
*aiaMgr
,
594 PKIX_PL_Cert
*prevCert
,
599 PKIX_UInt32 numAias
= 0;
600 PKIX_UInt32 aiaIndex
= 0;
601 PKIX_UInt32 iaType
= PKIX_INFOACCESS_LOCATION_UNKNOWN
;
602 PKIX_List
*certs
= NULL
;
603 PKIX_PL_InfoAccess
*ia
= NULL
;
606 PKIX_ENTER(AIAMGR
, "PKIX_PL_AIAMgr_GetAIACerts");
607 PKIX_NULLCHECK_FOUR(aiaMgr
, prevCert
, pNBIOContext
, pCerts
);
609 nbio
= *pNBIOContext
;
611 *pNBIOContext
= NULL
;
613 if (nbio
== NULL
) { /* a new request */
615 /* Does this Cert have an AIA extension? */
616 PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
617 (prevCert
, &aiaMgr
->aia
, plContext
),
618 PKIX_CERTGETAUTHORITYINFOACCESSFAILED
);
620 if (aiaMgr
->aia
!= NULL
) {
621 PKIX_CHECK(PKIX_List_GetLength
622 (aiaMgr
->aia
, &numAias
, plContext
),
623 PKIX_LISTGETLENGTHFAILED
);
626 /* And if so, does it have any entries? */
627 if ((aiaMgr
->aia
== NULL
) || (numAias
== 0)) {
632 aiaMgr
->aiaIndex
= 0;
633 aiaMgr
->numAias
= numAias
;
634 aiaMgr
->results
= NULL
;
638 for (aiaIndex
= aiaMgr
->aiaIndex
;
639 aiaIndex
< aiaMgr
->numAias
;
641 PKIX_UInt32 method
= 0;
643 PKIX_CHECK(PKIX_List_GetItem
646 (PKIX_PL_Object
**)&ia
,
648 PKIX_LISTGETITEMFAILED
);
650 PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod
651 (ia
, &method
, plContext
),
652 PKIX_INFOACCESSGETMETHODFAILED
);
654 if (method
!= PKIX_INFOACCESS_CA_ISSUERS
&&
655 method
!= PKIX_INFOACCESS_CA_REPOSITORY
) {
660 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType
661 (ia
, &iaType
, plContext
),
662 PKIX_INFOACCESSGETLOCATIONTYPEFAILED
);
664 if (iaType
== PKIX_INFOACCESS_LOCATION_HTTP
) {
665 PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts
666 (aiaMgr
, ia
, &nbio
, &certs
, plContext
),
667 PKIX_AIAMGRGETHTTPCERTSFAILED
);
668 } else if (iaType
== PKIX_INFOACCESS_LOCATION_LDAP
) {
669 PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts
670 (aiaMgr
, ia
, &nbio
, &certs
, plContext
),
671 PKIX_AIAMGRGETLDAPCERTSFAILED
);
673 /* We only support http and ldap requests. */
674 PKIX_ERROR(PKIX_UNKNOWNINFOACCESSTYPE
);
677 if (nbio
!= NULL
) { /* WOULDBLOCK */
678 aiaMgr
->aiaIndex
= aiaIndex
;
679 *pNBIOContext
= nbio
;
685 * We can't just use and modify the List we received.
686 * Because it's cached, it's set immutable.
688 if (aiaMgr
->results
== NULL
) {
689 PKIX_CHECK(PKIX_List_Create
690 (&(aiaMgr
->results
), plContext
),
691 PKIX_LISTCREATEFAILED
);
693 PKIX_CHECK(pkix_List_AppendList
694 (aiaMgr
->results
, certs
, plContext
),
695 PKIX_APPENDLISTFAILED
);
701 PKIX_DECREF(aiaMgr
->aia
);
703 *pNBIOContext
= NULL
;
704 *pCerts
= aiaMgr
->results
;
705 aiaMgr
->results
= NULL
;
709 if (PKIX_ERROR_RECEIVED
) {
710 PKIX_DECREF(aiaMgr
->aia
);
711 PKIX_DECREF(aiaMgr
->results
);
712 PKIX_DECREF(aiaMgr
->client
.ldapClient
);