From 252023d26e4df7674a659160766bc902b84d77ed Mon Sep 17 00:00:00 2001 From: "kaie%kuix.de" Date: Wed, 9 Jan 2008 08:23:44 +0000 Subject: [PATCH] Bug 403687, move pkix functions to certvfypkix.c, turn off EV_TEST_HACK r=rrelyea --- security/nss/lib/certhigh/certvfy.c | 683 ------------------------ security/nss/lib/certhigh/certvfypkix.c | 512 ++++++++++++++++++ 2 files changed, 512 insertions(+), 683 deletions(-) diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c index 5739862a215..fbdecce19bb 100644 --- a/security/nss/lib/certhigh/certvfy.c +++ b/security/nss/lib/certhigh/certvfy.c @@ -1986,686 +1986,3 @@ 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; - - error = PKIX_PL_Cert_CreateFromCERTCertificate(target, &eeCert, plContext); - if (error != NULL) goto cleanup; - - error = PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext); - if (error != NULL) goto cleanup; - - 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_SetCommonCertSelectorParams - (certSelector, certSelParams, plContext); - if (error != NULL) goto cleanup; - - error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certSelector, plContext); - if (error == NULL) r = certSelector; - -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 (certSelector != NULL) - PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelector, 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; itype != 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 *date = NULL; - PKIX_List *policyOIDList = NULL; - PKIX_RevocationChecker *ocspChecker = NULL; - PRUint64 flags; - - /* 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, &date, plContext); - } else { - error = pkix_pl_Date_CreateFromPRTime(param->value.scalar.time, - &date, plContext); - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_TIME); - r = SECFailure; - break; - } - } - - error = PKIX_ProcessingParams_SetDate(procParams, date, plContext); - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_TIME); - r = SECFailure; - } - - case cert_pi_revocationFlags: - flags = param->value.scalar.ul; - if (((flags & CERT_REV_FLAG_OCSP) == 0) || - (flags & CERT_REV_FLAG_OCSP_LEAF_ONLY)) { - /* OCSP off either because: - * 1) we didn't turn ocsp on, or - * 2) we are only checking ocsp on the leaf cert only. - * The caller needs to handle the leaf case once we add leaf - * checking there */ - - /* currently OCSP is the only external revocation checker */ - error = PKIX_ProcessingParams_SetRevocationCheckers(procParams, - NULL, plContext); - } else { - /* OCSP is on for the whole chain */ - if (date == NULL) { - error = PKIX_ProcessingParams_GetDate - (procParams, &date, plContext ); - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_TIME); - r = SECFailure; - break; - } - } - error = PKIX_OcspChecker_Initialize(date, NULL, NULL, - &ocspChecker, plContext); - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - r = SECFailure; - break; - } - - error = PKIX_ProcessingParams_AddRevocationChecker(procParams, - ocspChecker, plContext); - PKIX_PL_Object_DecRef((PKIX_PL_Object *)ocspChecker, plContext); - ocspChecker=NULL; - - /* add CERT_REV_FLAG_FAIL_SOFT_OCSP when underlying pkix - * supports it */ - } - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - r = SECFailure; - break; - } - if (((flags & CERT_REV_FLAG_CRL) == 0) || - (flags & CERT_REV_FLAG_CRL_LEAF_ONLY)) { - /* CRL checking is off either because: - * 1) we didn't turn crl checking on, or - * 2) we are only checking crls on the leaf cert only. - * The caller needs to handle the leaf case once we add leaf - * checking there */ - - /* this function only affects the built-in CRL checker */ - error = PKIX_ProcessingParams_SetRevocationEnabled(procParams, - PKIX_FALSE, plContext); - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - r = SECFailure; - break; - } - /* make sure NIST Revocation Policy is off as well */ - error = PKIX_ProcessingParams_SetNISTRevocationPolicyEnabled - (procParams, PKIX_FALSE, plContext); - } else { - /* CRL checking is on for the whole chain */ - error = PKIX_ProcessingParams_SetRevocationEnabled(procParams, - PKIX_TRUE, plContext); - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - r = SECFailure; - break; - } - if (flags & CERT_REV_FAIL_SOFT_CRL) { - error = PKIX_ProcessingParams_SetNISTRevocationPolicyEnabled - (procParams, PKIX_FALSE, plContext); - } else { - error = PKIX_ProcessingParams_SetNISTRevocationPolicyEnabled - (procParams, PKIX_TRUE, plContext); - } - } - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - r = SECFailure; - break; - } - break; - - - default: - r = SECFailure; - PORT_SetError(SEC_ERROR_INVALID_ARGS); - } - - if (policyOIDList != NULL) - PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOIDList, plContext); - - if (date != NULL) - PKIX_PL_Object_DecRef((PKIX_PL_Object *)date, plContext); - - if (ocspChecker != NULL) - PKIX_PL_Object_DecRef((PKIX_PL_Object *)ocspChecker, 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; ivalue.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; - } - - error = pkix_pl_NssContext_SetCertUsage(usages, plContext); - if (error != NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - 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; -} - diff --git a/security/nss/lib/certhigh/certvfypkix.c b/security/nss/lib/certhigh/certvfypkix.c index ed1fe88ee57..891101431fa 100644 --- a/security/nss/lib/certhigh/certvfypkix.c +++ b/security/nss/lib/certhigh/certvfypkix.c @@ -1218,3 +1218,515 @@ cleanup: } return rv; } + +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; + + error = PKIX_PL_Cert_CreateFromCERTCertificate(target, &eeCert, plContext); + if (error != NULL) goto cleanup; + + error = PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext); + if (error != NULL) goto cleanup; + + 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_SetCommonCertSelectorParams + (certSelector, certSelParams, plContext); + if (error != NULL) goto cleanup; + + error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certSelector, plContext); + if (error == NULL) r = certSelector; + +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 (certSelector != NULL) + PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelector, 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; itype != 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 *date = NULL; + PKIX_List *policyOIDList = NULL; + PKIX_RevocationChecker *ocspChecker = NULL; + PRUint64 flags; + + /* 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, &date, plContext); + } else { + error = pkix_pl_Date_CreateFromPRTime(param->value.scalar.time, + &date, plContext); + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_TIME); + r = SECFailure; + break; + } + } + + error = PKIX_ProcessingParams_SetDate(procParams, date, plContext); + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_TIME); + r = SECFailure; + } + + case cert_pi_revocationFlags: + flags = param->value.scalar.ul; + if (((flags & CERT_REV_FLAG_OCSP) == 0) || + (flags & CERT_REV_FLAG_OCSP_LEAF_ONLY)) { + /* OCSP off either because: + * 1) we didn't turn ocsp on, or + * 2) we are only checking ocsp on the leaf cert only. + * The caller needs to handle the leaf case once we add leaf + * checking there */ + + /* currently OCSP is the only external revocation checker */ + error = PKIX_ProcessingParams_SetRevocationCheckers(procParams, + NULL, plContext); + } else { + /* OCSP is on for the whole chain */ + if (date == NULL) { + error = PKIX_ProcessingParams_GetDate + (procParams, &date, plContext ); + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_TIME); + r = SECFailure; + break; + } + } + error = PKIX_OcspChecker_Initialize(date, NULL, NULL, + &ocspChecker, plContext); + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + r = SECFailure; + break; + } + + error = PKIX_ProcessingParams_AddRevocationChecker(procParams, + ocspChecker, plContext); + PKIX_PL_Object_DecRef((PKIX_PL_Object *)ocspChecker, plContext); + ocspChecker=NULL; + + /* add CERT_REV_FLAG_FAIL_SOFT_OCSP when underlying pkix + * supports it */ + } + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + r = SECFailure; + break; + } + if (((flags & CERT_REV_FLAG_CRL) == 0) || + (flags & CERT_REV_FLAG_CRL_LEAF_ONLY)) { + /* CRL checking is off either because: + * 1) we didn't turn crl checking on, or + * 2) we are only checking crls on the leaf cert only. + * The caller needs to handle the leaf case once we add leaf + * checking there */ + + /* this function only affects the built-in CRL checker */ + error = PKIX_ProcessingParams_SetRevocationEnabled(procParams, + PKIX_FALSE, plContext); + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + r = SECFailure; + break; + } + /* make sure NIST Revocation Policy is off as well */ + error = PKIX_ProcessingParams_SetNISTRevocationPolicyEnabled + (procParams, PKIX_FALSE, plContext); + } else { + /* CRL checking is on for the whole chain */ + error = PKIX_ProcessingParams_SetRevocationEnabled(procParams, + PKIX_TRUE, plContext); + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + r = SECFailure; + break; + } + if (flags & CERT_REV_FAIL_SOFT_CRL) { + error = PKIX_ProcessingParams_SetNISTRevocationPolicyEnabled + (procParams, PKIX_FALSE, plContext); + } else { + error = PKIX_ProcessingParams_SetNISTRevocationPolicyEnabled + (procParams, PKIX_TRUE, plContext); + } + } + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + r = SECFailure; + break; + } + break; + + + default: + r = SECFailure; + PORT_SetError(SEC_ERROR_INVALID_ARGS); + } + + if (policyOIDList != NULL) + PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOIDList, plContext); + + if (date != NULL) + PKIX_PL_Object_DecRef((PKIX_PL_Object *)date, plContext); + + if (ocspChecker != NULL) + PKIX_PL_Object_DecRef((PKIX_PL_Object *)ocspChecker, plContext); + + return r; + + } + +/* + * 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 + */ +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 i=0; + + void *plContext = NULL; + + 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; + } + + error = pkix_pl_NssContext_SetCertUsage(usages, plContext); + if (error != NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + 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; +} +