BUG 816853: Add support for trusting the union of explicit trust anchors and

the trust DB.
r=rrelyea


git-svn-id: svn://10.0.0.236/trunk@264625 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ryan.sleevi%gmail.com
2013-01-07 03:56:15 +00:00
parent 6b4a303df9
commit 4eac635e00
12 changed files with 286 additions and 13 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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:

View File

@@ -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)
*/

View File

@@ -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 */

View File

@@ -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

View File

@@ -68,6 +68,7 @@ struct BuildConstantsStruct {
PKIX_RevocationChecker *revChecker;
PKIX_PL_AIAMgr *aiaMgr;
PKIX_Boolean useAIAForCertFetching;
PKIX_Boolean trustOnlyUserAnchors;
};
struct PKIX_ForwardBuilderStateStruct{

View File

@@ -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;

View File

@@ -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
;;

View File

@@ -19,6 +19,7 @@
#
# Contributor(s):
# Slavomir Katuscak <slavomir.katuscak@sun.com>, Sun Microsystems
# Ryan Sleevi <ryan.sleevi@gmail.com>, 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

View File

@@ -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