Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / lib / libpkix / pkix_pl_nss / module / pkix_pl_pk11certstore.c
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
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/
8  *
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
12  * License.
13  *
14  * The Original Code is the PKIX-C library.
15  *
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.
20  *
21  * Contributor(s):
22  *   Sun Microsystems, Inc.
23  *
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.
35  *
36  * ***** END LICENSE BLOCK ***** */
37 /*
38  * pkix_pl_pk11certstore.c
39  *
40  * PKCS11CertStore Function Definitions
41  *
42  */
43
44 #include "pkix_pl_pk11certstore.h"
45
46 /*
47  * PKIX_DEFAULT_MAX_RESPONSE_LENGTH (64 * 1024) is too small for downloading
48  * CRLs.  We observed CRLs of sizes 338759 and 439035 in practice.  So we
49  * need to use a higher max response length for CRLs.
50  */
51 #define PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH (512 * 1024)
52
53 /* --Private-Pk11CertStore-Functions---------------------------------- */
54
55 /*
56  * FUNCTION: pkix_pl_Pk11CertStore_CheckTrust
57  * DESCRIPTION:
58  * This function checks the trust status of this "cert" that was retrieved
59  * from the CertStore "store" and returns its trust status at "pTrusted".
60  *
61  * PARAMETERS:
62  * "store"
63  *      Address of the CertStore. Must be non-NULL.
64  * "cert"
65  *      Address of the Cert. Must be non-NULL.
66  * "pTrusted"
67  *      Address of PKIX_Boolean where the "cert" trust status is returned.
68  *      Must be non-NULL.
69  * "plContext"
70  *      Platform-specific context pointer
71  * THREAD SAFETY:
72  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
73  * RETURNS:
74  *  Returns NULL if the function succeeds.
75  *  Returns a CertStore Error if the function fails in a non-fatal way.
76  *  Returns a Fatal Error if the function fails in an unrecoverable way.
77  */
78 static PKIX_Error *
79 pkix_pl_Pk11CertStore_CheckTrust(
80         PKIX_CertStore *store,
81         PKIX_PL_Cert *cert,
82         PKIX_Boolean *pTrusted,
83         void *plContext)
84 {
85         SECStatus rv = SECFailure;
86         PKIX_Boolean trusted = PKIX_FALSE;
87         SECCertUsage certUsage = 0;
88         SECCertificateUsage certificateUsage;
89         unsigned int requiredFlags;
90         SECTrustType trustType;
91         CERTCertTrust trust;
92
93         PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckTrust");
94         PKIX_NULLCHECK_THREE(store, cert, pTrusted);
95         PKIX_NULLCHECK_ONE(cert->nssCert);
96
97         certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
98
99         /* ensure we obtained a single usage bit only */
100         PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
101
102         /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
103         while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
104
105         rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType);
106         if (rv == SECSuccess) {
107                 rv = CERT_GetCertTrust(cert->nssCert, &trust);
108         }
109
110         if (rv == SECSuccess) {
111             unsigned int certFlags;
112
113             if (certUsage != certUsageAnyCA &&
114                 certUsage != certUsageStatusResponder) {
115                 CERTCertificate *nssCert = cert->nssCert;
116                 
117                 if (certUsage == certUsageVerifyCA) {
118                     if (nssCert->nsCertType & NS_CERT_TYPE_EMAIL_CA) {
119                         trustType = trustEmail;
120                     } else if (nssCert->nsCertType & NS_CERT_TYPE_SSL_CA) {
121                         trustType = trustSSL;
122                     } else {
123                         trustType = trustObjectSigning;
124                     }
125                 }
126                 
127                 certFlags = SEC_GET_TRUST_FLAGS((&trust), trustType);
128                 if ((certFlags & requiredFlags) == requiredFlags) {
129                     trusted = PKIX_TRUE;
130                 }
131             } else {
132                 for (trustType = trustSSL; trustType < trustTypeNone;
133                      trustType++) {
134                     certFlags =
135                         SEC_GET_TRUST_FLAGS((&trust), trustType);
136                     if ((certFlags & requiredFlags) == requiredFlags) {
137                         trusted = PKIX_TRUE;
138                         break;
139                     }
140                 }
141             }
142         }
143
144         *pTrusted = trusted;
145
146         PKIX_RETURN(CERTSTORE);
147 }
148
149 /*
150  * FUNCTION: pkix_pl_Pk11CertStore_CertQuery
151  * DESCRIPTION:
152  *
153  *  This function obtains from the database the Certs specified by the
154  *  ComCertSelParams pointed to by "params" and stores the resulting
155  *  List at "pSelected". If no matching Certs are found, a NULL pointer
156  *  will be stored.
157  *
158  *  This function uses a "smart" database query if the Subject has been set
159  *  in ComCertSelParams. Otherwise, it uses a very inefficient call to
160  *  retrieve all Certs in the database (and run them through the selector).
161  *
162  * PARAMETERS:
163  * "params"
164  *      Address of the ComCertSelParams. Must be non-NULL.
165  * "pSelected"
166  *      Address at which List will be stored. Must be non-NULL.
167  * "plContext"
168  *      Platform-specific context pointer
169  * THREAD SAFETY:
170  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
171  * RETURNS:
172  *  Returns NULL if the function succeeds.
173  *  Returns a CertStore Error if the function fails in a non-fatal way.
174  *  Returns a Fatal Error if the function fails in an unrecoverable way.
175  */
176 static PKIX_Error *
177 pkix_pl_Pk11CertStore_CertQuery(
178         PKIX_ComCertSelParams *params,
179         PKIX_List **pSelected,
180         void *plContext)
181 {
182         PRBool validOnly = PR_FALSE;
183         PRTime prtime = 0;
184         PKIX_PL_X500Name *subjectName = NULL;
185         PKIX_PL_Date *certValid = NULL;
186         PKIX_List *certList = NULL;
187         PKIX_PL_Cert *cert = NULL;
188         CERTCertList *pk11CertList = NULL;
189         CERTCertListNode *node = NULL;
190         CERTCertificate *nssCert = NULL;
191         CERTCertDBHandle *dbHandle = NULL;
192
193         PRArenaPool *arena = NULL;
194         SECItem *nameItem = NULL;
195         void *wincx = NULL;
196
197         PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CertQuery");
198         PKIX_NULLCHECK_TWO(params, pSelected);
199
200         /* avoid multiple calls to retrieve a constant */
201         PKIX_PL_NSSCALLRV(CERTSTORE, dbHandle, CERT_GetDefaultCertDB, ());
202
203         /*
204          * Any of the ComCertSelParams may be obtained and used to constrain
205          * the database query, to allow the use of a "smart" query. See
206          * pkix_certsel.h for a list of the PKIX_ComCertSelParams_Get*
207          * calls available. No corresponding "smart" queries exist at present,
208          * except for CERT_CreateSubjectCertList based on Subject. When others
209          * are added, corresponding code should be added to
210          * pkix_pl_Pk11CertStore_CertQuery to use them when appropriate
211          * selector parameters have been set.
212          */
213
214         PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
215                 (params, &subjectName, plContext),
216                 PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
217
218         PKIX_CHECK(PKIX_ComCertSelParams_GetCertificateValid
219                 (params, &certValid, plContext),
220                 PKIX_COMCERTSELPARAMSGETCERTIFICATEVALIDFAILED);
221
222         /* If caller specified a Date, convert it to PRTime */
223         if (certValid) {
224                 PKIX_CHECK(pkix_pl_Date_GetPRTime
225                         (certValid, &prtime, plContext),
226                         PKIX_DATEGETPRTIMEFAILED);
227                 validOnly = PR_TRUE;
228         }
229
230         /*
231          * If we have the subject name for the desired subject,
232          * ask the database for Certs with that subject. Otherwise
233          * ask the database for all Certs.
234          */
235         if (subjectName) {
236                 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
237                 if (arena) {
238
239                         PKIX_CHECK(pkix_pl_X500Name_GetDERName
240                                 (subjectName, arena, &nameItem, plContext),
241                                 PKIX_X500NAMEGETSECNAMEFAILED);
242
243                         if (nameItem) {
244
245                             PKIX_PL_NSSCALLRV
246                                 (CERTSTORE,
247                                 pk11CertList,
248                                 CERT_CreateSubjectCertList,
249                                 (NULL, dbHandle, nameItem, prtime, validOnly));
250                         }
251                         PKIX_PL_NSSCALL
252                                 (CERTSTORE, PORT_FreeArena, (arena, PR_FALSE));
253                         arena = NULL;
254                 }
255
256         } else {
257
258                 PKIX_CHECK(pkix_pl_NssContext_GetWincx
259                         ((PKIX_PL_NssContext *)plContext, &wincx),
260                         PKIX_NSSCONTEXTGETWINCXFAILED);
261
262                 PKIX_PL_NSSCALLRV
263                         (CERTSTORE,
264                         pk11CertList,
265                         PK11_ListCerts,
266                         (PK11CertListAll, wincx));
267         }
268
269         if (pk11CertList) {
270
271                 PKIX_CHECK(PKIX_List_Create(&certList, plContext),
272                         PKIX_LISTCREATEFAILED);
273
274                 for (node = CERT_LIST_HEAD(pk11CertList);
275                     !(CERT_LIST_END(node, pk11CertList));
276                     node = CERT_LIST_NEXT(node)) {
277
278                         PKIX_PL_NSSCALLRV
279                                 (CERTSTORE,
280                                 nssCert,
281                                 CERT_NewTempCertificate,
282                                         (dbHandle,
283                                         &(node->cert->derCert),
284                                         NULL, /* nickname */
285                                         PR_FALSE,
286                                         PR_TRUE)); /* copyDER */
287
288                         if (!nssCert) {
289                                 continue; /* just skip bad certs */
290                         }
291
292                         PKIX_CHECK_ONLY_FATAL(pkix_pl_Cert_CreateWithNSSCert
293                                 (nssCert, &cert, plContext),
294                                 PKIX_CERTCREATEWITHNSSCERTFAILED);
295
296                         if (PKIX_ERROR_RECEIVED) {
297                                 CERT_DestroyCertificate(nssCert);
298                                 nssCert = NULL;
299                                 continue; /* just skip bad certs */
300                         }
301
302                         PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
303                                 (certList, (PKIX_PL_Object *)cert, plContext),
304                                 PKIX_LISTAPPENDITEMFAILED);
305
306                         PKIX_DECREF(cert);
307
308                 }
309
310                 /* Don't throw away the list if one cert was bad! */
311                 pkixTempErrorReceived = PKIX_FALSE;
312         }
313
314         *pSelected = certList;
315         certList = NULL;
316
317 cleanup:
318         
319         if (pk11CertList) {
320             CERT_DestroyCertList(pk11CertList);
321         }
322         if (arena) {
323             PORT_FreeArena(arena, PR_FALSE);
324         }
325
326         PKIX_DECREF(subjectName);
327         PKIX_DECREF(certValid);
328         PKIX_DECREF(cert);
329         PKIX_DECREF(certList);
330
331         PKIX_RETURN(CERTSTORE);
332 }
333
334 /*
335  * FUNCTION: pkix_pl_Pk11CertStore_ImportCrl
336  * DESCRIPTION:
337  *
338  * PARAMETERS:
339  * "params"
340  *      Address of the ComCRLSelParams. Must be non-NULL.
341  * "pSelected"
342  *      Address at which List will be stored. Must be non-NULL.
343  * "plContext"
344  *      Platform-specific context pointer
345  * THREAD SAFETY:
346  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
347  * RETURNS:
348  *  Returns NULL if the function succeeds.
349  *  Returns a CertStore Error if the function fails in a non-fatal way.
350  *  Returns a Fatal Error if the function fails in an unrecoverable way.
351  */
352 static PKIX_Error *
353 pkix_pl_Pk11CertStore_ImportCrl(
354         PKIX_CertStore *store,
355         PKIX_PL_X500Name *issuerName,
356         PKIX_List *crlList,
357         void *plContext)
358 {
359     CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
360     PKIX_PL_CRL *crl = NULL;
361     SECItem *derCrl = NULL;
362
363     PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ImportCrl");
364     PKIX_NULLCHECK_TWO(store, plContext);
365     
366     if (!crlList) {
367         goto cleanup;
368     }
369     while (crlList->length > 0) {
370         PKIX_CHECK(
371             PKIX_List_GetItem(crlList, 0, (PKIX_PL_Object**)&crl,
372                               plContext),
373             PKIX_LISTGETITEMFAILED);
374
375         /* Delete crl from the list to keep controll of the
376          * last reference. crl need to be destroyed right after
377          * it released the ownership of the crl der. */
378         PKIX_CHECK(
379             PKIX_List_DeleteItem(crlList, 0, plContext),
380             PKIX_LISTDELETEITEMFAILED);
381
382         /* acquire the crlder ownership */
383         pkixErrorResult =
384             PKIX_PL_CRL_ReleaseDerCrl(crl, &derCrl, plContext);
385         PORT_Assert(!pkixErrorResult && derCrl);
386         if (pkixErrorResult || !derCrl) {
387             /* All pkix delivered crls should be able to
388              * release their ders. */
389             PKIX_DECREF(pkixErrorResult);
390             PKIX_DECREF(crl);
391             continue;
392         }
393         cert_CacheCRLByGeneralName(certHandle, derCrl, 
394                                         crl->derGenName);
395         /* Do not check the status. If it is a SECFailure,
396          * derCrl is already destroyed. */
397         derCrl = NULL;
398         PKIX_DECREF(crl);
399     }
400
401 cleanup:
402     PKIX_DECREF(crl);
403
404     PKIX_RETURN(CERTSTORE);
405 }
406
407 static PKIX_Error *
408 NameCacheHasFetchedCrlInfo(PKIX_PL_Cert *pkixCert,
409                            PRTime time,
410                            PKIX_Boolean *pHasFetchedCrlInCache,
411                            void *plContext)
412 {
413     /* Returning true result in this case will mean, that case info
414      * is currect and should used as is. */
415     NamedCRLCache* nameCrlCache = NULL;
416     PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
417     PKIX_List *dpList = NULL;
418     pkix_pl_CrlDp *dp = NULL;
419     CERTCertificate *cert;
420     PKIX_UInt32 dpIndex = 0;
421     SECStatus rv = SECSuccess;
422     PRTime reloadDelay = 0, badCrlInvalDelay = 0;
423
424     PKIX_ENTER(CERTSTORE, "ChechCacheHasFetchedCrl");
425
426     cert = pkixCert->nssCert;
427     reloadDelay = 
428         ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
429                                                 PR_USEC_PER_SEC;
430     badCrlInvalDelay =
431         ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
432                                                 PR_USEC_PER_SEC;
433     if (!time) {
434         time = PR_Now();
435     }
436     /* If we already download the crl and inserted into the cache, then
437      * there is no need to check for fetched crl. We have what we have. */
438     PKIX_CHECK(
439         PKIX_PL_Cert_GetCrlDp(pkixCert, &dpList, plContext),
440         PKIX_CERTGETCRLDPFAILED);
441     if (dpList && dpList->length) {
442         hasFetchedCrlInCache = PKIX_FALSE;
443         rv = cert_AcquireNamedCRLCache(&nameCrlCache);
444         if (rv != SECSuccess) {
445             PKIX_DECREF(dpList);
446         }
447     } else {
448         /* If no dp then treat it as if we already have
449          * a fetched crl. */
450         PKIX_DECREF(dpList);
451     }
452     for (;!hasFetchedCrlInCache &&
453              dpList && dpIndex < dpList->length;dpIndex++) {
454         SECItem **derDpNames = NULL;
455         pkixErrorResult =
456             PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
457                               plContext);
458         if (pkixErrorResult) {
459             PKIX_DECREF(pkixErrorResult);
460             continue;
461         }
462         if (dp->nssdp->distPointType == generalName) {
463             /* dp can only be created from nssdp. */
464             derDpNames = dp->nssdp->derFullName;
465         }
466         while (derDpNames && *derDpNames != NULL) {
467             NamedCRLCacheEntry* cacheEntry = NULL;
468             const SECItem *derDpName = *derDpNames++;
469             rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
470                                            &cacheEntry);
471             if (rv == SECSuccess && cacheEntry) {
472                 if ((cacheEntry->inCRLCache &&
473                     (cacheEntry->successfulInsertionTime + reloadDelay > time ||
474                      (cacheEntry->dupe &&
475                       cacheEntry->lastAttemptTime + reloadDelay > time))) ||
476                     (cacheEntry->badDER &&
477                      cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
478                     hasFetchedCrlInCache = PKIX_TRUE;
479                     break;
480                 }
481             }
482         }
483         PKIX_DECREF(dp);
484     }
485 cleanup:
486     *pHasFetchedCrlInCache = hasFetchedCrlInCache;
487     if (nameCrlCache) {
488         cert_ReleaseNamedCRLCache(nameCrlCache);
489     }
490     PKIX_DECREF(dpList);
491
492     PKIX_RETURN(CERTSTORE);
493 }
494
495 /*
496  * FUNCTION: pkix_pl_Pk11CertStore_CheckCrl
497  * DESCRIPTION:
498  *
499  * PARAMETERS:
500  * "params"
501  *      Address of the ComCRLSelParams. Must be non-NULL.
502  * "pSelected"
503  *      Address at which List will be stored. Must be non-NULL.
504  * "plContext"
505  *      Platform-specific context pointer
506  * THREAD SAFETY:
507  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
508  * RETURNS:
509  *  Returns NULL if the function succeeds.
510  *  Returns a CertStore Error if the function fails in a non-fatal way.
511  *  Returns a Fatal Error if the function fails in an unrecoverable way.
512  */
513 static PKIX_Error *
514 pkix_pl_Pk11CertStore_CheckRevByCrl(
515         PKIX_CertStore *store,
516         PKIX_PL_Cert *pkixCert,
517         PKIX_PL_Cert *pkixIssuer,
518         PKIX_PL_Date *date,
519         PKIX_Boolean  crlDownloadDone,
520         PKIX_UInt32  *pReasonCode,
521         PKIX_RevocationStatus *pStatus,
522         void *plContext)
523 {
524     PKIX_RevocationStatus pkixRevStatus = PKIX_RevStatus_NoInfo;
525     CERTRevocationStatus revStatus = certRevocationStatusUnknown;
526     PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
527     CERTCertificate *cert = NULL, *issuer = NULL;
528     SECStatus rv = SECSuccess;
529     void *wincx = NULL;
530     PRTime time = 0;
531
532     PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckRevByCrl");
533     PKIX_NULLCHECK_FOUR(store, pkixCert, pkixIssuer, plContext);
534
535     cert = pkixCert->nssCert;
536     issuer = pkixIssuer->nssCert;
537     if (date) {
538         PKIX_CHECK(
539             pkix_pl_Date_GetPRTime(date, &time, plContext),
540             PKIX_DATEGETPRTIMEFAILED);
541     }
542     PKIX_CHECK(
543         pkix_pl_NssContext_GetWincx((PKIX_PL_NssContext*)plContext,
544                                     &wincx),
545         PKIX_NSSCONTEXTGETWINCXFAILED);
546     /* No need to check any cDPs, since partitioned crls are not
547      * supported. If a ds does not point to partitioned crl, then
548      * the crl should be in issuer cache that is unrelated to any
549      * dp. Using NULL as a dp pointer to check it.*/
550     rv = cert_CheckCertRevocationStatus(cert, issuer, NULL,
551                                         /* Will not validate the signature
552                                          * on the crl if time is not specified.*/
553                                         time, wincx, &revStatus, pReasonCode);
554     if (rv == SECFailure) {
555         pkixRevStatus = PKIX_RevStatus_Revoked;
556         goto cleanup;
557     }
558     if (crlDownloadDone) {
559         if (revStatus == certRevocationStatusRevoked) {
560             pkixRevStatus = PKIX_RevStatus_Revoked;
561         } else if (revStatus == certRevocationStatusValid) {
562             pkixRevStatus = PKIX_RevStatus_Success;
563         } 
564     } else {
565         pkixErrorResult =
566             NameCacheHasFetchedCrlInfo(pkixCert, time, &hasFetchedCrlInCache,
567                                        plContext);
568         if (pkixErrorResult) {
569             goto cleanup;
570         }
571         if (revStatus == certRevocationStatusRevoked &&
572             (hasFetchedCrlInCache ||
573              *pReasonCode != crlEntryReasoncertificatedHold)) {
574             pkixRevStatus = PKIX_RevStatus_Revoked;
575         } else if (revStatus == certRevocationStatusValid &&
576                    hasFetchedCrlInCache) {
577             pkixRevStatus = PKIX_RevStatus_Success;
578         }
579     }
580 cleanup:
581     *pStatus = pkixRevStatus;
582
583     PKIX_RETURN(CERTSTORE);    
584 }
585
586
587 /*
588  * FUNCTION: pkix_pl_Pk11CertStore_GetCert
589  *  (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
590  */
591 PKIX_Error *
592 pkix_pl_Pk11CertStore_GetCert(
593         PKIX_CertStore *store,
594         PKIX_CertSelector *selector,
595         PKIX_VerifyNode *parentVerifyNode,
596         void **pNBIOContext,
597         PKIX_List **pCertList,
598         void *plContext)
599 {
600         PKIX_UInt32 i = 0;
601         PKIX_UInt32 numFound = 0;
602         PKIX_PL_Cert *candidate = NULL;
603         PKIX_List *selected = NULL;
604         PKIX_List *filtered = NULL;
605         PKIX_CertSelector_MatchCallback selectorCallback = NULL;
606         PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
607         PKIX_ComCertSelParams *params = NULL;
608         PKIX_Boolean cacheFlag = PKIX_FALSE;
609         PKIX_VerifyNode *verifyNode = NULL;
610         PKIX_Error *selectorError = NULL;
611
612         PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCert");
613         PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCertList);
614
615         *pNBIOContext = NULL;   /* We don't use non-blocking I/O */
616
617         PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
618                 (selector, &selectorCallback, plContext),
619                 PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
620
621         PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
622                 (selector, &params, plContext),
623                 PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED);
624
625         PKIX_CHECK(pkix_pl_Pk11CertStore_CertQuery
626                 (params, &selected, plContext),
627                 PKIX_PK11CERTSTORECERTQUERYFAILED);
628
629         if (selected) {
630                 PKIX_CHECK(PKIX_List_GetLength(selected, &numFound, plContext),
631                         PKIX_LISTGETLENGTHFAILED);
632         }
633
634         PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
635                 (store, &cacheFlag, plContext),
636                 PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
637
638         PKIX_CHECK(PKIX_CertStore_GetTrustCallback
639                 (store, &trustCallback, plContext),
640                 PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
641
642         PKIX_CHECK(PKIX_List_Create(&filtered, plContext),
643                 PKIX_LISTCREATEFAILED);
644
645         for (i = 0; i < numFound; i++) {
646                 PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
647                         (selected,
648                         i,
649                         (PKIX_PL_Object **)&candidate,
650                         plContext),
651                         PKIX_LISTGETITEMFAILED);
652
653                 if (PKIX_ERROR_RECEIVED) {
654                         continue; /* just skip bad certs */
655                 }
656
657                 selectorError =
658                     selectorCallback(selector, candidate, plContext);
659                 if (!selectorError) {
660                         PKIX_CHECK(PKIX_PL_Cert_SetCacheFlag
661                                 (candidate, cacheFlag, plContext),
662                                 PKIX_CERTSETCACHEFLAGFAILED);
663
664                         if (trustCallback) {
665                                 PKIX_CHECK(PKIX_PL_Cert_SetTrustCertStore
666                                     (candidate, store, plContext),
667                                     PKIX_CERTSETTRUSTCERTSTOREFAILED);
668                         }
669
670                         PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
671                                 (filtered,
672                                 (PKIX_PL_Object *)candidate,
673                                 plContext),
674                                 PKIX_LISTAPPENDITEMFAILED);
675                 } else if (parentVerifyNode) {
676                     PKIX_CHECK_FATAL(
677                         pkix_VerifyNode_Create(candidate, 0, selectorError,
678                                                &verifyNode, plContext),
679                         PKIX_VERIFYNODECREATEFAILED);
680                     PKIX_CHECK_FATAL(
681                         pkix_VerifyNode_AddToTree(parentVerifyNode,
682                                                   verifyNode,
683                                                   plContext),
684                         PKIX_VERIFYNODEADDTOTREEFAILED);
685                     PKIX_DECREF(verifyNode);
686                 }
687                 PKIX_DECREF(selectorError);
688                 PKIX_DECREF(candidate);
689         }
690
691         /* Don't throw away the list if one cert was bad! */
692         pkixTempErrorReceived = PKIX_FALSE;
693
694         *pCertList = filtered;
695         filtered = NULL;
696
697 cleanup:
698 fatal:
699         PKIX_DECREF(filtered);
700         PKIX_DECREF(candidate);
701         PKIX_DECREF(selected);
702         PKIX_DECREF(params);
703         PKIX_DECREF(verifyNode);
704         PKIX_DECREF(selectorError);
705
706         PKIX_RETURN(CERTSTORE);
707 }
708
709 static PKIX_Error *
710 RemovePartitionedDpsFromList(PKIX_List *dpList, PKIX_PL_Date *date,
711                              void *plContext)
712 {
713     NamedCRLCache* nameCrlCache = NULL;
714     pkix_pl_CrlDp *dp = NULL;
715     int dpIndex = 0;
716     PRTime time;
717     PRTime reloadDelay = 0, badCrlInvalDelay = 0;
718     SECStatus rv;
719
720     PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ListRemovePrtDp");
721
722     if (!dpList || !dpList->length) {
723         PKIX_RETURN(CERTSTORE);
724     }
725     reloadDelay = 
726         ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
727                                                 PR_USEC_PER_SEC;
728     badCrlInvalDelay =
729         ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
730                                                 PR_USEC_PER_SEC;
731     PKIX_CHECK(pkix_pl_Date_GetPRTime(date, &time, plContext),
732                PKIX_DATEGETPRTIMEFAILED);
733     rv = cert_AcquireNamedCRLCache(&nameCrlCache);
734     if (rv == SECFailure) {
735         /* Baling out. Wont find out any thing useful. */
736         PKIX_RETURN(CERTSTORE);
737     }
738     while (dpIndex < dpList->length) {
739         SECItem **derDpNames = NULL;
740         PKIX_Boolean removeDp = PKIX_FALSE;
741         
742         PKIX_CHECK(
743             PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
744                               plContext),
745             PKIX_LISTGETITEMFAILED);
746         if (!dp->isPartitionedByReasonCode) {
747             /* See if we know about this dp anything why we should
748              * not use it to download a crl. */
749             if (dp->nssdp->distPointType == generalName) {
750                 /* dp can only be created from nssdp. */
751                 derDpNames = dp->nssdp->derFullName;
752             } else {
753                 removeDp = PKIX_TRUE;
754             }
755             while (derDpNames && *derDpNames != NULL) {
756                 NamedCRLCacheEntry* cacheEntry = NULL;
757                 const SECItem *derDpName = *derDpNames++;
758                 /* Removing from the list all dps that we know about. */
759                 rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
760                                                &cacheEntry);
761                 if (rv && cacheEntry) {
762                     if (cacheEntry->unsupported ||
763                         (cacheEntry->inCRLCache &&
764                          (cacheEntry->successfulInsertionTime + reloadDelay > time ||
765                           (cacheEntry->dupe &&
766                            cacheEntry->lastAttemptTime + reloadDelay > time))) ||
767                           (cacheEntry->badDER &&
768                            cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
769                         removeDp = PKIX_TRUE;
770                     }
771                 }
772             }
773         } else {
774             /* Remove dp that point to a partitioned crl . RFC 5280
775              * recommends against crl partitioned by reason code.
776              * Will skip such crls */
777             removeDp = PKIX_TRUE;
778         }
779         if (removeDp) {
780             PKIX_CHECK_ONLY_FATAL(
781                 pkix_List_Remove(dpList,(PKIX_PL_Object*)dp,
782                                  plContext),
783                 PKIX_LISTGETITEMFAILED); 
784         } else {
785             dpIndex += 1;
786         }
787         PKIX_DECREF(dp);
788     }
789
790 cleanup:
791     if (nameCrlCache) {
792         cert_ReleaseNamedCRLCache(nameCrlCache);
793     }
794     PKIX_DECREF(dp);
795     
796     PKIX_RETURN(CERTSTORE);
797 }
798
799 /*
800  * FUNCTION: pkix_pl_Pk11CertStore_DownloadCrl
801  */
802 static PKIX_Error *
803 DownloadCrl(pkix_pl_CrlDp *dp, PKIX_PL_CRL **crl,
804             const SEC_HttpClientFcnV1 *hcv1, void *plContext)
805 {
806     char *location = NULL;
807     char *hostname = NULL;
808     char *path = NULL;
809     PRUint16 port;
810     SEC_HTTP_SERVER_SESSION pServerSession = NULL;
811     SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
812     PRUint16 myHttpResponseCode;
813     const char *myHttpResponseData = NULL;
814     PRUint32 myHttpResponseDataLen;
815     SECItem *uri = NULL;
816     SECItem *derCrlCopy = NULL;
817     CERTSignedCrl *nssCrl = NULL;
818     CERTGeneralName *genName = NULL;
819     PKIX_Int32 savedError = -1;
820     SECItem **derGenNames = NULL;
821     SECItem  *derGenName = NULL;
822
823     PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_DownloadCrl");
824
825     /* Do not support dps others than a one with GeneralName
826      * name type. */
827     if (dp->distPointType != generalName ||
828         !dp->nssdp->derFullName) {
829         PKIX_ERROR(PKIX_UNSUPPORTEDCRLDPTYPE);
830     }
831     genName = dp->name.fullName;
832     derGenNames = dp->nssdp->derFullName;
833     do {
834         derGenName = *derGenNames;
835         do {
836             if (!derGenName ||
837                 !genName->name.other.data) {
838                 /* get to next name if no data. */
839                 savedError = PKIX_UNSUPPORTEDCRLDPTYPE;
840                 break;
841             }
842             uri = &genName->name.other;
843             location = (char*)PR_Malloc(1 + uri->len);
844             if (!location) {
845                 savedError = PKIX_ALLOCERROR;
846                 break;
847             }
848             PORT_Memcpy(location, uri->data, uri->len);
849             location[uri->len] = 0;
850             if (CERT_ParseURL(location, &hostname,
851                               &port, &path) != SECSuccess) {
852                 PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
853                 savedError = PKIX_URLPARSINGFAILED;
854                 break;
855             }
856     
857             PORT_Assert(hostname != NULL);
858             PORT_Assert(path != NULL);
859
860             if ((*hcv1->createSessionFcn)(hostname, port, 
861                                           &pServerSession) != SECSuccess) {
862                 PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
863                 savedError = PKIX_URLPARSINGFAILED;
864                 break;
865             }
866
867             if ((*hcv1->createFcn)(pServerSession, "http", path, "GET",
868                 /* Users with slow connections might not get CRL revocation 
869                    checking for certs that use big CRLs because of the timeout
870                    We absolutely need code that limits our retry attempts.
871                  */
872                           PR_SecondsToInterval(
873                               ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
874                                    &pRequestSession) != SECSuccess) {
875                 savedError = PKIX_HTTPSERVERERROR;
876                 break;
877             }
878
879             myHttpResponseDataLen =
880                 ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
881             if (myHttpResponseDataLen < PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH)
882                 myHttpResponseDataLen = PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH;
883
884             /* We use a non-zero timeout, which means:
885                - the client will use blocking I/O
886                - TryFcn will not return WOULD_BLOCK nor a poll descriptor
887                - it's sufficient to call TryFcn once
888             */
889             /* we don't want result objects larger than this: */
890             if ((*hcv1->trySendAndReceiveFcn)(
891                     pRequestSession, 
892                     NULL,
893                     &myHttpResponseCode,
894                     NULL,
895                     NULL,
896                     &myHttpResponseData,
897                     &myHttpResponseDataLen) != SECSuccess) {
898                 savedError = PKIX_HTTPSERVERERROR;
899                 break;
900             }
901
902             if (myHttpResponseCode != 200) {
903                 savedError = PKIX_HTTPSERVERERROR;
904                 break;
905             }
906         } while(0);
907         if (!myHttpResponseData) {
908             /* Going to the next one. */
909             genName = CERT_GetNextGeneralName(genName);
910             derGenNames++;
911         }
912         /* Staing in the loop through all the names until
913          * we have a successful download. */
914     } while (!myHttpResponseData && *derGenNames &&
915              genName != dp->name.fullName);
916     /* Need this name to track the crl source location. */
917     PORT_Assert(derGenName);
918
919     if (!myHttpResponseData) {
920         /* Generating fake bad CRL to keep track of this dp */
921         SECItem derCrl = {siBuffer, (void*)"BadCrl", 6 };
922         
923         derCrlCopy = SECITEM_DupItem(&derCrl);
924         if (!derCrlCopy) {
925             PKIX_ERROR(PKIX_ALLOCERROR);
926         }
927         derGenName = *dp->nssdp->derFullName;
928     } else {
929         SECItem derCrl = { siBuffer,
930                            (void*)myHttpResponseData,
931                            myHttpResponseDataLen };
932         derCrlCopy = SECITEM_DupItem(&derCrl);
933         if (!derCrlCopy) {
934             PKIX_ERROR(PKIX_ALLOCERROR);
935         }
936         /* crl will be based on derCrlCopy, but will not own the der. */
937         nssCrl =
938             CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE,
939                                        CRL_DECODE_DONT_COPY_DER |
940                                        CRL_DECODE_SKIP_ENTRIES);
941     }
942     /* pkix crl owns the der. */
943     PKIX_CHECK(
944         pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy,
945                                         derGenName,
946                                         crl, plContext),
947         PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
948     /* pkix crl now own both objects. */
949     derCrlCopy = NULL;
950     nssCrl = NULL;
951
952 cleanup:
953     if (derCrlCopy)
954         PORT_Free(derCrlCopy);
955     if (nssCrl)
956         SEC_DestroyCrl(nssCrl);
957     if (pRequestSession != NULL) 
958         (*hcv1->freeFcn)(pRequestSession);
959     if (pServerSession != NULL)
960         (*hcv1->freeSessionFcn)(pServerSession);
961     if (path != NULL)
962         PORT_Free(path);
963     if (hostname != NULL)
964         PORT_Free(hostname);
965     if (location) {
966         PORT_Free(location);
967     }
968
969     PKIX_RETURN(CERTSTORE);
970 }
971
972 /*
973  * FUNCTION: pkix_pl_Pk11CertStore_GetCRL
974  *  (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
975  */
976 static PKIX_Error *
977 pkix_pl_Pk11CertStore_GetCRL(
978         PKIX_CertStore *store,
979         PKIX_CRLSelector *selector,
980         void **pNBIOContext,
981         PKIX_List **pCrlList,
982         void *plContext)
983 {
984     PKIX_UInt32 dpIndex = 0;
985     PKIX_PL_CRL *crl = NULL;
986     PKIX_List *crlList = NULL;
987     PKIX_List *dpList = NULL;
988     pkix_pl_CrlDp *dp = NULL;
989     PKIX_PL_Date *date = NULL;
990     const SEC_HttpClientFcn *registeredHttpClient = NULL;
991
992     PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCRL");
993     PKIX_NULLCHECK_THREE(store, pNBIOContext, pCrlList);
994     PKIX_NULLCHECK_TWO(selector, selector->params);
995
996     registeredHttpClient = SEC_GetRegisteredHttpClient();
997     if (!registeredHttpClient || registeredHttpClient->version != 1) {
998         goto cleanup;
999     }
1000     dpList = selector->params->crldpList;
1001     date = selector->params->date;
1002     PKIX_CHECK(
1003         RemovePartitionedDpsFromList(dpList, date,
1004                                      plContext),
1005         PKIX_FAILTOREMOVEDPFROMLIST);
1006     for (;dpIndex < dpList->length;dpIndex++) {
1007         PKIX_DECREF(dp);
1008         pkixErrorResult =
1009             PKIX_List_GetItem(dpList, dpIndex,
1010                               (PKIX_PL_Object **)&dp,
1011                               plContext);
1012         if (pkixErrorResult) {
1013             PKIX_DECREF(pkixErrorResult);
1014             continue;
1015         }
1016         pkixErrorResult =
1017             DownloadCrl(dp, &crl,
1018                         &registeredHttpClient->fcnTable.ftable1,
1019                         plContext);
1020         if (pkixErrorResult || !crl) {
1021             /* continue to next dp in case of unsuccesfull
1022              * download attempt. */
1023             PKIX_DECREF(pkixErrorResult);
1024             continue;
1025         }
1026         if (!crlList) {
1027             PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
1028                        PKIX_LISTCREATEFAILED);
1029         }
1030         pkixErrorResult =
1031             PKIX_List_AppendItem(crlList, (PKIX_PL_Object *)crl,
1032                                  plContext);
1033         if (pkixErrorResult) {
1034             PKIX_DECREF(pkixErrorResult);
1035         }
1036         PKIX_DECREF(crl);
1037     }
1038     *pCrlList = crlList;
1039     crlList = NULL;
1040
1041 cleanup:
1042     PKIX_DECREF(dp);
1043     PKIX_DECREF(crl);
1044     PKIX_DECREF(crlList);
1045
1046     PKIX_RETURN(CERTSTORE);
1047 }
1048
1049
1050 /* --Public-Pk11CertStore-Functions----------------------------------- */
1051
1052 /*
1053  * FUNCTION: PKIX_PL_Pk11CertStore_Create
1054  * (see comments in pkix_samples_modules.h)
1055  */
1056 PKIX_Error *
1057 PKIX_PL_Pk11CertStore_Create(
1058         PKIX_CertStore **pCertStore,
1059         void *plContext)
1060 {
1061         PKIX_CertStore *certStore = NULL;
1062
1063         PKIX_ENTER(CERTSTORE, "PKIX_PL_Pk11CertStore_Create");
1064         PKIX_NULLCHECK_ONE(pCertStore);
1065
1066         PKIX_CHECK(PKIX_CertStore_Create
1067                 (pkix_pl_Pk11CertStore_GetCert,
1068                 pkix_pl_Pk11CertStore_GetCRL,
1069                 NULL, /* getCertContinue */
1070                 NULL, /* getCrlContinue */
1071                 pkix_pl_Pk11CertStore_CheckTrust,
1072                 pkix_pl_Pk11CertStore_ImportCrl,
1073                 pkix_pl_Pk11CertStore_CheckRevByCrl,
1074                 NULL,
1075                 PKIX_TRUE, /* cache flag */
1076                 PKIX_TRUE, /* local - no network I/O */
1077                 &certStore,
1078                 plContext),
1079                 PKIX_CERTSTORECREATEFAILED);
1080
1081         *pCertStore = certStore;
1082
1083 cleanup:
1084
1085         PKIX_RETURN(CERTSTORE);
1086 }