bug 284531 Design new interfaces for certificate path building and verification for libPKIX
patch by stevep review by rrelyea. git-svn-id: svn://10.0.0.236/trunk@236687 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
76fab5eb65
commit
d2cf075703
@ -37,7 +37,7 @@
|
||||
/*
|
||||
* cert.h - public data structures and prototypes for the certificate library
|
||||
*
|
||||
* $Id: cert.h,v 1.60 2007-09-07 18:45:51 neil.williams%sun.com Exp $
|
||||
* $Id: cert.h,v 1.61 2007-09-25 23:48:02 rrelyea%redhat.com Exp $
|
||||
*/
|
||||
|
||||
#ifndef _CERT_H_
|
||||
@ -1596,6 +1596,31 @@ CERT_EncodeNoticeReference(PRArenaPool *arena,
|
||||
CERTNoticeReference *reference,
|
||||
SECItem *dest);
|
||||
|
||||
|
||||
/*
|
||||
* Verify a Cert with libpkix
|
||||
* paramsIn control the verification options. If a value isn't specified
|
||||
* in paramsIn, it reverts to the application default.
|
||||
* paramsOut specifies the parameters the caller would like to get back.
|
||||
* the caller may pass NULL, in which case no parameters are returned.
|
||||
*/
|
||||
extern SECStatus CERT_PKIXVerifyCert(
|
||||
CERTCertificate *cert,
|
||||
SECCertificateUsage usages,
|
||||
CERTValInParam *paramsIn,
|
||||
CERTValOutParam *paramsOut,
|
||||
void *wincx);
|
||||
/*
|
||||
* This function changes the application defaults for the Verify function.
|
||||
* It should be called once at app initialization time, and only changes
|
||||
* if the default configuration changes.
|
||||
*
|
||||
* This changes the default values for the parameters specified. These
|
||||
* defaults can be overridden in CERT_PKIXVerifyCert() by explicitly
|
||||
* setting the value in paramsIn.
|
||||
*/
|
||||
extern SECStatus CERT_PKIXSetDefaults(CERTValInParam *paramsIn);
|
||||
|
||||
SEC_END_PROTOS
|
||||
|
||||
#endif /* _CERT_H_ */
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
/*
|
||||
* certt.h - public data structures for the certificate library
|
||||
*
|
||||
* $Id: certt.h,v 1.38 2007-08-29 21:59:05 nelson%bolyard.com Exp $
|
||||
* $Id: certt.h,v 1.39 2007-09-25 23:48:02 rrelyea%redhat.com Exp $
|
||||
*/
|
||||
#ifndef _CERTT_H_
|
||||
#define _CERTT_H_
|
||||
@ -886,6 +886,197 @@ typedef struct {
|
||||
SECItem inhibitMappingSkipCerts;
|
||||
} CERTCertificatePolicyConstraints;
|
||||
|
||||
|
||||
/*
|
||||
* these types are for the CERT_PKIX* Verification functions
|
||||
* These are all optional parameters.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
cert_pi_end = 0, /* SPECIAL: signifies end of array of
|
||||
* CERTValParam* */
|
||||
cert_pi_nbioContext = 1, /* specify a non-blocking IO context used to
|
||||
* resume a session. If this argument is
|
||||
* specified, no other arguments should be.
|
||||
* Specified in value.pointer.p. If the
|
||||
* operation completes the context will be
|
||||
* freed. */
|
||||
cert_pi_nbioAbort = 2, /* specify a non-blocking IO context for an
|
||||
* existing operation which the caller wants
|
||||
* to abort. If this argument is
|
||||
* specified, no other arguments should be.
|
||||
* Specified in value.pointer.p. If the
|
||||
* operation succeeds the context will be
|
||||
* freed. */
|
||||
cert_pi_certList = 3, /* specify the chain to validate against. If
|
||||
* this value is given, then the path
|
||||
* construction step in the validation is
|
||||
* skipped. Specified in value.pointer.chain */
|
||||
cert_pi_policyOID = 4, /* validate certificate for policy OID.
|
||||
* Specified in value.array.oids. Cert must
|
||||
* be good for at least one OID in order
|
||||
* to validate. Default is no policyOID */
|
||||
cert_pi_policyFlags = 5, /* flags for each policy specified in policyOID.
|
||||
* Specified in value.scalar.ul. Policy flags
|
||||
* apply to all specified oids.
|
||||
* Use CERT_POLICY_FLAG_* macros below. If not
|
||||
* specified policy flags default to 0 */
|
||||
cert_pi_keyusage = 6, /* specify what the keyusages the certificate
|
||||
* will be evaluated against, specified in
|
||||
* value.scalar.ui. The cert must validate for
|
||||
* at least one of the specified key usages.
|
||||
* Values match the KU_ bit flags defined
|
||||
* in this file. Default is derived from
|
||||
* the 'usages' function argument */
|
||||
cert_pi_extendedKeyusage= 7, /* specify what the required extended key
|
||||
* usage of the certificate. Specified as
|
||||
* an array of oidTags in value.array.oids.
|
||||
* The cert must validate for at least one
|
||||
* of the specified extended key usages.
|
||||
* If not specified, no extended key usages
|
||||
* will be checked. */
|
||||
cert_pi_date = 8, /* validate certificate is valid as of date
|
||||
* specified in value.scalar.time. A special
|
||||
* value '0' indicates 'now'. default is '0' */
|
||||
cert_pi_revocationFlags = 9, /* Specify what revocation checking to do.
|
||||
* See CERT_REV_FLAG_* macros below
|
||||
* Set in value.scalar.ul */
|
||||
cert_pi_certStores = 10,/* Bitmask of Cert Store flags (see below)
|
||||
* Set in value.scalar.ui */
|
||||
|
||||
cert_pi_max /* SPECIAL: signifies maximum allowed value,
|
||||
* can increase in future releases */
|
||||
} CERTValParamInType;
|
||||
|
||||
/*
|
||||
* for all out parameters:
|
||||
* out parameters are only returned if the caller asks for them in
|
||||
* the CERTValOutParam array. Caller is responsible for the CERTValOutParam
|
||||
* array itself. The pkix verify function will allocate and other arrays
|
||||
* pointers, or objects. The Caller is responsible for freeing those results.
|
||||
* If SECWouldBlock is returned, only cert_pi_nbioContext is returned.
|
||||
*/
|
||||
typedef enum {
|
||||
cert_po_end = 0, /* SPECIAL: signifies end of array of
|
||||
* CERTValParam* */
|
||||
cert_po_nbioContext = 1, /* Return a nonblocking context. If no
|
||||
* non-blocking context is specified, then
|
||||
* blocking IO will be used.
|
||||
* Returned in value.pointer.p. The context is
|
||||
* freed after an abort or a complete operation.
|
||||
* This value is only returned on SECWouldBlock.
|
||||
*/
|
||||
cert_po_trustAnchor = 2, /* Return the trust anchor for the chain that
|
||||
* was validated. Returned in
|
||||
* value.pointer.cert, this value is only
|
||||
* returned on SECSuccess. */
|
||||
cert_po_certList = 3, /* Return the entire chain that was validated.
|
||||
* Returned in value.pointer.certList. If no
|
||||
* chain could be constructed, this value
|
||||
* would be NULL. */
|
||||
cert_po_policyOID = 4, /* Return the policies that were found to be
|
||||
* valid. Returned in value.array.oids as an
|
||||
* array. This is only returned on
|
||||
* SECSuccess. */
|
||||
cert_po_errorLog = 5, /* Return a log of problems with the chain.
|
||||
* Returned in value.pointer.log */
|
||||
cert_po_usages = 6, /* Return what usages the certificate is valid
|
||||
for. Returned in value.scalar.usages */
|
||||
cert_po_keyUsage = 7, /* Return what key usages the certificate
|
||||
* is valid for.
|
||||
* Returned in value.scalar.usage */
|
||||
cert_po_extendedKeyusage= 8, /* Return what extended key usages the
|
||||
* certificate is valid for.
|
||||
* Returned in value.array.oids */
|
||||
cert_po_max /* SPECIAL: signifies maximum allowed value,
|
||||
* can increase in future releases */
|
||||
|
||||
} CERTValParamOutType;
|
||||
|
||||
typedef struct CERTValParamInValueStr {
|
||||
union {
|
||||
PRBool b;
|
||||
PRInt32 i;
|
||||
PRUint32 ui;
|
||||
PRInt64 l;
|
||||
PRUint64 ul;
|
||||
PRTime time;
|
||||
} scalar;
|
||||
union {
|
||||
const void* p;
|
||||
const char* s;
|
||||
const CERTCertificate* cert;
|
||||
const CERTCertList *chain;
|
||||
} pointer;
|
||||
union {
|
||||
const PRInt32 *pi;
|
||||
const PRUint32 *pui;
|
||||
const PRInt64 *pl;
|
||||
const PRUint64 *pul;
|
||||
const SECOidTag *oids;
|
||||
} array;
|
||||
int arraySize;
|
||||
} CERTValParamInValue;
|
||||
|
||||
|
||||
typedef struct CERTValParamOutValueStr {
|
||||
union {
|
||||
PRBool b;
|
||||
PRInt32 i;
|
||||
PRUint32 ui;
|
||||
PRInt64 l;
|
||||
PRUint64 ul;
|
||||
SECCertificateUsage usages;
|
||||
} scalar;
|
||||
union {
|
||||
void* p;
|
||||
char* s;
|
||||
CERTVerifyLog *log;
|
||||
CERTCertificate* cert;
|
||||
CERTCertList *chain;
|
||||
} pointer;
|
||||
union {
|
||||
void *p;
|
||||
SECOidTag *oids;
|
||||
} array;
|
||||
int arraySize;
|
||||
} CERTValParamOutValue;
|
||||
|
||||
typedef struct {
|
||||
CERTValParamInType type;
|
||||
CERTValParamInValue value;
|
||||
} CERTValInParam;
|
||||
|
||||
typedef struct {
|
||||
CERTValParamOutType type;
|
||||
CERTValParamOutValue value;
|
||||
} CERTValOutParam;
|
||||
|
||||
/*
|
||||
* policy flag defines
|
||||
*/
|
||||
#define CERT_POLICY_FLAG_NO_MAPPING 1
|
||||
#define CERT_POLICY_FLAG_EXPLICIT 2
|
||||
#define CERT_POLICY_FLAG_NO_ANY 4
|
||||
|
||||
/*
|
||||
* revocation flags
|
||||
*/
|
||||
#define CERT_REV_FLAG_OCSP 1
|
||||
#define CERT_REV_FLAG_OCSP_LEAF_ONLY 2
|
||||
#define CERT_REV_FLAG_CRL 4
|
||||
#define CERT_REV_FLAG_CRL_LEAF_ONLY 8
|
||||
/* set if we don't want to fail because we were unable to get revocation
|
||||
* data */
|
||||
#define CERT_REV_FAIL_SOFT 0x10
|
||||
#define CERT_REV_NIST (CERT_REV_FLAG_OCSP|CERT_REV_FLAG_CRL)
|
||||
|
||||
/*
|
||||
* CertStore flags
|
||||
*/
|
||||
#define CERT_ENABLE_LDAP_FETCH 1
|
||||
#define CERT_ENABLE_HTTP_FETCH 2
|
||||
|
||||
/* XXX Lisa thinks the template declarations belong in cert.h, not here? */
|
||||
|
||||
#include "secasn1t.h" /* way down here because I expect template stuff to
|
||||
|
||||
@ -45,6 +45,10 @@
|
||||
#include "certdb.h"
|
||||
#include "certi.h"
|
||||
#include "cryptohi.h"
|
||||
#include "pkix.h"
|
||||
/*#include "pkix_sample_modules.h" */
|
||||
#include "pkix_pl_cert.h"
|
||||
|
||||
|
||||
#ifndef NSS_3_4_CODE
|
||||
#define NSS_3_4_CODE
|
||||
@ -55,7 +59,6 @@
|
||||
#include "pki3hack.h"
|
||||
#include "base.h"
|
||||
|
||||
|
||||
/*
|
||||
* Check the validity times of a certificate
|
||||
*/
|
||||
@ -2059,3 +2062,595 @@ CERT_GetCertChainFromCert(CERTCertificate *cert, int64 time, SECCertUsage usage)
|
||||
PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PKIX_CertSelector *
|
||||
cert_GetTargetCertConstraints(CERTCertificate *target, void *plContext)
|
||||
{
|
||||
PKIX_ComCertSelParams *certSelParams = NULL;
|
||||
PKIX_CertSelector *certSelector = NULL;
|
||||
PKIX_CertSelector *r= NULL;
|
||||
PKIX_PL_Cert *eeCert = NULL;
|
||||
PKIX_Error *error = NULL;
|
||||
|
||||
pkix_pl_Cert_CreateWithNSSCert
|
||||
(target, &eeCert, plContext);
|
||||
|
||||
|
||||
error = PKIX_ComCertSelParams_Create(&certSelParams, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_ComCertSelParams_SetCertificate(
|
||||
certSelParams, eeCert, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_CertSelector_SetCommonCertSelectorParams
|
||||
(certSelector, certSelParams, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certSelParams, plContext);
|
||||
if (error == NULL) r = certSelParams;
|
||||
|
||||
cleanup:
|
||||
if (certSelParams != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelParams, plContext);
|
||||
|
||||
if (eeCert != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)eeCert, plContext);
|
||||
|
||||
if (certSelParams != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelParams, plContext);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
PKIX_List *
|
||||
CERT_GetCertStores(void *plContext)
|
||||
{
|
||||
PKIX_CertStore *certStore = NULL;
|
||||
PKIX_List *certStores = NULL;
|
||||
PKIX_List *r = NULL;
|
||||
PKIX_Error *error = NULL;
|
||||
|
||||
error = PKIX_PL_Pk11CertStore_Create(&certStore, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_List_Create(&certStores, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_List_AppendItem( certStores,
|
||||
(PKIX_PL_Object *)certStore, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certStores, plContext);
|
||||
if (error == NULL) r = certStores;
|
||||
|
||||
cleanup:
|
||||
if (certStores != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStores, plContext);
|
||||
|
||||
if (certStore != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStore, plContext);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* XXX
|
||||
* There is no NSS SECItem -> PKIX OID
|
||||
* conversion function. For now, I go via the ascii
|
||||
* representation
|
||||
* this should be in PKIX_PL_*
|
||||
*/
|
||||
|
||||
PKIX_PL_OID *
|
||||
CERT_PKIXOIDFromNSSOid(SECOidTag tag, void*plContext)
|
||||
{
|
||||
char *oidstring = NULL;
|
||||
char *oidstring_adj = NULL;
|
||||
PKIX_PL_OID *policyOID = NULL;
|
||||
SECOidData *data;
|
||||
|
||||
data = SECOID_FindOIDByTag(tag);
|
||||
if (data != NULL) {
|
||||
oidstring = CERT_GetOidString(&data->oid);
|
||||
if (oidstring == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
oidstring_adj = oidstring;
|
||||
if (PORT_Strncmp("OID.",oidstring_adj,4) == 0) {
|
||||
oidstring_adj += 4;
|
||||
}
|
||||
|
||||
PKIX_PL_OID_Create(oidstring_adj, &policyOID, plContext);
|
||||
}
|
||||
cleanup:
|
||||
if (oidstring != NULL) PR_smprintf_free(oidstring);
|
||||
|
||||
return policyOID;
|
||||
}
|
||||
|
||||
|
||||
struct fake_PKIX_PL_CertStruct {
|
||||
CERTCertificate *nssCert;
|
||||
};
|
||||
|
||||
/* This needs to be part of the PKIX_PL_* */
|
||||
/* This definitely needs to go away, and be replaced with
|
||||
a real accessor function in PKIX */
|
||||
CERTCertificate *
|
||||
cert_NSSCertFromPKIXCert(const PKIX_PL_Cert *pkix_cert, void *plContext)
|
||||
{
|
||||
struct fake_PKIX_PL_CertStruct *fcert = NULL;
|
||||
|
||||
fcert = (struct fake_PKIX_PL_CertStruct*)pkix_cert;
|
||||
|
||||
return CERT_DupCertificate(fcert->nssCert);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PKIX_List *cert_PKIXMakeOIDList(const SECOidTag *oids, int oidCount, void *plContext)
|
||||
{
|
||||
PKIX_List *r = NULL;
|
||||
PKIX_List *policyList = NULL;
|
||||
PKIX_PL_OID *policyOID = NULL;
|
||||
PKIX_Error *error = NULL;
|
||||
int i;
|
||||
|
||||
PKIX_List_Create(&policyList, plContext);
|
||||
|
||||
for (i=0; i<oidCount; i++) {
|
||||
policyOID = CERT_PKIXOIDFromNSSOid(oids[i],plContext);
|
||||
if (policyOID == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
error = PKIX_List_AppendItem(policyList,
|
||||
(PKIX_PL_Object *)policyOID, plContext);
|
||||
if (error != NULL) {
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOID, plContext);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
error = PKIX_List_SetImmutable(policyList, plContext);
|
||||
if (error != NULL) goto cleanup;
|
||||
|
||||
error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)policyList, plContext);
|
||||
if (error == NULL) r = policyList;
|
||||
|
||||
cleanup:
|
||||
if (policyList != NULL) {
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyList, plContext);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
CERTValOutParam *
|
||||
cert_pkix_FindOutputParam(const CERTValOutParam *params, const CERTValParamOutType t)
|
||||
{
|
||||
CERTValOutParam *i;
|
||||
if (params == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (i = params; i->type != cert_po_end; i++) {
|
||||
if (i->type == t) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SECStatus
|
||||
cert_pkixSetParam(PKIX_ProcessingParams *procParams,
|
||||
const CERTValInParam *param, void *plContext)
|
||||
{
|
||||
PKIX_Error * error = NULL;
|
||||
SECStatus r=SECSuccess;
|
||||
PKIX_PL_Date *d = NULL;
|
||||
PKIX_List *policyOIDList = NULL;
|
||||
|
||||
/* XXX we need a way to map generic PKIX error to generic NSS errors */
|
||||
|
||||
switch (param->type) {
|
||||
|
||||
case cert_pi_policyOID:
|
||||
|
||||
/* needed? */
|
||||
error = PKIX_ProcessingParams_SetExplicitPolicyRequired(
|
||||
procParams, PKIX_TRUE, plContext);
|
||||
|
||||
if (error != NULL) {
|
||||
r = SECFailure;
|
||||
break;
|
||||
}
|
||||
|
||||
policyOIDList = cert_PKIXMakeOIDList(param->value.array.oids,
|
||||
param->value.arraySize,plContext);
|
||||
|
||||
error = PKIX_ProcessingParams_SetInitialPolicies(
|
||||
procParams,policyOIDList,plContext);
|
||||
if (error != NULL) {
|
||||
r = SECFailure;
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
break;
|
||||
|
||||
case cert_pi_date:
|
||||
if (param->value.scalar.time == 0) {
|
||||
error = PKIX_PL_Date_Create_UTCTime(NULL, &d, plContext);
|
||||
} else {
|
||||
error = pkix_pl_Date_CreateFromPRTime( param->value.scalar.time,
|
||||
&d, plContext);
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_TIME);
|
||||
r = SECFailure;
|
||||
}
|
||||
}
|
||||
|
||||
error = PKIX_ProcessingParams_SetDate( procParams, d, plContext );
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_TIME);
|
||||
r = SECFailure;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case cvpt_revCheckRequired:
|
||||
error = PKIX_ProcessingParams_SetRevocationEnabled(
|
||||
procParams, param->value.b?PKIX_TRUE:PKIX_FALSE, plContext);
|
||||
|
||||
if (error != NULL) r = SECFailure;
|
||||
break;
|
||||
*/
|
||||
|
||||
default:
|
||||
r = SECFailure;
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
if (policyOIDList != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOIDList, plContext);
|
||||
|
||||
if (d != NULL) PKIX_PL_Object_DecRef((PKIX_PL_Object *)d, plContext);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
#define EV_TEST_HACK 1
|
||||
#ifdef EV_TEST_HACK
|
||||
|
||||
/* This function checks if the certificate asserts the given policy oid.
|
||||
* It does not check if the certificate is authorized to assert that oid.
|
||||
*
|
||||
* This function is mainly here for testing purposes, to support the
|
||||
* EV_HACK_INSECURE_OID_CHECK mode.
|
||||
*
|
||||
*/
|
||||
|
||||
SECStatus
|
||||
cert_hasPolicy(CERTCertificate *cert, SECOidTag tag)
|
||||
{
|
||||
SECStatus r=SECFailure;
|
||||
SECStatus rv=SECFailure;
|
||||
SECItem policyItem = {siBuffer,0};
|
||||
CERTPolicyInfo **cpi=NULL;
|
||||
CERTCertificatePolicies *policyExt = NULL;
|
||||
SECOidTag tagincert;
|
||||
|
||||
|
||||
rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
|
||||
&policyItem);
|
||||
if (rv != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
policyExt = CERT_DecodeCertificatePoliciesExtension(&policyItem);
|
||||
if (policyExt == NULL) goto loser;
|
||||
|
||||
for (cpi = policyExt->policyInfos; *cpi; cpi++) {
|
||||
tagincert = SECOID_FindOIDTag(&(*cpi)->policyID);
|
||||
if (tagincert == tag) {
|
||||
r = SECSuccess;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loser:
|
||||
if (policyExt != NULL) CERT_DestroyCertificatePoliciesExtension(policyExt);
|
||||
if (policyItem.data) PORT_Free(policyItem.data);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* determine which EV test mode we are in by reading an environment variable
|
||||
* 'NSS_EV_TEST_HACK'.
|
||||
*/
|
||||
#define EV_HACK_ALWAYS_FAIL 0
|
||||
#define EV_HACK_USE_PKIX 1
|
||||
#define EV_HACK_INSECURE_OID_CHECK 2
|
||||
|
||||
int cert_GetEVMode()
|
||||
{
|
||||
static int firsttime = 1;
|
||||
static char *mode_string = NULL;
|
||||
static int mode = EV_HACK_ALWAYS_FAIL;
|
||||
|
||||
if (firsttime) {
|
||||
firsttime = 0;
|
||||
#if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
|
||||
mode_string = getenv("NSS_EV_TEST_HACK");
|
||||
#endif
|
||||
if (mode_string != NULL) {
|
||||
if (PORT_Strcmp(mode_string, "ALWAYS_FAIL") == 0) {
|
||||
mode = EV_HACK_ALWAYS_FAIL;
|
||||
} else if (PORT_Strcmp(mode_string, "USE_PKIX") == 0) {
|
||||
mode = EV_HACK_USE_PKIX;
|
||||
} else if (PORT_Strcmp(mode_string, "INSECURE_OID_CHECK") == 0) {
|
||||
mode = EV_HACK_INSECURE_OID_CHECK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* CERT_PKIXVerifyCert
|
||||
*
|
||||
* Verify a Certificate using the PKIX library.
|
||||
*
|
||||
* Parameters:
|
||||
* cert - the target certificate to verify. Must be non-null
|
||||
* params - an array of type/value parameters which can be
|
||||
* used to modify the behavior of the validation
|
||||
* algorithm, or supply additional constraints.
|
||||
*
|
||||
* outputTrustAnchor - the trust anchor which the certificate
|
||||
* chains to. The caller is responsible
|
||||
* for freeing this.
|
||||
*
|
||||
* Example Usage:
|
||||
* CERTValParam args[3];
|
||||
* args[0].type = cvpt_policyOID;
|
||||
* args[0].value.si = oid;
|
||||
* args[1].type = revCheckRequired;
|
||||
* args[1].value.b = PR_TRUE;
|
||||
* args[2].type = cvpt_end;
|
||||
*
|
||||
* CERT_PKIXVerifyCert(cert, &output, args
|
||||
*
|
||||
*
|
||||
* NOTE: Currently, the behavior of this function can be modified
|
||||
* to allow for testing, using the environment variable
|
||||
* 'NSS_EV_TEST_HACK'. This variable can have the following values,
|
||||
*
|
||||
* ALWAYS_FAIL - always returns SECFailure (default)
|
||||
*
|
||||
* INSECURE_OID_CHECK - do no validation, just check if the
|
||||
* target cert has the policy OID, if
|
||||
* specified
|
||||
*
|
||||
* USE_PKIX - use PKIX calls, validating the full chain
|
||||
*
|
||||
*/
|
||||
SECStatus CERT_PKIXVerifyCert(
|
||||
CERTCertificate *cert,
|
||||
SECCertificateUsage usages,
|
||||
CERTValInParam *paramsIn,
|
||||
CERTValOutParam *paramsOut,
|
||||
void *wincx)
|
||||
{
|
||||
SECStatus r = SECFailure;
|
||||
PKIX_List * anchors = NULL;
|
||||
PKIX_Error * error = NULL;
|
||||
PKIX_ProcessingParams *procParams = NULL;
|
||||
PKIX_BuildResult * buildResult = NULL;
|
||||
void * nbioContext = NULL; /* for non-blocking IO */
|
||||
void * buildState = NULL; /* for non-blocking IO */
|
||||
PKIX_CertSelector * certSelector = NULL;
|
||||
PKIX_List * certStores = NULL;
|
||||
PKIX_ValidateResult * valResult = NULL;
|
||||
PKIX_TrustAnchor * trustAnchor = NULL;
|
||||
PKIX_PL_Cert * trustAnchorCert = NULL;
|
||||
CERTValInParam * param = NULL;
|
||||
CERTValOutParam * oparam = NULL;
|
||||
int mode = EV_HACK_ALWAYS_FAIL;
|
||||
int i=0;
|
||||
|
||||
void *plContext = NULL;
|
||||
|
||||
#ifdef EV_TEST_HACK
|
||||
|
||||
/* XXX - check temporary env variable - this needs to go away */
|
||||
mode = cert_GetEVMode();
|
||||
|
||||
if (mode == EV_HACK_ALWAYS_FAIL) {
|
||||
/* this error is probably too generic - need to create specific
|
||||
policy error codes */
|
||||
PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* XXX This needs to go away */
|
||||
if (mode == EV_HACK_INSECURE_OID_CHECK) {
|
||||
if (paramsIn != NULL) {
|
||||
for (i=0; paramsIn[i].type != cert_pi_end; i++) {
|
||||
if (paramsIn[i].type == cert_pi_policyOID) {
|
||||
param = ¶msIn[i];
|
||||
}
|
||||
}
|
||||
if (param == NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
for (i=0; i<param->value.arraySize; i++) {
|
||||
if (cert_hasPolicy(cert,param->value.array.oids[i]) == SECSuccess) {
|
||||
CERTCertList *certChain = NULL;
|
||||
CERTCertListNode *node = NULL;
|
||||
CERTCertListNode *next_node = NULL;
|
||||
|
||||
oparam = cert_pkix_FindOutputParam(paramsOut, cert_po_trustAnchor);
|
||||
if (oparam != NULL) {
|
||||
certChain = CERT_GetCertChainFromCert(cert, PR_Now(),
|
||||
usages);
|
||||
for (node = CERT_LIST_HEAD(certChain);
|
||||
!CERT_LIST_END(node, certChain);
|
||||
node = next_node) {
|
||||
next_node = CERT_LIST_NEXT(node);
|
||||
if (CERT_LIST_END(next_node, certChain)) {
|
||||
/* We arrived at the top level cert */
|
||||
oparam->value.pointer.cert =
|
||||
CERT_DupCertificate(node->cert);
|
||||
}
|
||||
}
|
||||
CERT_DestroyCertList(certChain);
|
||||
}
|
||||
r = SECSuccess;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != EV_HACK_USE_PKIX) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* From this point on, we are going to do a PKIX validation */
|
||||
|
||||
error = PKIX_PL_NssContext_Create(
|
||||
0, PR_FALSE /*use arena*/, wincx, &plContext);
|
||||
if (error != NULL) { /* need pkix->nss error map */
|
||||
PORT_SetError(SEC_ERROR_CERT_NOT_VALID);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* The 'anchors' parameter must be supplied, but it can be an
|
||||
empty list. PKIX will use the NSS trust database to form
|
||||
the anchors list */
|
||||
PKIX_List_Create(&anchors, plContext);
|
||||
error = PKIX_ProcessingParams_Create(anchors, &procParams, plContext);
|
||||
if (error != NULL) { /* need pkix->nss error map */
|
||||
PORT_SetError(SEC_ERROR_CERT_NOT_VALID);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* now process the extensible input parameters structure */
|
||||
if (paramsIn != NULL) {
|
||||
i=0;
|
||||
while (paramsIn[i].type != cert_pi_end) {
|
||||
if (paramsIn[i].type >= cert_pi_max) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
if (cert_pkixSetParam(procParams,
|
||||
¶msIn[i],plContext) != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto cleanup;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
certSelector = cert_GetTargetCertConstraints(cert, plContext);
|
||||
error = PKIX_ProcessingParams_SetTargetCertConstraints
|
||||
(procParams, certSelector, plContext);
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_IO); /* need pkix->nss error map */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
certStores = CERT_GetCertStores(plContext);
|
||||
error = PKIX_ProcessingParams_SetCertStores
|
||||
(procParams, certStores, plContext);
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_IO); /* need pkix->nss error map */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error = PKIX_BuildChain( procParams, &nbioContext,
|
||||
&buildState, &buildResult, NULL,
|
||||
plContext);
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_IO); /* need pkix->nss error map */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error = PKIX_BuildResult_GetValidateResult( buildResult, &valResult,
|
||||
plContext);
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_IO); /* need pkix->nss error map */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error = PKIX_ValidateResult_GetTrustAnchor( valResult, &trustAnchor,
|
||||
plContext);
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_IO); /* need pkix->nss error map */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error = PKIX_TrustAnchor_GetTrustedCert( trustAnchor, &trustAnchorCert,
|
||||
plContext);
|
||||
if (error != NULL) {
|
||||
PORT_SetError(SEC_ERROR_IO); /* need pkix->nss error map */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
oparam = cert_pkix_FindOutputParam(paramsOut, cert_po_trustAnchor);
|
||||
if (oparam != NULL) {
|
||||
oparam->value.pointer.cert =
|
||||
cert_NSSCertFromPKIXCert(trustAnchorCert,plContext);
|
||||
}
|
||||
|
||||
r = SECSuccess;
|
||||
|
||||
cleanup:
|
||||
if (procParams != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)procParams, plContext);
|
||||
|
||||
if (trustAnchorCert != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchorCert, plContext);
|
||||
|
||||
if (trustAnchor != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchor, plContext);
|
||||
|
||||
if (valResult != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)valResult, plContext);
|
||||
|
||||
if (buildResult != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)buildResult, plContext);
|
||||
|
||||
if (certStores != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStores, plContext);
|
||||
|
||||
if (certSelector != NULL)
|
||||
PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelector, plContext);
|
||||
|
||||
PKIX_PL_NssContext_Destroy(plContext);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@ -912,6 +912,7 @@ CERT_EncodeUserNotice;
|
||||
CERT_FindCRLEntryReasonExten;
|
||||
CERT_FindCRLNumberExten;
|
||||
CERT_FindNameConstraintsExten;
|
||||
CERT_PKIXVerifyCert;
|
||||
PK11_GetAllSlotsForCert;
|
||||
PK11_GenerateKeyPairWithOpFlags;
|
||||
SEC_GetRegisteredHttpClient;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user