diff options
author | Wyllys Ingersoll <wyllys.ingersoll@sun.com> | 2010-07-27 07:05:04 -0700 |
---|---|---|
committer | Wyllys Ingersoll <wyllys.ingersoll@sun.com> | 2010-07-27 07:05:04 -0700 |
commit | fc2613b0a10c787c0f90e9b36f170183746c63f8 (patch) | |
tree | 09f5e7b7fede6097276713a5766ca03726ef6249 | |
parent | f89940742f5d14dde79b69b98a414dd7b7f585c7 (diff) | |
download | illumos-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.c | 3 | ||||
-rw-r--r-- | usr/src/cmd/cmd-crypto/kmfcfg/kmfcfg.c | 2 | ||||
-rw-r--r-- | usr/src/cmd/cmd-crypto/kmfcfg/kmfpolicy.xml | 7 | ||||
-rw-r--r-- | usr/src/cmd/cmd-crypto/kmfcfg/list.c | 3 | ||||
-rw-r--r-- | usr/src/cmd/cmd-crypto/kmfcfg/modify.c | 4 | ||||
-rw-r--r-- | usr/src/lib/libkmf/include/kmftypes.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/certop.c | 157 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/generalop.c | 3 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/policy.c | 6 |
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; |