summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWyllys Ingersoll <wyllys.ingersoll@sun.com>2010-07-27 07:05:04 -0700
committerWyllys Ingersoll <wyllys.ingersoll@sun.com>2010-07-27 07:05:04 -0700
commitfc2613b0a10c787c0f90e9b36f170183746c63f8 (patch)
tree09f5e7b7fede6097276713a5766ca03726ef6249
parentf89940742f5d14dde79b69b98a414dd7b7f585c7 (diff)
downloadillumos-joyent-fc2613b0a10c787c0f90e9b36f170183746c63f8.tar.gz
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
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/create.c3
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c2
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml7
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/list.c3
-rw-r--r--usr/src/cmd/cmd-crypto/kmfcfg/modify.c4
-rw-r--r--usr/src/lib/libkmf/include/kmftypes.h3
-rw-r--r--usr/src/lib/libkmf/libkmf/common/certop.c157
-rw-r--r--usr/src/lib/libkmf/libkmf/common/generalop.c3
-rw-r--r--usr/src/lib/libkmf/libkmf/common/policy.c6
9 files changed, 113 insertions, 75 deletions
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/create.c b/usr/src/cmd/cmd-crypto/kmfcfg/create.c
index 8bf1279646..e399205613 100644
--- a/usr/src/cmd/cmd-crypto/kmfcfg/create.c
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/create.c
@@ -140,7 +140,8 @@ kc_create(int argc, char *argv[])
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,
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c b/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c
index e2d23a2126..bb7263b110 100644
--- a/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c
@@ -101,7 +101,7 @@ static verbcmd cmds[] = {
"\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"
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml
index 2c2ed35e2c..30be08c66b 100644
--- a/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml
@@ -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"
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/list.c b/usr/src/cmd/cmd-crypto/kmfcfg/list.c
index 41556b9c07..40cb7cb8ee 100644
--- a/usr/src/cmd/cmd-crypto/kmfcfg/list.c
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/list.c
@@ -57,6 +57,9 @@ show_policy(KMF_POLICY_RECORD *plc)
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"),
diff --git a/usr/src/cmd/cmd-crypto/kmfcfg/modify.c b/usr/src/cmd/cmd-crypto/kmfcfg/modify.c
index 387d2aaef3..01065d6214 100644
--- a/usr/src/cmd/cmd-crypto/kmfcfg/modify.c
+++ b/usr/src/cmd/cmd-crypto/kmfcfg/modify.c
@@ -200,7 +200,7 @@ kc_modify_policy(int argc, char *argv[])
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 @@ kc_modify_policy(int argc, char *argv[])
kmf_free_dn(&taDN);
flags |= KC_TA_NAME;
}
+ } else {
+ flags |= KC_TA_NAME;
}
break;
case 's':
diff --git a/usr/src/lib/libkmf/include/kmftypes.h b/usr/src/lib/libkmf/include/kmftypes.h
index eff431908a..e881633ef5 100644
--- a/usr/src/lib/libkmf/include/kmftypes.h
+++ b/usr/src/lib/libkmf/include/kmftypes.h
@@ -348,7 +348,8 @@ typedef enum {
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 */
diff --git a/usr/src/lib/libkmf/libkmf/common/certop.c b/usr/src/lib/libkmf/libkmf/common/certop.c
index a111690158..f5ea79845a 100644
--- a/usr/src/lib/libkmf/libkmf/common/certop.c
+++ b/usr/src/lib/libkmf/libkmf/common/certop.c
@@ -2275,6 +2275,10 @@ find_ta_cert(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
/* 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 @@ find_ta_cert(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
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_BIGINT_ATTR,
+ &serial, sizeof (KMF_BIGINT));
- kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_SUBJECT_NAME_ATTR,
+ 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 @@ out:
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 @@ kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
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 @@ kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
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 @@ kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
ret = cert_ku_check(handle, pcert);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_KEYUSAGE;
- goto out;
}
/*
@@ -2494,7 +2485,6 @@ kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
ret = cert_eku_check(handle, pcert);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE;
- goto out;
}
/*
@@ -2508,10 +2498,8 @@ kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
* 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 @@ kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
* 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 @@ kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
*/
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 @@ check_revocation:
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 @@ out:
if (user_subject)
free(user_subject);
- if (ta_cert.Data)
- free(ta_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 (issuer_cert.Data)
- free(issuer_cert.Data);
+ /*
+ * 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
diff --git a/usr/src/lib/libkmf/libkmf/common/generalop.c b/usr/src/lib/libkmf/libkmf/common/generalop.c
index e3c80f6cee..da3ff15652 100644
--- a/usr/src/lib/libkmf/libkmf/common/generalop.c
+++ b/usr/src/lib/libkmf/libkmf/common/generalop.c
@@ -138,7 +138,8 @@ static kmf_error_map kmf_errcodes[] = {
{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 {
diff --git a/usr/src/lib/libkmf/libkmf/common/policy.c b/usr/src/lib/libkmf/libkmf/common/policy.c
index a8d4175d81..3204dd865c 100644
--- a/usr/src/lib/libkmf/libkmf/common/policy.c
+++ b/usr/src/lib/libkmf/libkmf/common/policy.c
@@ -1279,7 +1279,6 @@ out:
return (ret);
}
-
KMF_RETURN
kmf_verify_policy(KMF_POLICY_RECORD *policy)
{
@@ -1290,7 +1289,10 @@ kmf_verify_policy(KMF_POLICY_RECORD *policy)
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;