summaryrefslogtreecommitdiff
path: root/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c
diff options
context:
space:
mode:
Diffstat (limited to 'mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c')
-rwxr-xr-xmozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c1086
1 files changed, 1086 insertions, 0 deletions
diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c
new file mode 100755
index 0000000..083197e
--- /dev/null
+++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c
@@ -0,0 +1,1086 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the PKIX-C library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are
+ * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sun Microsystems, Inc.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * pkix_pl_pk11certstore.c
+ *
+ * PKCS11CertStore Function Definitions
+ *
+ */
+
+#include "pkix_pl_pk11certstore.h"
+
+/*
+ * PKIX_DEFAULT_MAX_RESPONSE_LENGTH (64 * 1024) is too small for downloading
+ * CRLs. We observed CRLs of sizes 338759 and 439035 in practice. So we
+ * need to use a higher max response length for CRLs.
+ */
+#define PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH (512 * 1024)
+
+/* --Private-Pk11CertStore-Functions---------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CheckTrust
+ * DESCRIPTION:
+ * This function checks the trust status of this "cert" that was retrieved
+ * from the CertStore "store" and returns its trust status at "pTrusted".
+ *
+ * PARAMETERS:
+ * "store"
+ * Address of the CertStore. Must be non-NULL.
+ * "cert"
+ * Address of the Cert. Must be non-NULL.
+ * "pTrusted"
+ * Address of PKIX_Boolean where the "cert" trust status is returned.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CheckTrust(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ SECCertUsage certUsage = 0;
+ SECCertificateUsage certificateUsage;
+ unsigned int requiredFlags;
+ SECTrustType trustType;
+ CERTCertTrust trust;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckTrust");
+ PKIX_NULLCHECK_THREE(store, cert, pTrusted);
+ PKIX_NULLCHECK_ONE(cert->nssCert);
+
+ certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
+
+ /* ensure we obtained a single usage bit only */
+ PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
+
+ /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
+ while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
+
+ rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType);
+ if (rv == SECSuccess) {
+ rv = CERT_GetCertTrust(cert->nssCert, &trust);
+ }
+
+ if (rv == SECSuccess) {
+ unsigned int certFlags;
+
+ if (certUsage != certUsageAnyCA &&
+ certUsage != certUsageStatusResponder) {
+ CERTCertificate *nssCert = cert->nssCert;
+
+ if (certUsage == certUsageVerifyCA) {
+ if (nssCert->nsCertType & NS_CERT_TYPE_EMAIL_CA) {
+ trustType = trustEmail;
+ } else if (nssCert->nsCertType & NS_CERT_TYPE_SSL_CA) {
+ trustType = trustSSL;
+ } else {
+ trustType = trustObjectSigning;
+ }
+ }
+
+ certFlags = SEC_GET_TRUST_FLAGS((&trust), trustType);
+ if ((certFlags & requiredFlags) == requiredFlags) {
+ trusted = PKIX_TRUE;
+ }
+ } else {
+ for (trustType = trustSSL; trustType < trustTypeNone;
+ trustType++) {
+ certFlags =
+ SEC_GET_TRUST_FLAGS((&trust), trustType);
+ if ((certFlags & requiredFlags) == requiredFlags) {
+ trusted = PKIX_TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ *pTrusted = trusted;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CertQuery
+ * DESCRIPTION:
+ *
+ * This function obtains from the database the Certs specified by the
+ * ComCertSelParams pointed to by "params" and stores the resulting
+ * List at "pSelected". If no matching Certs are found, a NULL pointer
+ * will be stored.
+ *
+ * This function uses a "smart" database query if the Subject has been set
+ * in ComCertSelParams. Otherwise, it uses a very inefficient call to
+ * retrieve all Certs in the database (and run them through the selector).
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCertSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CertQuery(
+ PKIX_ComCertSelParams *params,
+ PKIX_List **pSelected,
+ void *plContext)
+{
+ PRBool validOnly = PR_FALSE;
+ PRTime prtime = 0;
+ PKIX_PL_X500Name *subjectName = NULL;
+ PKIX_PL_Date *certValid = NULL;
+ PKIX_List *certList = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ CERTCertList *pk11CertList = NULL;
+ CERTCertListNode *node = NULL;
+ CERTCertificate *nssCert = NULL;
+ CERTCertDBHandle *dbHandle = NULL;
+
+ PRArenaPool *arena = NULL;
+ SECItem *nameItem = NULL;
+ void *wincx = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CertQuery");
+ PKIX_NULLCHECK_TWO(params, pSelected);
+
+ /* avoid multiple calls to retrieve a constant */
+ PKIX_PL_NSSCALLRV(CERTSTORE, dbHandle, CERT_GetDefaultCertDB, ());
+
+ /*
+ * Any of the ComCertSelParams may be obtained and used to constrain
+ * the database query, to allow the use of a "smart" query. See
+ * pkix_certsel.h for a list of the PKIX_ComCertSelParams_Get*
+ * calls available. No corresponding "smart" queries exist at present,
+ * except for CERT_CreateSubjectCertList based on Subject. When others
+ * are added, corresponding code should be added to
+ * pkix_pl_Pk11CertStore_CertQuery to use them when appropriate
+ * selector parameters have been set.
+ */
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
+ (params, &subjectName, plContext),
+ PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetCertificateValid
+ (params, &certValid, plContext),
+ PKIX_COMCERTSELPARAMSGETCERTIFICATEVALIDFAILED);
+
+ /* If caller specified a Date, convert it to PRTime */
+ if (certValid) {
+ PKIX_CHECK(pkix_pl_Date_GetPRTime
+ (certValid, &prtime, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ validOnly = PR_TRUE;
+ }
+
+ /*
+ * If we have the subject name for the desired subject,
+ * ask the database for Certs with that subject. Otherwise
+ * ask the database for all Certs.
+ */
+ if (subjectName) {
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena) {
+
+ PKIX_CHECK(pkix_pl_X500Name_GetDERName
+ (subjectName, arena, &nameItem, plContext),
+ PKIX_X500NAMEGETSECNAMEFAILED);
+
+ if (nameItem) {
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ pk11CertList,
+ CERT_CreateSubjectCertList,
+ (NULL, dbHandle, nameItem, prtime, validOnly));
+ }
+ PKIX_PL_NSSCALL
+ (CERTSTORE, PORT_FreeArena, (arena, PR_FALSE));
+ arena = NULL;
+ }
+
+ } else {
+
+ PKIX_CHECK(pkix_pl_NssContext_GetWincx
+ ((PKIX_PL_NssContext *)plContext, &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ pk11CertList,
+ PK11_ListCerts,
+ (PK11CertListAll, wincx));
+ }
+
+ if (pk11CertList) {
+
+ PKIX_CHECK(PKIX_List_Create(&certList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (node = CERT_LIST_HEAD(pk11CertList);
+ !(CERT_LIST_END(node, pk11CertList));
+ node = CERT_LIST_NEXT(node)) {
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ nssCert,
+ CERT_NewTempCertificate,
+ (dbHandle,
+ &(node->cert->derCert),
+ NULL, /* nickname */
+ PR_FALSE,
+ PR_TRUE)); /* copyDER */
+
+ if (!nssCert) {
+ continue; /* just skip bad certs */
+ }
+
+ PKIX_CHECK_ONLY_FATAL(pkix_pl_Cert_CreateWithNSSCert
+ (nssCert, &cert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+ if (PKIX_ERROR_RECEIVED) {
+ CERT_DestroyCertificate(nssCert);
+ nssCert = NULL;
+ continue; /* just skip bad certs */
+ }
+
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
+ (certList, (PKIX_PL_Object *)cert, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(cert);
+
+ }
+
+ /* Don't throw away the list if one cert was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+ }
+
+ *pSelected = certList;
+ certList = NULL;
+
+cleanup:
+
+ if (pk11CertList) {
+ CERT_DestroyCertList(pk11CertList);
+ }
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ PKIX_DECREF(subjectName);
+ PKIX_DECREF(certValid);
+ PKIX_DECREF(cert);
+ PKIX_DECREF(certList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_ImportCrl
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCRLSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_ImportCrl(
+ PKIX_CertStore *store,
+ PKIX_PL_X500Name *issuerName,
+ PKIX_List *crlList,
+ void *plContext)
+{
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+ PKIX_PL_CRL *crl = NULL;
+ SECItem *derCrl = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ImportCrl");
+ PKIX_NULLCHECK_TWO(store, plContext);
+
+ if (!crlList) {
+ goto cleanup;
+ }
+ while (crlList->length > 0) {
+ PKIX_CHECK(
+ PKIX_List_GetItem(crlList, 0, (PKIX_PL_Object**)&crl,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ /* Delete crl from the list to keep controll of the
+ * last reference. crl need to be destroyed right after
+ * it released the ownership of the crl der. */
+ PKIX_CHECK(
+ PKIX_List_DeleteItem(crlList, 0, plContext),
+ PKIX_LISTDELETEITEMFAILED);
+
+ /* acquire the crlder ownership */
+ pkixErrorResult =
+ PKIX_PL_CRL_ReleaseDerCrl(crl, &derCrl, plContext);
+ PORT_Assert(!pkixErrorResult && derCrl);
+ if (pkixErrorResult || !derCrl) {
+ /* All pkix delivered crls should be able to
+ * release their ders. */
+ PKIX_DECREF(pkixErrorResult);
+ PKIX_DECREF(crl);
+ continue;
+ }
+ cert_CacheCRLByGeneralName(certHandle, derCrl,
+ crl->derGenName);
+ /* Do not check the status. If it is a SECFailure,
+ * derCrl is already destroyed. */
+ derCrl = NULL;
+ PKIX_DECREF(crl);
+ }
+
+cleanup:
+ PKIX_DECREF(crl);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+static PKIX_Error *
+NameCacheHasFetchedCrlInfo(PKIX_PL_Cert *pkixCert,
+ PRTime time,
+ PKIX_Boolean *pHasFetchedCrlInCache,
+ void *plContext)
+{
+ /* Returning true result in this case will mean, that case info
+ * is currect and should used as is. */
+ NamedCRLCache* nameCrlCache = NULL;
+ PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
+ PKIX_List *dpList = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ CERTCertificate *cert;
+ PKIX_UInt32 dpIndex = 0;
+ SECStatus rv = SECSuccess;
+ PRTime reloadDelay = 0, badCrlInvalDelay = 0;
+
+ PKIX_ENTER(CERTSTORE, "ChechCacheHasFetchedCrl");
+
+ cert = pkixCert->nssCert;
+ reloadDelay =
+ ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
+ PR_USEC_PER_SEC;
+ badCrlInvalDelay =
+ ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
+ PR_USEC_PER_SEC;
+ if (!time) {
+ time = PR_Now();
+ }
+ /* If we already download the crl and inserted into the cache, then
+ * there is no need to check for fetched crl. We have what we have. */
+ PKIX_CHECK(
+ PKIX_PL_Cert_GetCrlDp(pkixCert, &dpList, plContext),
+ PKIX_CERTGETCRLDPFAILED);
+ if (dpList && dpList->length) {
+ hasFetchedCrlInCache = PKIX_FALSE;
+ rv = cert_AcquireNamedCRLCache(&nameCrlCache);
+ if (rv != SECSuccess) {
+ PKIX_DECREF(dpList);
+ }
+ } else {
+ /* If no dp then treat it as if we already have
+ * a fetched crl. */
+ PKIX_DECREF(dpList);
+ }
+ for (;!hasFetchedCrlInCache &&
+ dpList && dpIndex < dpList->length;dpIndex++) {
+ SECItem **derDpNames = NULL;
+ pkixErrorResult =
+ PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ if (dp->nssdp->distPointType == generalName) {
+ /* dp can only be created from nssdp. */
+ derDpNames = dp->nssdp->derFullName;
+ }
+ while (derDpNames && *derDpNames != NULL) {
+ NamedCRLCacheEntry* cacheEntry = NULL;
+ const SECItem *derDpName = *derDpNames++;
+ rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
+ &cacheEntry);
+ if (rv == SECSuccess && cacheEntry) {
+ if ((cacheEntry->inCRLCache &&
+ (cacheEntry->successfulInsertionTime + reloadDelay > time ||
+ (cacheEntry->dupe &&
+ cacheEntry->lastAttemptTime + reloadDelay > time))) ||
+ (cacheEntry->badDER &&
+ cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
+ hasFetchedCrlInCache = PKIX_TRUE;
+ break;
+ }
+ }
+ }
+ PKIX_DECREF(dp);
+ }
+cleanup:
+ *pHasFetchedCrlInCache = hasFetchedCrlInCache;
+ if (nameCrlCache) {
+ cert_ReleaseNamedCRLCache(nameCrlCache);
+ }
+ PKIX_DECREF(dpList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CheckCrl
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCRLSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CheckRevByCrl(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *pkixCert,
+ PKIX_PL_Cert *pkixIssuer,
+ PKIX_PL_Date *date,
+ PKIX_Boolean crlDownloadDone,
+ PKIX_UInt32 *pReasonCode,
+ PKIX_RevocationStatus *pStatus,
+ void *plContext)
+{
+ PKIX_RevocationStatus pkixRevStatus = PKIX_RevStatus_NoInfo;
+ CERTRevocationStatus revStatus = certRevocationStatusUnknown;
+ PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
+ CERTCertificate *cert = NULL, *issuer = NULL;
+ SECStatus rv = SECSuccess;
+ void *wincx = NULL;
+ PRTime time = 0;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckRevByCrl");
+ PKIX_NULLCHECK_FOUR(store, pkixCert, pkixIssuer, plContext);
+
+ cert = pkixCert->nssCert;
+ issuer = pkixIssuer->nssCert;
+ if (date) {
+ PKIX_CHECK(
+ pkix_pl_Date_GetPRTime(date, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ }
+ PKIX_CHECK(
+ pkix_pl_NssContext_GetWincx((PKIX_PL_NssContext*)plContext,
+ &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+ /* No need to check any cDPs, since partitioned crls are not
+ * supported. If a ds does not point to partitioned crl, then
+ * the crl should be in issuer cache that is unrelated to any
+ * dp. Using NULL as a dp pointer to check it.*/
+ rv = cert_CheckCertRevocationStatus(cert, issuer, NULL,
+ /* Will not validate the signature
+ * on the crl if time is not specified.*/
+ time, wincx, &revStatus, pReasonCode);
+ if (rv == SECFailure) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ goto cleanup;
+ }
+ if (crlDownloadDone) {
+ if (revStatus == certRevocationStatusRevoked) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ } else if (revStatus == certRevocationStatusValid) {
+ pkixRevStatus = PKIX_RevStatus_Success;
+ }
+ } else {
+ pkixErrorResult =
+ NameCacheHasFetchedCrlInfo(pkixCert, time, &hasFetchedCrlInCache,
+ plContext);
+ if (pkixErrorResult) {
+ goto cleanup;
+ }
+ if (revStatus == certRevocationStatusRevoked &&
+ (hasFetchedCrlInCache ||
+ *pReasonCode != crlEntryReasoncertificatedHold)) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ } else if (revStatus == certRevocationStatusValid &&
+ hasFetchedCrlInCache) {
+ pkixRevStatus = PKIX_RevStatus_Success;
+ }
+ }
+cleanup:
+ *pStatus = pkixRevStatus;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_GetCert
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_Pk11CertStore_GetCert(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *parentVerifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ PKIX_UInt32 i = 0;
+ PKIX_UInt32 numFound = 0;
+ PKIX_PL_Cert *candidate = NULL;
+ PKIX_List *selected = NULL;
+ PKIX_List *filtered = NULL;
+ PKIX_CertSelector_MatchCallback selectorCallback = NULL;
+ PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
+ PKIX_ComCertSelParams *params = NULL;
+ PKIX_Boolean cacheFlag = PKIX_FALSE;
+ PKIX_VerifyNode *verifyNode = NULL;
+ PKIX_Error *selectorError = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCert");
+ PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCertList);
+
+ *pNBIOContext = NULL; /* We don't use non-blocking I/O */
+
+ PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
+ (selector, &selectorCallback, plContext),
+ PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (selector, &params, plContext),
+ PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED);
+
+ PKIX_CHECK(pkix_pl_Pk11CertStore_CertQuery
+ (params, &selected, plContext),
+ PKIX_PK11CERTSTORECERTQUERYFAILED);
+
+ if (selected) {
+ PKIX_CHECK(PKIX_List_GetLength(selected, &numFound, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+ }
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (store, &cacheFlag, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ PKIX_CHECK(PKIX_CertStore_GetTrustCallback
+ (store, &trustCallback, plContext),
+ PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_List_Create(&filtered, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; i < numFound; i++) {
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
+ (selected,
+ i,
+ (PKIX_PL_Object **)&candidate,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (PKIX_ERROR_RECEIVED) {
+ continue; /* just skip bad certs */
+ }
+
+ selectorError =
+ selectorCallback(selector, candidate, plContext);
+ if (!selectorError) {
+ PKIX_CHECK(PKIX_PL_Cert_SetCacheFlag
+ (candidate, cacheFlag, plContext),
+ PKIX_CERTSETCACHEFLAGFAILED);
+
+ if (trustCallback) {
+ PKIX_CHECK(PKIX_PL_Cert_SetTrustCertStore
+ (candidate, store, plContext),
+ PKIX_CERTSETTRUSTCERTSTOREFAILED);
+ }
+
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
+ (filtered,
+ (PKIX_PL_Object *)candidate,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ } else if (parentVerifyNode) {
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_Create(candidate, 0, selectorError,
+ &verifyNode, plContext),
+ PKIX_VERIFYNODECREATEFAILED);
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_AddToTree(parentVerifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ PKIX_DECREF(selectorError);
+ PKIX_DECREF(candidate);
+ }
+
+ /* Don't throw away the list if one cert was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pCertList = filtered;
+ filtered = NULL;
+
+cleanup:
+fatal:
+ PKIX_DECREF(filtered);
+ PKIX_DECREF(candidate);
+ PKIX_DECREF(selected);
+ PKIX_DECREF(params);
+ PKIX_DECREF(verifyNode);
+ PKIX_DECREF(selectorError);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+static PKIX_Error *
+RemovePartitionedDpsFromList(PKIX_List *dpList, PKIX_PL_Date *date,
+ void *plContext)
+{
+ NamedCRLCache* nameCrlCache = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ int dpIndex = 0;
+ PRTime time;
+ PRTime reloadDelay = 0, badCrlInvalDelay = 0;
+ SECStatus rv;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ListRemovePrtDp");
+
+ if (!dpList || !dpList->length) {
+ PKIX_RETURN(CERTSTORE);
+ }
+ reloadDelay =
+ ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
+ PR_USEC_PER_SEC;
+ badCrlInvalDelay =
+ ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
+ PR_USEC_PER_SEC;
+ PKIX_CHECK(pkix_pl_Date_GetPRTime(date, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ rv = cert_AcquireNamedCRLCache(&nameCrlCache);
+ if (rv == SECFailure) {
+ /* Baling out. Wont find out any thing useful. */
+ PKIX_RETURN(CERTSTORE);
+ }
+ while (dpIndex < dpList->length) {
+ SECItem **derDpNames = NULL;
+ PKIX_Boolean removeDp = PKIX_FALSE;
+
+ PKIX_CHECK(
+ PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ if (!dp->isPartitionedByReasonCode) {
+ /* See if we know about this dp anything why we should
+ * not use it to download a crl. */
+ if (dp->nssdp->distPointType == generalName) {
+ /* dp can only be created from nssdp. */
+ derDpNames = dp->nssdp->derFullName;
+ } else {
+ removeDp = PKIX_TRUE;
+ }
+ while (derDpNames && *derDpNames != NULL) {
+ NamedCRLCacheEntry* cacheEntry = NULL;
+ const SECItem *derDpName = *derDpNames++;
+ /* Removing from the list all dps that we know about. */
+ rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
+ &cacheEntry);
+ if (rv && cacheEntry) {
+ if (cacheEntry->unsupported ||
+ (cacheEntry->inCRLCache &&
+ (cacheEntry->successfulInsertionTime + reloadDelay > time ||
+ (cacheEntry->dupe &&
+ cacheEntry->lastAttemptTime + reloadDelay > time))) ||
+ (cacheEntry->badDER &&
+ cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
+ removeDp = PKIX_TRUE;
+ }
+ }
+ }
+ } else {
+ /* Remove dp that point to a partitioned crl . RFC 5280
+ * recommends against crl partitioned by reason code.
+ * Will skip such crls */
+ removeDp = PKIX_TRUE;
+ }
+ if (removeDp) {
+ PKIX_CHECK_ONLY_FATAL(
+ pkix_List_Remove(dpList,(PKIX_PL_Object*)dp,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ } else {
+ dpIndex += 1;
+ }
+ PKIX_DECREF(dp);
+ }
+
+cleanup:
+ if (nameCrlCache) {
+ cert_ReleaseNamedCRLCache(nameCrlCache);
+ }
+ PKIX_DECREF(dp);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_DownloadCrl
+ */
+static PKIX_Error *
+DownloadCrl(pkix_pl_CrlDp *dp, PKIX_PL_CRL **crl,
+ const SEC_HttpClientFcnV1 *hcv1, void *plContext)
+{
+ char *location = NULL;
+ char *hostname = NULL;
+ char *path = NULL;
+ PRUint16 port;
+ SEC_HTTP_SERVER_SESSION pServerSession = NULL;
+ SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
+ PRUint16 myHttpResponseCode;
+ const char *myHttpResponseData = NULL;
+ PRUint32 myHttpResponseDataLen;
+ SECItem *uri = NULL;
+ SECItem *derCrlCopy = NULL;
+ CERTSignedCrl *nssCrl = NULL;
+ CERTGeneralName *genName = NULL;
+ PKIX_Int32 savedError = -1;
+ SECItem **derGenNames = NULL;
+ SECItem *derGenName = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_DownloadCrl");
+
+ /* Do not support dps others than a one with GeneralName
+ * name type. */
+ if (dp->distPointType != generalName ||
+ !dp->nssdp->derFullName) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDCRLDPTYPE);
+ }
+ genName = dp->name.fullName;
+ derGenNames = dp->nssdp->derFullName;
+ do {
+ derGenName = *derGenNames;
+ do {
+ if (!derGenName ||
+ !genName->name.other.data) {
+ /* get to next name if no data. */
+ savedError = PKIX_UNSUPPORTEDCRLDPTYPE;
+ break;
+ }
+ uri = &genName->name.other;
+ location = (char*)PR_Malloc(1 + uri->len);
+ if (!location) {
+ savedError = PKIX_ALLOCERROR;
+ break;
+ }
+ PORT_Memcpy(location, uri->data, uri->len);
+ location[uri->len] = 0;
+ if (CERT_ParseURL(location, &hostname,
+ &port, &path) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
+ savedError = PKIX_URLPARSINGFAILED;
+ break;
+ }
+
+ PORT_Assert(hostname != NULL);
+ PORT_Assert(path != NULL);
+
+ if ((*hcv1->createSessionFcn)(hostname, port,
+ &pServerSession) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
+ savedError = PKIX_URLPARSINGFAILED;
+ break;
+ }
+
+ if ((*hcv1->createFcn)(pServerSession, "http", path, "GET",
+ /* Users with slow connections might not get CRL revocation
+ checking for certs that use big CRLs because of the timeout
+ We absolutely need code that limits our retry attempts.
+ */
+ PR_SecondsToInterval(
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
+ &pRequestSession) != SECSuccess) {
+ savedError = PKIX_HTTPSERVERERROR;
+ break;
+ }
+
+ myHttpResponseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+ if (myHttpResponseDataLen < PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH)
+ myHttpResponseDataLen = PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH;
+
+ /* We use a non-zero timeout, which means:
+ - the client will use blocking I/O
+ - TryFcn will not return WOULD_BLOCK nor a poll descriptor
+ - it's sufficient to call TryFcn once
+ */
+ /* we don't want result objects larger than this: */
+ if ((*hcv1->trySendAndReceiveFcn)(
+ pRequestSession,
+ NULL,
+ &myHttpResponseCode,
+ NULL,
+ NULL,
+ &myHttpResponseData,
+ &myHttpResponseDataLen) != SECSuccess) {
+ savedError = PKIX_HTTPSERVERERROR;
+ break;
+ }
+
+ if (myHttpResponseCode != 200) {
+ savedError = PKIX_HTTPSERVERERROR;
+ break;
+ }
+ } while(0);
+ if (!myHttpResponseData) {
+ /* Going to the next one. */
+ genName = CERT_GetNextGeneralName(genName);
+ derGenNames++;
+ }
+ /* Staing in the loop through all the names until
+ * we have a successful download. */
+ } while (!myHttpResponseData && *derGenNames &&
+ genName != dp->name.fullName);
+ /* Need this name to track the crl source location. */
+ PORT_Assert(derGenName);
+
+ if (!myHttpResponseData) {
+ /* Generating fake bad CRL to keep track of this dp */
+ SECItem derCrl = {siBuffer, (void*)"BadCrl", 6 };
+
+ derCrlCopy = SECITEM_DupItem(&derCrl);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ derGenName = *dp->nssdp->derFullName;
+ } else {
+ SECItem derCrl = { siBuffer,
+ (void*)myHttpResponseData,
+ myHttpResponseDataLen };
+ derCrlCopy = SECITEM_DupItem(&derCrl);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ /* crl will be based on derCrlCopy, but will not own the der. */
+ nssCrl =
+ CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE,
+ CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_SKIP_ENTRIES);
+ }
+ /* pkix crl owns the der. */
+ PKIX_CHECK(
+ pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy,
+ derGenName,
+ crl, plContext),
+ PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
+ /* pkix crl now own both objects. */
+ derCrlCopy = NULL;
+ nssCrl = NULL;
+
+cleanup:
+ if (derCrlCopy)
+ PORT_Free(derCrlCopy);
+ if (nssCrl)
+ SEC_DestroyCrl(nssCrl);
+ if (pRequestSession != NULL)
+ (*hcv1->freeFcn)(pRequestSession);
+ if (pServerSession != NULL)
+ (*hcv1->freeSessionFcn)(pServerSession);
+ if (path != NULL)
+ PORT_Free(path);
+ if (hostname != NULL)
+ PORT_Free(hostname);
+ if (location) {
+ PORT_Free(location);
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_GetCRL
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_GetCRL(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ PKIX_UInt32 dpIndex = 0;
+ PKIX_PL_CRL *crl = NULL;
+ PKIX_List *crlList = NULL;
+ PKIX_List *dpList = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ PKIX_PL_Date *date = NULL;
+ const SEC_HttpClientFcn *registeredHttpClient = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCRL");
+ PKIX_NULLCHECK_THREE(store, pNBIOContext, pCrlList);
+ PKIX_NULLCHECK_TWO(selector, selector->params);
+
+ registeredHttpClient = SEC_GetRegisteredHttpClient();
+ if (!registeredHttpClient || registeredHttpClient->version != 1) {
+ goto cleanup;
+ }
+ dpList = selector->params->crldpList;
+ date = selector->params->date;
+ PKIX_CHECK(
+ RemovePartitionedDpsFromList(dpList, date,
+ plContext),
+ PKIX_FAILTOREMOVEDPFROMLIST);
+ for (;dpIndex < dpList->length;dpIndex++) {
+ PKIX_DECREF(dp);
+ pkixErrorResult =
+ PKIX_List_GetItem(dpList, dpIndex,
+ (PKIX_PL_Object **)&dp,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ pkixErrorResult =
+ DownloadCrl(dp, &crl,
+ &registeredHttpClient->fcnTable.ftable1,
+ plContext);
+ if (pkixErrorResult || !crl) {
+ /* continue to next dp in case of unsuccesfull
+ * download attempt. */
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ if (!crlList) {
+ PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+ pkixErrorResult =
+ PKIX_List_AppendItem(crlList, (PKIX_PL_Object *)crl,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ }
+ PKIX_DECREF(crl);
+ }
+ *pCrlList = crlList;
+ crlList = NULL;
+
+cleanup:
+ PKIX_DECREF(dp);
+ PKIX_DECREF(crl);
+ PKIX_DECREF(crlList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+
+/* --Public-Pk11CertStore-Functions----------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Pk11CertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_Pk11CertStore_Create(
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_CertStore *certStore = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_Pk11CertStore_Create");
+ PKIX_NULLCHECK_ONE(pCertStore);
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_Pk11CertStore_GetCert,
+ pkix_pl_Pk11CertStore_GetCRL,
+ NULL, /* getCertContinue */
+ NULL, /* getCrlContinue */
+ pkix_pl_Pk11CertStore_CheckTrust,
+ pkix_pl_Pk11CertStore_ImportCrl,
+ pkix_pl_Pk11CertStore_CheckRevByCrl,
+ NULL,
+ PKIX_TRUE, /* cache flag */
+ PKIX_TRUE, /* local - no network I/O */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ *pCertStore = certStore;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+}