Mercurial > illumos > illumos-gate
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;