diff --git a/mozilla/security/nss/cmd/vfychain/vfychain.c b/mozilla/security/nss/cmd/vfychain/vfychain.c index 56be1c6d099..800ae19b56f 100644 --- a/mozilla/security/nss/cmd/vfychain/vfychain.c +++ b/mozilla/security/nss/cmd/vfychain/vfychain.c @@ -66,6 +66,9 @@ Usage(const char *progName) "\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n" "\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n" "\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA\n" + "\t-T\t\t Trust both explicit trust anchors (-t) and the database.\n" + "\t\t\t (Default is to only trust certificates marked -t, if there are any,\n" + "\t\t\t or to trust the database if there are certificates marked -t.)\n" "\t-v\t\t Verbose mode. Prints root cert subject(double the\n" "\t\t\t argument for whole root cert info)\n" "\t-w password\t Database password.\n" @@ -423,13 +426,14 @@ main(int argc, char *argv[], char *envp[]) int revDataIndex = 0; PRBool ocsp_fetchingFailureIsAFailure = PR_TRUE; PRBool useDefaultRevFlags = PR_TRUE; + PRBool onlyTrustAnchors = PR_TRUE; int vfyCounts = 1; PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); progName = PL_strdup(argv[0]); - optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tu:vw:W:"); + optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tTu:vw:W:"); while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch(optstate->option) { case 0 : /* positional parameter */ goto breakout; @@ -478,6 +482,7 @@ main(int argc, char *argv[], char *envp[]) revMethodsData[revDataIndex]. methodFlagsStr = PL_strdup(optstate->value); break; case 't' : trusted = PR_TRUE; break; + case 'T' : onlyTrustAnchors = PR_FALSE; break; case 'u' : usage = PORT_Atoi(optstate->value); if (usage < 0 || usage > 62) Usage(progName); certUsage = ((SECCertificateUsage)1) << usage; @@ -511,6 +516,11 @@ breakout: " CERT_PKIXVerifyCert(-pp) function.\n"); Usage(progName); } + if (!onlyTrustAnchors) { + fprintf(stderr, "Cert trust anchor exclusiveness can be" + " used only with CERT_PKIXVerifyCert(-pp)" + " function.\n"); + } } if (!useDefaultRevFlags && parseRevMethodsAndFlags()) { @@ -593,7 +603,7 @@ breakout: NULL);/* returned usages */ } else do { static CERTValOutParam cvout[4]; - static CERTValInParam cvin[6]; + static CERTValInParam cvin[7]; SECOidTag oidTag; int inParamIndex = 0; static PRUint64 revFlagsLeaf[2]; @@ -667,6 +677,12 @@ breakout: cvin[inParamIndex].value.scalar.time = time; inParamIndex++; } + + if (!onlyTrustAnchors) { + cvin[inParamIndex].type = cert_pi_useOnlyTrustAnchors; + cvin[inParamIndex].value.scalar.b = onlyTrustAnchors; + inParamIndex++; + } cvin[inParamIndex].type = cert_pi_end; diff --git a/mozilla/security/nss/lib/certdb/certt.h b/mozilla/security/nss/lib/certdb/certt.h index 506b010da60..11765a05bf8 100644 --- a/mozilla/security/nss/lib/certdb/certt.h +++ b/mozilla/security/nss/lib/certdb/certt.h @@ -4,7 +4,7 @@ /* * certt.h - public data structures for the certificate library * - * $Id: certt.h,v 1.57 2012-09-28 23:40:14 rrelyea%redhat.com Exp $ + * $Id: certt.h,v 1.58 2013-01-07 03:56:12 ryan.sleevi%gmail.com Exp $ */ #ifndef _CERTT_H_ #define _CERTT_H_ @@ -955,6 +955,8 @@ typedef enum { * the following cases: * * when the parameter is not set. * * when the list of trust anchors is empty. + * Note that this handling can be further altered by altering the + * cert_pi_useOnlyTrustAnchors flag * Specified in value.pointer.chain */ cert_pi_useAIACertFetch = 12, /* Enables cert fetching using AIA extension. * In NSS 3.12.1 or later. Default is off. @@ -963,6 +965,16 @@ typedef enum { /* The callback container for doing extra * validation on the currently calculated chain. * Value is in value.pointer.chainVerifyCallback */ + cert_pi_useOnlyTrustAnchors = 14,/* If true, disables trusting any + * certificates other than the ones passed in via cert_pi_trustAnchors. + * If false, then the certificates specified via cert_pi_trustAnchors + * will be combined with the pre-existing trusted roots, but only for + * the certificate validation being performed. + * If no value has been supplied via cert_pi_trustAnchors, this has no + * effect. + * The default value is true, meaning if this is not supplied, only + * trust anchors supplied via cert_pi_trustAnchors are trusted. + * Specified in value.scalar.b */ cert_pi_max /* SPECIAL: signifies maximum allowed value, * can increase in future releases */ } CERTValParamInType; diff --git a/mozilla/security/nss/lib/certhigh/certvfypkix.c b/mozilla/security/nss/lib/certhigh/certvfypkix.c index a37a722b4cd..1138566e7e3 100644 --- a/mozilla/security/nss/lib/certhigh/certvfypkix.c +++ b/mozilla/security/nss/lib/certhigh/certvfypkix.c @@ -1711,6 +1711,13 @@ cert_pkixSetParam(PKIX_ProcessingParams *procParams, } break; + case cert_pi_useOnlyTrustAnchors: + error = + PKIX_ProcessingParams_SetUseOnlyTrustAnchors(procParams, + (PRBool)(param->value.scalar.b != 0), + plContext); + break; + default: PORT_SetError(errCode); r = SECFailure; diff --git a/mozilla/security/nss/lib/libpkix/include/pkix_params.h b/mozilla/security/nss/lib/libpkix/include/pkix_params.h index c239ed7ab5f..a4d8e485cb3 100755 --- a/mozilla/security/nss/lib/libpkix/include/pkix_params.h +++ b/mozilla/security/nss/lib/libpkix/include/pkix_params.h @@ -636,9 +636,11 @@ PKIX_ProcessingParams_GetTrustAnchors( * FUNCTION: PKIX_ProcessingParams_SetTrustAnchors * DESCRIPTION: * - * Sets user defined set of trust anchors. A certificate will be considered - * invalid if it does not chain to a trusted anchor from this list. - * + * Sets user defined set of trust anchors. The handling of the trust anchors + * may be furthered alter via PKIX_ProcessingParams_SetUseOnlyTrustAnchors. + * By default, a certificate will be considered invalid if it does not chain + * to a trusted anchor from this list. + * * PARAMETERS: * "params" * Address of ProcessingParams whose List of TrustAnchors are to @@ -661,6 +663,71 @@ PKIX_ProcessingParams_SetTrustAnchors( PKIX_List *pAnchors, /* list of TrustAnchor */ void *plContext); +/* + * FUNCTION: PKIX_ProcessingParams_GetUseOnlyTrustAnchors + * DESCRIPTION: + * + * Retrieves a pointer to the Boolean. The boolean value represents + * the switch value that is used to identify whether trust anchors, if + * specified, should be the exclusive source of trust information. + * If the function succeeds, the pointer to the Boolean is guaranteed to be + * non-NULL. + * + * PARAMETERS: + * "params" + * Address of ProcessingParams. Must be non-NULL. + * "pUseOnlyTrustAnchors" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Params Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +PKIX_ProcessingParams_GetUseOnlyTrustAnchors( + PKIX_ProcessingParams *params, + PKIX_Boolean *pUseOnlyTrustAnchors, + void *plContext); + +/* + * FUNCTION: PKIX_ProcessingParams_SetUseOnlyTrustAnchors + * DESCRIPTION: + * + * Configures whether trust anchors are used as the exclusive source of trust. + * + * PARAMETERS: + * "params" + * Address of ProcessingParams. Must be non-NULL. + * "useOnlyTrustAnchors" + * If true, indicates that trust anchors should be used exclusively when + * they have been specified via PKIX_ProcessingParams_SetTrustAnchors. A + * certificate will be considered invalid if it does not chain to a + * trusted anchor from that list. + * If false, indicates that the trust anchors are additive to whatever + * existing trust stores are configured. A certificate is considered + * valid if it chains to EITHER a trusted anchor from that list OR a + * certificate marked trusted in a trust store. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Params Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +PKIX_ProcessingParams_SetUseOnlyTrustAnchors( + PKIX_ProcessingParams *params, + PKIX_Boolean useOnlyTrustAnchors, + void *plContext); + /* * FUNCTION: PKIX_ProcessingParams_GetUseAIAForCertFetching * DESCRIPTION: diff --git a/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.c b/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.c index 6715df90977..260b0074c79 100755 --- a/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.c +++ b/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.c @@ -556,6 +556,7 @@ PKIX_ProcessingParams_Create( params->useAIAForCertFetching = PKIX_FALSE; params->qualifyTargetCert = PKIX_TRUE; + params->useOnlyTrustAnchors = PKIX_TRUE; *pParams = params; params = NULL; @@ -687,6 +688,44 @@ cleanup: PKIX_RETURN(PROCESSINGPARAMS); } +/** + * FUNCTION: PKIX_ProcessingParams_SetUseOnlyTrustAnchors + * (see comments in pkix_params.h) + */ +PKIX_Error * +PKIX_ProcessingParams_GetUseOnlyTrustAnchors( + PKIX_ProcessingParams *params, + PKIX_Boolean *pUseOnlyTrustAnchors, + void *plContext) +{ + PKIX_ENTER(PROCESSINGPARAMS, + "PKIX_ProcessingParams_SetUseTrustAnchorsOnly"); + PKIX_NULLCHECK_TWO(params, pUseOnlyTrustAnchors); + + *pUseOnlyTrustAnchors = params->useOnlyTrustAnchors; + + PKIX_RETURN(PROCESSINGPARAMS); +} + +/** + * FUNCTION: PKIX_ProcessingParams_SetUseOnlyTrustAnchors + * (see comments in pkix_params.h) + */ +PKIX_Error * +PKIX_ProcessingParams_SetUseOnlyTrustAnchors( + PKIX_ProcessingParams *params, + PKIX_Boolean useOnlyTrustAnchors, + void *plContext) +{ + PKIX_ENTER(PROCESSINGPARAMS, + "PKIX_ProcessingParams_SetUseTrustAnchorsOnly"); + PKIX_NULLCHECK_ONE(params); + + params->useOnlyTrustAnchors = useOnlyTrustAnchors; + + PKIX_RETURN(PROCESSINGPARAMS); +} + /* * FUNCTION: PKIX_ProcessingParams_GetDate (see comments in pkix_params.h) */ diff --git a/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.h b/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.h index 7ded2f99f0a..599f5d4988e 100755 --- a/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.h +++ b/mozilla/security/nss/lib/libpkix/pkix/params/pkix_procparams.h @@ -36,6 +36,7 @@ struct PKIX_ProcessingParamsStruct { PKIX_ResourceLimits *resourceLimits; PKIX_Boolean useAIAForCertFetching; PKIX_Boolean qualifyTargetCert; + PKIX_Boolean useOnlyTrustAnchors; }; /* see source file for function documentation */ diff --git a/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.c b/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.c index 4b1d5e81cb4..574fcfbbfc9 100755 --- a/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.c +++ b/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.c @@ -263,6 +263,8 @@ pkix_ForwardBuilderState_Create( parentState->buildConstants.revChecker; state->buildConstants.aiaMgr = parentState->buildConstants.aiaMgr; + state->buildConstants.trustOnlyUserAnchors = + parentState->buildConstants.trustOnlyUserAnchors; } *pState = state; @@ -847,10 +849,8 @@ pkix_Build_VerifyCertificate( PKIX_INCREF(state->candidateCert); candidateCert = state->candidateCert; - /* If user defined trust anchor list is not empty, do not - * trust any certs except to the ones that are in the list */ if (state->buildConstants.numAnchors) { - trustOnlyUserAnchors = PKIX_TRUE; + trustOnlyUserAnchors = state->buildConstants.trustOnlyUserAnchors; } PKIX_CHECK( @@ -3477,7 +3477,9 @@ pkix_Build_InitiateBuildChain( buildConstants.hintCerts = hintCerts; buildConstants.revChecker = revChecker; buildConstants.aiaMgr = aiaMgr; - + buildConstants.trustOnlyUserAnchors = + procParams->useOnlyTrustAnchors; + PKIX_CHECK(pkix_Build_GetResourceLimits(&buildConstants, plContext), PKIX_BUILDGETRESOURCELIMITSFAILED); @@ -3524,6 +3526,8 @@ pkix_Build_InitiateBuildChain( state->buildConstants.revChecker = buildConstants.revChecker; state->buildConstants.aiaMgr = buildConstants.aiaMgr; aiaMgr = NULL; + state->buildConstants.trustOnlyUserAnchors = + buildConstants.trustOnlyUserAnchors; if (buildConstants.maxTime != 0) { PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds diff --git a/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.h b/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.h index d0ed14ddbdc..91916d4c8ad 100755 --- a/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.h +++ b/mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.h @@ -68,6 +68,7 @@ struct BuildConstantsStruct { PKIX_RevocationChecker *revChecker; PKIX_PL_AIAMgr *aiaMgr; PKIX_Boolean useAIAForCertFetching; + PKIX_Boolean trustOnlyUserAnchors; }; struct PKIX_ForwardBuilderStateStruct{ diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c index 0051f0dbf63..147e03de2c1 100644 --- a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c +++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c @@ -3315,7 +3315,7 @@ PKIX_PL_Cert_IsCertTrusted( PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED); } - if (trustOnlyUserAnchors) { + if (trustOnlyUserAnchors || cert->isUserTrustAnchor) { /* discard our |trusted| value since we are using the anchors */ *pTrusted = cert->isUserTrustAnchor; goto cleanup; diff --git a/mozilla/security/nss/tests/chains/chains.sh b/mozilla/security/nss/tests/chains/chains.sh index 5d56f6375cd..650215e4041 100644 --- a/mozilla/security/nss/tests/chains/chains.sh +++ b/mozilla/security/nss/tests/chains/chains.sh @@ -790,6 +790,7 @@ revoke_cert() # FETCH - fetch flag (used with AIA extension) # POLICY - list of policies # TRUST - trust anchor +# TRUST_AND_DB - Examine both trust anchors and the cert db for trust # VERIFY - list of certificates to use as vfychain parameters # EXP_RESULT - expected result # REV_OPTS - revocation options @@ -806,6 +807,7 @@ verify_cert() TRUST_OPT= VFY_CERTS= VFY_LIST= + TRUST_AND_DB_OPT= if [ -n "${DB}" ]; then DB_OPT="-d ${DB}" @@ -819,6 +821,10 @@ verify_cert() fi fi + if [ -n "${TRUST_AND_DB}" ]; then + TRUST_AND_DB_OPT="-T" + fi + for ITEM in ${POLICY}; do POLICY_OPT="${POLICY_OPT} -o ${ITEM}" done @@ -851,8 +857,8 @@ verify_cert() fi done - VFY_OPTS_TNAME="${REV_OPTS} ${DB_OPT} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${TRUST_OPT}" - VFY_OPTS_ALL="${DB_OPT} -pp -vv ${REV_OPTS} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${VFY_CERTS} ${TRUST_OPT}" + VFY_OPTS_TNAME="${TRUST_AND_DB_OPT} ${REV_OPTS} ${DB_OPT} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${TRUST_OPT}" + VFY_OPTS_ALL="${DB_OPT} -pp -vv ${TRUST_AND_DB_OPT} ${REV_OPTS} ${FETCH_OPT} ${USAGE_OPT} ${POLICY_OPT} ${VFY_CERTS} ${TRUST_OPT}" TESTNAME="Verifying certificate(s) ${VFY_LIST} with flags ${VFY_OPTS_TNAME}" echo "${SCRIPTNAME}: ${TESTNAME}" @@ -1045,6 +1051,7 @@ parse_config() "verify") VERIFY="${VALUE}" TRUST= + TRUST_AND_DB= POLICY= FETCH= EXP_RESULT= @@ -1064,6 +1071,9 @@ parse_config() "trust") TRUST="${TRUST} ${VALUE}" ;; + "trust_and_db") + TRUST_AND_DB=1 + ;; "fetch") FETCH=1 ;; diff --git a/mozilla/security/nss/tests/chains/scenarios/scenarios b/mozilla/security/nss/tests/chains/scenarios/scenarios index f3cd2beef6a..3eda34fd72c 100644 --- a/mozilla/security/nss/tests/chains/scenarios/scenarios +++ b/mozilla/security/nss/tests/chains/scenarios/scenarios @@ -19,6 +19,7 @@ # # Contributor(s): # Slavomir Katuscak , Sun Microsystems +# Ryan Sleevi , Google # # 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 @@ -51,3 +52,4 @@ dsa.cfg revoc.cfg ocsp.cfg crldp.cfg +trustanchors.cfg diff --git a/mozilla/security/nss/tests/chains/scenarios/trustanchors.cfg b/mozilla/security/nss/tests/chains/scenarios/trustanchors.cfg new file mode 100644 index 00000000000..db18990ac6e --- /dev/null +++ b/mozilla/security/nss/tests/chains/scenarios/trustanchors.cfg @@ -0,0 +1,114 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +scenario TrustAnchors + +entity RootCA + type Root + +entity CA1 + type Intermediate + issuer RootCA + +entity CA2 + type Intermediate + issuer CA1 + +entity EE1 + type EE + issuer CA2 + +entity OtherRoot + type Root + +entity OtherIntermediate + type Intermediate + issuer OtherRoot + +entity EE2 + type EE + issuer OtherIntermediate + +# Scenarios where trust only comes from the DB +db DBOnly + +import RootCA::CT,C,C +import CA1:RootCA: + +# Simple chaining - no trust anchors +verify EE1:CA2 + cert CA2:CA1 + result pass + +# Simple trust anchors - ignore the Cert DB +verify EE1:CA2 + trust CA2:CA1 + result pass + +# Redundant trust - trust anchor and DB +verify EE1:CA2 + cert CA2:CA1 + trust RootCA + result pass + + +# Scenarios where trust only comes from trust anchors +db TrustOnly + +# Simple checking - direct trust anchor +verify EE1:CA2 + cert CA2:CA1 + cert CA1:RootCA: + trust RootCA: + result pass + +# Partial chain (not self-signed), with a trust anchor +verify EE1:CA2 + trust CA2:CA1 + result pass + + +# Scenarios where trust comes from both trust anchors and the DB +db TrustAndDB + +import RootCA::CT,C,C +import CA1:RootCA: + +# Check that trust in the DB works +verify EE1:CA2 + cert CA2:CA1 + result pass + +# Check that trust anchors work +verify EE2:OtherIntermediate + cert OtherIntermediate:OtherRoot + trust OtherRoot: + result pass + +# Check that specifying a trust anchor still allows searching the cert DB +verify EE1:CA2 + trust_and_db + cert CA2:CA1 + trust OtherIntermediate:OtherRoot + trust OtherRoot: + result pass + +# Scenarios where the trust DB has explicitly distrusted one or more certs, +# even when the trust anchors indicate trust +db ExplicitDistrust + +import RootCA::CT,C,C +import CA1:RootCA:p,p,p +import OtherRoot::p,p,p + +# Verify that a distrusted intermediate, but trusted root, is rejected. +verify EE1:CA2 + cert CA2:CA1 + trust CA1:RootCA + result fail + +# Verify that a trusted intermediate, but distrusted root, is accepted. +verify EE2:OtherIntermediate + trust OtherIntermediate:OtherRoot + result pass