changeset 12931:db25553c7f2e

PSARC 2010/269 KMF Certificate Validation Enhancements 6963018 kmf_validate_cert should put more flags into the output attribute in case of an error 6939226 allow one KMF session to choose from multiple trusted anchors to validate a certificate
author Wyllys Ingersoll <wyllys.ingersoll@sun.com>
date Tue, 27 Jul 2010 07:05:04 -0700
parents 32a41a5f8110
children ee579b934f0a
files usr/src/cmd/cmd-crypto/kmfcfg/create.c usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml usr/src/cmd/cmd-crypto/kmfcfg/list.c usr/src/cmd/cmd-crypto/kmfcfg/modify.c usr/src/lib/libkmf/include/kmftypes.h usr/src/lib/libkmf/libkmf/common/certop.c usr/src/lib/libkmf/libkmf/common/generalop.c usr/src/lib/libkmf/libkmf/common/policy.c
diffstat 9 files changed, 116 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-crypto/kmfcfg/create.c	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/create.c	Tue Jul 27 07:05:04 2010 -0700
@@ -140,7 +140,8 @@
 				if (plc.ta_name == NULL) {
 					(void) fprintf(stderr,
 					    gettext("Error name input.\n"));
-				} else {
+				} else if (strcasecmp(plc.ta_name,
+				    "search") != 0) {
 					KMF_X509_NAME taDN;
 					/* for syntax checking */
 					if (kmf_dn_parser(plc.ta_name,
--- a/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c	Tue Jul 27 07:05:04 2010 -0700
@@ -101,7 +101,7 @@
 		"\t\t[ignore-unknown-eku=true|false]\n"
 		"\t\t[ignore-trust-anchor=true|false]\n"
 		"\t\t[validity-adjusttime=adjusttime]\n"
-		"\t\t[ta-name=trust anchor subject DN]\n"
+		"\t\t[ta-name=trust anchor subject DN | search]\n"
 		"\t\t[ta-serial=trust anchor serial number]\n"
 		"\t\t[ocsp-responder=URL]\n"
 		"\t\t[ocsp-proxy=URL]\n"
--- a/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml	Tue Jul 27 07:05:04 2010 -0700
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- Use is subject to license terms.
+ Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 
  CDDL HEADER START
 
@@ -23,13 +22,11 @@
  CDDL HEADER END
  
  Sample KMF Policy Database file.
-
-        ident	"%Z%%M%	%I%	%E% SMI"
 -->
 <!DOCTYPE kmf-policy-db SYSTEM "/usr/share/lib/xml/dtd/kmfpolicy.dtd">
 <kmf-policy-db>
   
-<kmf-policy name="default" ignore-date="TRUE" ignore-trust-anchor="TRUE">
+<kmf-policy name="default" ta-name="SEARCH">
 	<validation-methods>
 		<ocsp>
 			<ocsp-basic uri-from-cert="TRUE"
--- a/usr/src/cmd/cmd-crypto/kmfcfg/list.c	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/list.c	Tue Jul 27 07:05:04 2010 -0700
@@ -57,6 +57,9 @@
 
 	if (plc->ta_name == NULL && plc->ta_serial == NULL) {
 		(void) printf(gettext("Trust Anchor Certificate: <null>\n"));
+	} else if (strcasecmp(plc->ta_name, "search") == 0) {
+		(void) printf(gettext("Trust Anchor Certificate: "
+		    "Search by Issuer\n"));
 	} else {
 		(void) printf(gettext("Trust Anchor Certificate:\n"));
 		(void) printf(gettext("\tName: %s\n"),
--- a/usr/src/cmd/cmd-crypto/kmfcfg/modify.c	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/modify.c	Tue Jul 27 07:05:04 2010 -0700
@@ -200,7 +200,7 @@
 				if (plc.ta_name == NULL) {
 					(void) fprintf(stderr,
 					    gettext("Error name input.\n"));
-				} else {
+				} else if (strcasecmp(plc.ta_name, "search")) {
 					KMF_X509_NAME taDN;
 					/* for syntax checking */
 					if (kmf_dn_parser(plc.ta_name,
@@ -213,6 +213,8 @@
 						kmf_free_dn(&taDN);
 						flags |= KC_TA_NAME;
 					}
+				} else {
+					flags |= KC_TA_NAME;
 				}
 				break;
 			case 's':
--- a/usr/src/lib/libkmf/include/kmftypes.h	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/lib/libkmf/include/kmftypes.h	Tue Jul 27 07:05:04 2010 -0700
@@ -348,7 +348,8 @@
 	KMF_ERR_NAME_NOT_MATCHED	= 0x56,
 	KMF_ERR_MAPPER_OPEN		= 0x57,
 	KMF_ERR_MAPPER_NOT_FOUND	= 0x58,
-	KMF_ERR_MAPPING_FAILED		= 0x59
+	KMF_ERR_MAPPING_FAILED		= 0x59,
+	KMF_ERR_CERT_VALIDATION		= 0x60
 } KMF_RETURN;
 
 /* Data structures for OCSP support */
--- a/usr/src/lib/libkmf/libkmf/common/certop.c	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/lib/libkmf/libkmf/common/certop.c	Tue Jul 27 07:05:04 2010 -0700
@@ -2275,6 +2275,10 @@
 	/* Get the TA name and serial number from the policy */
 	policy = handle->policy;
 	ta_name = policy->ta_name;
+
+	/*
+	 * Use name and serial from policy.
+	 */
 	ret = kmf_hexstr_to_bytes((uchar_t *)policy->ta_serial,
 	    &bytes, &bytelen);
 	if (ret != KMF_OK || bytes == NULL) {
@@ -2285,40 +2289,35 @@
 	serial.len = bytelen;
 
 	/* set up fc_attrlist for kmf_find_cert */
-	kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_KEYSTORE_TYPE_ATTR,
-	    kstype, sizeof (KMF_KEYSTORE_TYPE));
-	fc_numattr++;
-
-	kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_SUBJECT_NAME_ATTR,
+	kmf_set_attr_at_index(fc_attrlist,
+	    fc_numattr++, KMF_BIGINT_ATTR,
+	    &serial, sizeof (KMF_BIGINT));
+
+	kmf_set_attr_at_index(fc_attrlist,
+	    fc_numattr++, KMF_SUBJECT_NAME_ATTR,
 	    ta_name, strlen(ta_name));
-	fc_numattr++;
-
-	kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_BIGINT_ATTR,
-	    &serial, sizeof (KMF_BIGINT));
-	fc_numattr++;
+
+	kmf_set_attr_at_index(fc_attrlist, fc_numattr++, KMF_KEYSTORE_TYPE_ATTR,
+	    kstype, sizeof (KMF_KEYSTORE_TYPE));
 
 	if (*kstype == KMF_KEYSTORE_NSS && slotlabel != NULL) {
-		kmf_set_attr_at_index(fc_attrlist, fc_numattr,
+		kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
 		    KMF_TOKEN_LABEL_ATTR, slotlabel, strlen(slotlabel));
-		fc_numattr++;
 	}
 
 	if (*kstype == KMF_KEYSTORE_OPENSSL) {
 		if (dirpath == NULL) {
-			kmf_set_attr_at_index(fc_attrlist, fc_numattr,
+			kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
 			    KMF_DIRPATH_ATTR, dir, strlen(dir));
-			fc_numattr++;
 		} else {
-			kmf_set_attr_at_index(fc_attrlist, fc_numattr,
+			kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
 			    KMF_DIRPATH_ATTR, dirpath, strlen(dirpath));
-			fc_numattr++;
 		}
 	}
 
 	num = 0;
-	kmf_set_attr_at_index(fc_attrlist, fc_numattr,
+	kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
 	    KMF_COUNT_ATTR, &num, sizeof (uint32_t));
-	fc_numattr++;
 
 	ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
 	if (ret != KMF_OK || num != 1)  {
@@ -2376,15 +2375,15 @@
 	if (ta_retrCert.certificate.Data)
 		kmf_free_kmf_cert(handle, &ta_retrCert);
 
-	if ((ret != KMF_OK) && (ta_cert->Data != NULL))
-		free(ta_cert->Data);
+	if ((ret != KMF_OK))
+		kmf_free_data(ta_cert);
+
+	if (ta_subject != NULL)
+		free(ta_subject);
 
 	if (serial.val != NULL)
 		free(serial.val);
 
-	if (ta_subject)
-		free(ta_subject);
-
 	return (ret);
 }
 
@@ -2446,12 +2445,9 @@
 	if ((ret = kmf_get_cert_issuer_str(handle, pcert,
 	    &user_issuer)) != KMF_OK) {
 		*result |= KMF_CERT_VALIDATE_ERR_USER;
-		goto out;
-	}
-
-	if ((ret = kmf_dn_parser(user_issuer,  &user_issuerDN)) != KMF_OK) {
+	} else if ((ret = kmf_dn_parser(user_issuer,  &user_issuerDN)) !=
+	    KMF_OK) {
 		*result |= KMF_CERT_VALIDATE_ERR_USER;
-		goto out;
 	}
 
 	/*
@@ -2460,17 +2456,13 @@
 	if ((ret = kmf_get_cert_subject_str(handle, pcert,
 	    &user_subject)) != KMF_OK) {
 		*result |= KMF_CERT_VALIDATE_ERR_USER;
-		kmf_free_dn(&user_issuerDN);
-		goto out;
-	}
-
-	if ((ret = kmf_dn_parser(user_subject,  &user_subjectDN)) != KMF_OK) {
+	} else if ((ret = kmf_dn_parser(user_subject,  &user_subjectDN)) !=
+	    KMF_OK) {
 		*result |= KMF_CERT_VALIDATE_ERR_USER;
-		kmf_free_dn(&user_issuerDN);
-		goto out;
 	}
 
-	if ((kmf_compare_rdns(&user_issuerDN, &user_subjectDN)) == 0) {
+	if ((*result & KMF_CERT_VALIDATE_ERR_USER) == 0 &&
+	    (kmf_compare_rdns(&user_issuerDN, &user_subjectDN)) == 0) {
 		/*
 		 * this is a self-signed cert
 		 */
@@ -2485,7 +2477,6 @@
 	ret = cert_ku_check(handle, pcert);
 	if (ret != KMF_OK)  {
 		*result |= KMF_CERT_VALIDATE_ERR_KEYUSAGE;
-		goto out;
 	}
 
 	/*
@@ -2494,7 +2485,6 @@
 	ret = cert_eku_check(handle, pcert);
 	if (ret != KMF_OK)  {
 		*result |= KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE;
-		goto out;
 	}
 
 	/*
@@ -2508,10 +2498,8 @@
 		 * Validate expiration date
 		 */
 		ret = kmf_check_cert_date(handle, pcert);
-		if (ret != KMF_OK)  {
+		if (ret != KMF_OK)
 			*result |= KMF_CERT_VALIDATE_ERR_TIME;
-			goto out;
-		}
 	}
 
 	/*
@@ -2523,6 +2511,10 @@
 	 * are defined as optional attributes in policy dtd, but they
 	 * should exist in policy when "ignore_trust_anchor" is set
 	 * to FALSE. The policy verification code has enforced that.
+	 *
+	 * The serial number may be NULL if the ta_name == "search"
+	 * which indicates that KMF should try to locate the issuer
+	 * of the subject cert instead of using a specific TA name.
 	 */
 	if (policy->ignore_trust_anchor) {
 		goto check_revocation;
@@ -2534,19 +2526,40 @@
 	 */
 	if (self_signed) {
 		ret = verify_cert_with_cert(handle, pcert, pcert);
-	} else {
-		ret = find_ta_cert(handle, kstype, &ta_cert,
-		    &user_issuerDN, slotlabel, dirpath);
+		if (ret != KMF_OK)
+			*result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
+	} else if (user_issuer != NULL) {
+		if (policy->ta_name != NULL &&
+		    strcasecmp(policy->ta_name, "search") == 0) {
+			ret = find_issuer_cert(handle, kstype, user_issuer,
+			    &issuer_cert, slotlabel, dirpath);
+			if (ret != KMF_OK)  {
+				*result |= KMF_CERT_VALIDATE_ERR_TA;
+			} else {
+				ta_cert = issuer_cert; /* used later */
+			}
+		} else {
+			/*
+			 * If we didnt find the user_issuer string, we
+			 * won't have a "user_issuerDN" either.
+			 */
+			ret = find_ta_cert(handle, kstype, &ta_cert,
+			    &user_issuerDN, slotlabel, dirpath);
+		}
 		if (ret != KMF_OK)  {
 			*result |= KMF_CERT_VALIDATE_ERR_TA;
-			goto out;
 		}
 
-		ret = verify_cert_with_cert(handle, pcert, &ta_cert);
-	}
-	if (ret != KMF_OK)  {
-		*result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
-		goto out;
+		/* Only verify if we got the TA without an error. */
+		if ((*result & KMF_CERT_VALIDATE_ERR_TA) == 0) {
+			ret = verify_cert_with_cert(handle, pcert,
+			    &ta_cert);
+			if (ret != KMF_OK)
+				*result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
+		}
+	} else {
+		/* No issuer was found, so we cannot find a trust anchor */
+		*result |= KMF_CERT_VALIDATE_ERR_TA;
 	}
 
 check_revocation:
@@ -2570,30 +2583,38 @@
 		goto out;
 	}
 
-	ret = find_issuer_cert(handle, kstype, user_issuer, &issuer_cert,
-	    slotlabel, dirpath);
-	if (ret != KMF_OK)  {
-		*result |= KMF_CERT_VALIDATE_ERR_ISSUER;
-		goto out;
+	/*
+	 * If we did not find the issuer cert earlier
+	 * (when policy->ta_name == "search"), get it here.
+	 * We need the issuer cert if the revocation method is
+	 * CRL or OCSP.
+	 */
+	if (issuer_cert.Length == 0 &&
+	    policy->revocation & KMF_REVOCATION_METHOD_CRL ||
+	    policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
+		ret = find_issuer_cert(handle, kstype, user_issuer,
+		    &issuer_cert, slotlabel, dirpath);
+		if (ret != KMF_OK)  {
+			*result |= KMF_CERT_VALIDATE_ERR_ISSUER;
+		}
 	}
 
-	if (policy->revocation & KMF_REVOCATION_METHOD_CRL) {
+	if (policy->revocation & KMF_REVOCATION_METHOD_CRL &&
+	    (*result & KMF_CERT_VALIDATE_ERR_ISSUER) == 0) {
 		ret = cert_crl_check(handle, kstype, pcert, &issuer_cert);
 		if (ret != KMF_OK)  {
 			*result |= KMF_CERT_VALIDATE_ERR_CRL;
-			goto out;
 		}
 	}
 
-	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
+	if (policy->revocation & KMF_REVOCATION_METHOD_OCSP &&
+	    (*result & KMF_CERT_VALIDATE_ERR_ISSUER) == 0) {
 		ret = cert_ocsp_check(handle, kstype, pcert, &issuer_cert,
 		    ocsp_response, slotlabel, dirpath);
 		if (ret != KMF_OK)  {
 			*result |= KMF_CERT_VALIDATE_ERR_OCSP;
-			goto out;
 		}
 	}
-
 out:
 	if (user_issuer) {
 		kmf_free_dn(&user_issuerDN);
@@ -2603,14 +2624,24 @@
 	if (user_subject)
 		free(user_subject);
 
-	if (ta_cert.Data)
-		free(ta_cert.Data);
-
-	if (issuer_cert.Data)
-		free(issuer_cert.Data);
+	/*
+	 * If we did not copy ta_cert to issuer_cert, free it.
+	 */
+	if (issuer_cert.Data &&
+	    issuer_cert.Data != ta_cert.Data)
+		kmf_free_data(&issuer_cert);
+
+	kmf_free_data(&ta_cert);
+
+	/*
+	 * If we got an error flag from any of the checks,
+	 * remap the return code to a generic "CERT_VALIDATION"
+	 * error so the caller knows to check the individual flags.
+	 */
+	if (*result != 0)
+		ret = KMF_ERR_CERT_VALIDATION;
 
 	return (ret);
-
 }
 
 KMF_RETURN
--- a/usr/src/lib/libkmf/libkmf/common/generalop.c	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/lib/libkmf/libkmf/common/generalop.c	Tue Jul 27 07:05:04 2010 -0700
@@ -138,7 +138,8 @@
 	{KMF_ERR_NAME_NOT_MATCHED,	"KMF_ERR_NAME_NOT_MATCHED"},
 	{KMF_ERR_MAPPER_OPEN,		"KMF_ERR_MAPPER_OPEN"},
 	{KMF_ERR_MAPPER_NOT_FOUND,	"KMF_ERR_MAPPER_NOT_FOUND"},
-	{KMF_ERR_MAPPING_FAILED,	"KMF_ERR_MAPPING_FAILED"}
+	{KMF_ERR_MAPPING_FAILED,	"KMF_ERR_MAPPING_FAILED"},
+	{KMF_ERR_CERT_VALIDATION,	"KMF_ERR_CERT_VALIDATION"}
 };
 
 typedef struct {
--- a/usr/src/lib/libkmf/libkmf/common/policy.c	Tue Jul 27 14:38:47 2010 +0200
+++ b/usr/src/lib/libkmf/libkmf/common/policy.c	Tue Jul 27 07:05:04 2010 -0700
@@ -1279,7 +1279,6 @@
 	return (ret);
 }
 
-
 KMF_RETURN
 kmf_verify_policy(KMF_POLICY_RECORD *policy)
 {
@@ -1290,7 +1289,10 @@
 		return (KMF_ERR_POLICY_NAME);
 
 	/* Check the TA related policy */
-	if (policy->ta_name != NULL && policy->ta_serial != NULL) {
+	if (policy->ta_name != NULL &&
+	    strcasecmp(policy->ta_name, "search") == 0) {
+		has_ta = B_TRUE;
+	} else if (policy->ta_name != NULL && policy->ta_serial != NULL) {
 		has_ta = B_TRUE;
 	} else if (policy->ta_name == NULL && policy->ta_serial == NULL) {
 		has_ta = B_FALSE;