2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A *
2N/A * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <link.h>
2N/A#include <fcntl.h>
2N/A#include <ctype.h>
2N/A#include <sys/param.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/socket.h>
2N/A#include <ber_der.h>
2N/A#include <kmfapiP.h>
2N/A#include <pem_encode.h>
2N/A#include <libgen.h>
2N/A#include <cryptoutil.h>
2N/A
2N/A#define CERTFILE_TEMPNAME "/tmp/user.certXXXXXX"
2N/A#define CRLFILE_TEMPNAME "/tmp/crlXXXXXX"
2N/A#define X509_FORMAT_VERSION 2
2N/A
2N/Astatic KMF_RETURN
2N/Asign_cert(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *,
2N/A KMF_OID *, KMF_DATA *);
2N/A
2N/Astatic KMF_RETURN
2N/Averify_cert_with_key(KMF_HANDLE_T, KMF_DATA *, const KMF_DATA *);
2N/A
2N/Astatic KMF_RETURN
2N/Averify_cert_with_cert(KMF_HANDLE_T, const KMF_DATA *, const KMF_DATA *);
2N/A
2N/Astatic KMF_RETURN
2N/Aget_keyalg_from_cert(KMF_DATA *cert, KMF_KEY_ALG *keyalg)
2N/A{
2N/A KMF_RETURN rv;
2N/A KMF_X509_CERTIFICATE *SignerCert = NULL;
2N/A KMF_ALGORITHM_INDEX AlgorithmId;
2N/A
2N/A rv = DerDecodeSignedCertificate(cert, &SignerCert);
2N/A
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A
2N/A /* Get the algorithm info from the signer certificate */
2N/A AlgorithmId = x509_algoid_to_algid(
2N/A &SignerCert->signature.algorithmIdentifier.algorithm);
2N/A
2N/A switch (AlgorithmId) {
2N/A case KMF_ALGID_MD5WithRSA:
2N/A case KMF_ALGID_SHA1WithRSA:
2N/A case KMF_ALGID_SHA256WithRSA:
2N/A case KMF_ALGID_SHA384WithRSA:
2N/A case KMF_ALGID_SHA512WithRSA:
2N/A *keyalg = KMF_RSA;
2N/A break;
2N/A case KMF_ALGID_SHA1WithDSA:
2N/A case KMF_ALGID_SHA256WithDSA:
2N/A *keyalg = KMF_DSA;
2N/A break;
2N/A case KMF_ALGID_SHA1WithECDSA:
2N/A case KMF_ALGID_SHA256WithECDSA:
2N/A case KMF_ALGID_SHA384WithECDSA:
2N/A case KMF_ALGID_SHA512WithECDSA:
2N/A case KMF_ALGID_ECDSA:
2N/A *keyalg = KMF_ECDSA;
2N/A break;
2N/A default:
2N/A rv = KMF_ERR_BAD_ALGORITHM;
2N/A }
2N/A
2N/A kmf_free_signed_cert(SignerCert);
2N/A free(SignerCert);
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * Name: kmf_find_prikey_by_cert
2N/A *
2N/A * Description:
2N/A * This function finds the corresponding private key in keystore
2N/A * for a certificate
2N/A */
2N/AKMF_RETURN
2N/Akmf_find_prikey_by_cert(KMF_HANDLE_T handle, int numattr,
2N/A KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_KEYSTORE_TYPE kstype;
2N/A KMF_KEY_ALG keyalg;
2N/A KMF_KEY_HANDLE *key = NULL;
2N/A KMF_DATA *cert = NULL;
2N/A
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
2N/A {KMF_KEY_HANDLE_ATTR, TRUE, sizeof (KMF_KEY_HANDLE),
2N/A sizeof (KMF_KEY_HANDLE)}
2N/A };
2N/A
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /*
2N/A * First, get the key algorithm info from the certificate and saves it
2N/A * in the returned key handle.
2N/A */
2N/A cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
2N/A if (cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A ret = get_keyalg_from_cert(cert, &keyalg);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
2N/A if (key == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A key->keyalg = keyalg;
2N/A
2N/A /* Call the plugin to do the work. */
2N/A ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
2N/A &kstype, NULL);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A plugin = FindPlugin(handle, kstype);
2N/A if (plugin == NULL || plugin->funclist->FindPrikeyByCert == NULL)
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A
2N/A return (plugin->funclist->FindPrikeyByCert(handle, numattr, attrlist));
2N/A}
2N/A
2N/A
2N/AKMF_RETURN
2N/Acheck_key_usage(void *handle,
2N/A const KMF_DATA *cert,
2N/A const KMF_KU_PURPOSE purpose)
2N/A{
2N/A KMF_X509EXT_BASICCONSTRAINTS constraint;
2N/A KMF_BOOL critical = B_FALSE;
2N/A KMF_X509EXT_KEY_USAGE keyusage;
2N/A KMF_RETURN ret = KMF_OK;
2N/A
2N/A if (handle == NULL || cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A (void) memset(&constraint, 0, sizeof (KMF_X509EXT_BASICCONSTRAINTS));
2N/A (void) memset(&keyusage, 0, sizeof (KMF_X509EXT_KEY_USAGE));
2N/A
2N/A ret = kmf_get_cert_ku(cert, &keyusage);
2N/A if (ret != KMF_OK)
2N/A /*
2N/A * If absent or error, the cert is assumed to be invalid
2N/A * for all key usage checking.
2N/A */
2N/A return (ret);
2N/A
2N/A switch (purpose) {
2N/A case KMF_KU_SIGN_CERT:
2N/A /*
2N/A * RFC 3280:
2N/A * The keyCertSign bit is asserted when the subject
2N/A * public key is used for verifying a signature on
2N/A * public key certificates. If the keyCertSign bit
2N/A * is asserted, then the cA bit in the basic constraints
2N/A * extension (section 4.2.1.10) MUST also be asserted.
2N/A * The basic constraints extension MUST appear as a
2N/A * critical extension in all CA certificates that
2N/A * contain public keys used to validate digital
2N/A * signatures on certificates.
2N/A */
2N/A if (keyusage.KeyUsageBits & KMF_keyCertSign) {
2N/A ret = kmf_get_cert_basic_constraint(cert,
2N/A &critical, &constraint);
2N/A
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A if ((!critical) || (!constraint.cA))
2N/A return (KMF_ERR_KEYUSAGE);
2N/A } else {
2N/A return (KMF_ERR_KEYUSAGE);
2N/A }
2N/A break;
2N/A case KMF_KU_SIGN_DATA:
2N/A /*
2N/A * RFC 3280:
2N/A * The digitalSignature bit is asserted when the subject
2N/A * public key is used with a digital signature mechanism
2N/A * to support security services other than certificate
2N/A * signing(bit 5), or CRL signing(bit 6).
2N/A */
2N/A if (!(keyusage.KeyUsageBits & KMF_digitalSignature))
2N/A return (KMF_ERR_KEYUSAGE);
2N/A break;
2N/A case KMF_KU_ENCRYPT_DATA:
2N/A /*
2N/A * RFC 3280:
2N/A * The dataEncipherment bit is asserted when the subject
2N/A * public key is used for enciphering user data, other than
2N/A * cryptographic keys.
2N/A */
2N/A if (!(keyusage.KeyUsageBits & KMF_dataEncipherment))
2N/A return (KMF_ERR_KEYUSAGE);
2N/A break;
2N/A default:
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A }
2N/A
2N/A return (KMF_OK);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_find_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_KEYSTORE_TYPE kstype;
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_COUNT_ATTR, FALSE, sizeof (uint32_t), sizeof (uint32_t)}
2N/A };
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
2N/A &kstype, NULL);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A plugin = FindPlugin(handle, kstype);
2N/A if (plugin == NULL || plugin->funclist->FindCert == NULL)
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A
2N/A return (plugin->funclist->FindCert(handle, numattr, attrlist));
2N/A}
2N/A
2N/A#define NODATA(d) (d.Data == NULL || d.Length == NULL)
2N/A
2N/AKMF_RETURN
2N/Akmf_encode_cert_record(KMF_X509_CERTIFICATE *CertData, KMF_DATA *encodedCert)
2N/A{
2N/A KMF_RETURN ret;
2N/A KMF_X509_TBS_CERT *tbs_cert;
2N/A
2N/A if (CertData == NULL || encodedCert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /*
2N/A * Validate that all required fields are present.
2N/A */
2N/A tbs_cert = &(CertData->certificate);
2N/A if (NODATA(tbs_cert->version) ||
2N/A NODATA(tbs_cert->signature.algorithm) ||
2N/A NODATA(tbs_cert->subjectPublicKeyInfo.subjectPublicKey) ||
2N/A tbs_cert->serialNumber.val == NULL ||
2N/A tbs_cert->serialNumber.len == 0 ||
2N/A tbs_cert->subject.numberOfRDNs == 0 ||
2N/A tbs_cert->issuer.numberOfRDNs == 0) {
2N/A return (KMF_ERR_INCOMPLETE_TBS_CERT);
2N/A }
2N/A
2N/A encodedCert->Length = 0;
2N/A encodedCert->Data = NULL;
2N/A
2N/A /* Pack the new certificate */
2N/A ret = DerEncodeSignedCertificate(CertData, encodedCert);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * This function is used to setup the attribute list before calling
2N/A * kmf_find_prikey_by_cert(). This function is used by
2N/A * kmf_decrypt_with_cert
2N/A * kmf_sign_cert
2N/A * kmf_sign_data
2N/A *
2N/A * The attribute list in these callers contain all the attributes
2N/A * needed by kmf_find_prikey_by_cert(), except the
2N/A * KMF_KEY_HANDLE attribute and the KMF_CERT_DATA_ATTR attribute.
2N/A * These 2 attributes need to be added or reset.
2N/A *
2N/A * The caller should free the new_attrlist after use it.
2N/A */
2N/Astatic KMF_RETURN
2N/Asetup_findprikey_attrlist(KMF_ATTRIBUTE *src_attrlist, int src_num,
2N/A KMF_ATTRIBUTE **new_attrlist, int *new_num, KMF_KEY_HANDLE *key,
2N/A KMF_DATA *cert)
2N/A{
2N/A KMF_ATTRIBUTE *attrlist = NULL;
2N/A int cur_num = src_num;
2N/A int index;
2N/A int i;
2N/A
2N/A if (src_attrlist == NULL || new_num == NULL || key == NULL ||
2N/A cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* Create a new attribute list with 2 more elements */
2N/A attrlist = (KMF_ATTRIBUTE *) malloc(
2N/A (src_num + 2) * sizeof (KMF_ATTRIBUTE));
2N/A if (attrlist == NULL)
2N/A return (KMF_ERR_MEMORY);
2N/A
2N/A /* Copy the src_attrlist to the new list */
2N/A for (i = 0; i < src_num; i++) {
2N/A attrlist[i].type = src_attrlist[i].type;
2N/A attrlist[i].pValue = src_attrlist[i].pValue;
2N/A attrlist[i].valueLen = src_attrlist[i].valueLen;
2N/A }
2N/A
2N/A /* Add or reset the key handle attribute */
2N/A index = kmf_find_attr(KMF_KEY_HANDLE_ATTR, attrlist, cur_num);
2N/A if (index == -1) {
2N/A /* not found; add it */
2N/A kmf_set_attr_at_index(attrlist, cur_num,
2N/A KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE));
2N/A cur_num++;
2N/A } else {
2N/A /* found; just reset it */
2N/A kmf_set_attr_at_index(attrlist, index,
2N/A KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE));
2N/A }
2N/A
2N/A /* add or reset the cert data attribute */
2N/A index = kmf_find_attr(KMF_CERT_DATA_ATTR, attrlist, cur_num);
2N/A if (index == -1) {
2N/A /* not found; add it */
2N/A kmf_set_attr_at_index(attrlist, cur_num,
2N/A KMF_CERT_DATA_ATTR, cert, sizeof (KMF_DATA));
2N/A cur_num++;
2N/A } else {
2N/A /* found; just reset it */
2N/A kmf_set_attr_at_index(attrlist, index,
2N/A KMF_CERT_DATA_ATTR, cert, sizeof (KMF_DATA));
2N/A }
2N/A
2N/A *new_attrlist = attrlist;
2N/A *new_num = cur_num;
2N/A return (KMF_OK);
2N/A}
2N/A
2N/A/*
2N/A * Determine a default signature type to use based on
2N/A * the key algorithm.
2N/A */
2N/Astatic KMF_OID *
2N/Aget_default_signoid(KMF_KEY_HANDLE *key)
2N/A{
2N/A KMF_OID *oid;
2N/A
2N/A switch (key->keyalg) {
2N/A case KMF_RSA:
2N/A oid = (KMF_OID *)&KMFOID_SHA256WithRSA;
2N/A break;
2N/A case KMF_DSA:
2N/A /* NSS doesn't support DSA-SHA2 hashes yet */
2N/A if (key->kstype == KMF_KEYSTORE_NSS)
2N/A oid = (KMF_OID *)&KMFOID_X9CM_DSAWithSHA1;
2N/A else
2N/A oid = (KMF_OID *)&KMFOID_SHA256WithDSA;
2N/A break;
2N/A case KMF_ECDSA:
2N/A oid = (KMF_OID *)&KMFOID_SHA256WithECDSA;
2N/A break;
2N/A default:
2N/A oid = NULL;
2N/A break;
2N/A }
2N/A return (oid);
2N/A}
2N/A
2N/A/*
2N/A * This is to check to see if a certificate being signed has
2N/A * the keyCertSign KeyUsage bit set, and if so, make sure the
2N/A * "BasicConstraints" extension is also set accordingly.
2N/A */
2N/Astatic KMF_RETURN
2N/Acheck_for_basic_constraint(KMF_DATA *cert)
2N/A{
2N/A KMF_RETURN rv = KMF_OK;
2N/A KMF_X509EXT_KEY_USAGE keyUsage;
2N/A KMF_X509_CERTIFICATE *x509cert = NULL;
2N/A
2N/A rv = kmf_get_cert_ku((const KMF_DATA *)cert, &keyUsage);
2N/A if (rv == KMF_OK) {
2N/A KMF_X509EXT_BASICCONSTRAINTS basicConstraint;
2N/A KMF_BOOL critical;
2N/A /* If keyCertSign is set, look for basicConstraints */
2N/A if (keyUsage.KeyUsageBits & KMF_keyCertSign)
2N/A rv = kmf_get_cert_basic_constraint(
2N/A (const KMF_DATA *)cert,
2N/A &critical, &basicConstraint);
2N/A
2N/A /*
2N/A * If we got KMF_OK (or an error), then return
2N/A * because the extension is already present. We
2N/A * only want to continue with this function if
2N/A * the extension is NOT found.
2N/A */
2N/A if (rv != KMF_ERR_EXTENSION_NOT_FOUND)
2N/A return (rv);
2N/A
2N/A /*
2N/A * Don't limit the pathLen (for now).
2N/A * This should probably be a policy setting in the
2N/A * future.
2N/A */
2N/A basicConstraint.cA = TRUE;
2N/A basicConstraint.pathLenConstraintPresent = FALSE;
2N/A
2N/A /*
2N/A * Decode the DER cert data into the internal
2N/A * X.509 structure we need to set extensions.
2N/A */
2N/A rv = DerDecodeSignedCertificate(cert, &x509cert);
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A /*
2N/A * Add the missing basic constraint.
2N/A */
2N/A rv = kmf_set_cert_basic_constraint(x509cert,
2N/A TRUE, &basicConstraint);
2N/A if (rv != KMF_OK) {
2N/A kmf_free_signed_cert(x509cert);
2N/A free(x509cert);
2N/A return (rv);
2N/A }
2N/A /* Free the old cert data record */
2N/A kmf_free_data(cert);
2N/A
2N/A /* Re-encode the cert with the extension */
2N/A rv = kmf_encode_cert_record(x509cert, cert);
2N/A
2N/A /* cleanup */
2N/A kmf_free_signed_cert(x509cert);
2N/A free(x509cert);
2N/A }
2N/A if (rv == KMF_ERR_EXTENSION_NOT_FOUND)
2N/A rv = KMF_OK;
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * Name: kmf_sign_cert
2N/A *
2N/A * Description:
2N/A * This function signs a certificate using the signer cert and
2N/A * returns a signed and DER-encoded certificate.
2N/A *
2N/A * The following types of certificate data can be submitted to be signed:
2N/A * KMF_TBS_CERT_DATA_ATTR - a KMF_DATA ptr is provided in the attrlist
2N/A * and is signed directly.
2N/A * KMF_X509_CERTIFICATE_ATTR - a KMF_X509_CERTIFICATE record is provided
2N/A * in the attribute list. This is converted to raw KMF_DATA
2N/A * prior to signing.
2N/A *
2N/A * The key for the signing operation can be provided as a KMF_KEY_HANDLE_ATTR
2N/A * or the caller may choose to provide a KMF_SIGNER_CERT_ATTR (KMF_DATA *).
2N/A * If the latter, this function will then attempt to find the private key
2N/A * associated with the certificate. The private key must be stored in
2N/A * the same keystore as the signer certificate.
2N/A */
2N/AKMF_RETURN
2N/Akmf_sign_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_RETURN ret;
2N/A int new_numattr = numattr + 1;
2N/A KMF_ATTRIBUTE *new_attrlist = NULL;
2N/A KMF_DATA *signer_cert = NULL;
2N/A KMF_DATA *tbs_cert = NULL; /* to be signed cert */
2N/A KMF_DATA *signed_cert = NULL;
2N/A KMF_DATA unsignedCert = {NULL, 0};
2N/A KMF_KEY_HANDLE sign_key, *sign_key_ptr;
2N/A int freethekey = 0;
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_OID *oid = NULL;
2N/A KMF_X509_CERTIFICATE *x509cert;
2N/A KMF_X509_TBS_CERT *decodedTbsCert = NULL;
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)}
2N/A };
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Get the signer cert and check its keyUsage */
2N/A signer_cert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A sign_key_ptr = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist,
2N/A numattr);
2N/A /*
2N/A * Only accept 1 or the other, not both.
2N/A */
2N/A if (signer_cert == NULL && sign_key_ptr == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A if (signer_cert != NULL && sign_key_ptr != NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A oid = kmf_get_attr_ptr(KMF_OID_ATTR, attrlist, numattr);
2N/A if (oid == NULL) {
2N/A /*
2N/A * If the signature OID was not given, check
2N/A * for an algorithm index identifier instead.
2N/A */
2N/A KMF_ALGORITHM_INDEX AlgId;
2N/A ret = kmf_get_attr(KMF_ALGORITHM_INDEX_ATTR, attrlist, numattr,
2N/A &AlgId, NULL);
2N/A if (ret == KMF_OK)
2N/A oid = x509_algid_to_algoid(AlgId);
2N/A }
2N/A
2N/A if (signer_cert != NULL) {
2N/A policy = handle->policy;
2N/A ret = check_key_usage(handle, signer_cert, KMF_KU_SIGN_CERT);
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
2N/A ret = KMF_OK;
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /*
2N/A * Find the private key from the signer certificate by calling
2N/A * kmf_find_prikey_by_cert().
2N/A */
2N/A ret = setup_findprikey_attrlist(attrlist, numattr,
2N/A &new_attrlist, &new_numattr, &sign_key, signer_cert);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A
2N/A ret = kmf_find_prikey_by_cert(handle, new_numattr,
2N/A new_attrlist);
2N/A if (ret != KMF_OK) {
2N/A goto out;
2N/A }
2N/A sign_key_ptr = &sign_key;
2N/A freethekey = 1;
2N/A }
2N/A
2N/A tbs_cert = kmf_get_attr_ptr(KMF_TBS_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A if (tbs_cert == NULL) {
2N/A x509cert = kmf_get_attr_ptr(KMF_X509_CERTIFICATE_ATTR, attrlist,
2N/A numattr);
2N/A if (x509cert == NULL) {
2N/A ret = KMF_ERR_BAD_PARAMETER;
2N/A goto out;
2N/A }
2N/A
2N/A ret = kmf_encode_cert_record(x509cert, &unsignedCert);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A
2N/A tbs_cert = &unsignedCert;
2N/A }
2N/A /*
2N/A * Check for the keyCertSign bit in the KeyUsage extn. If it is set,
2N/A * then the basicConstraints must also be present and be
2N/A * marked critical.
2N/A */
2N/A ret = check_for_basic_constraint(tbs_cert);
2N/A if (ret)
2N/A goto out;
2N/A
2N/A if (oid == NULL) {
2N/A /*
2N/A * If OID is not known yet, use a default value
2N/A * based on the signers key type.
2N/A */
2N/A oid = get_default_signoid(sign_key_ptr);
2N/A }
2N/A
2N/A signed_cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A if (signed_cert == NULL) {
2N/A ret = KMF_ERR_BAD_PARAMETER;
2N/A goto out;
2N/A }
2N/A
2N/A ret = sign_cert(handle, tbs_cert, sign_key_ptr, oid, signed_cert);
2N/Aout:
2N/A if (new_attrlist)
2N/A (void) free(new_attrlist);
2N/A
2N/A /* If we had to find the key, free it here. */
2N/A if (freethekey)
2N/A kmf_free_kmf_key(handle, &sign_key);
2N/A
2N/A kmf_free_data(&unsignedCert);
2N/A if (decodedTbsCert != NULL) {
2N/A kmf_free_tbs_cert(decodedTbsCert);
2N/A free(decodedTbsCert);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Name: kmf_sign_data
2N/A *
2N/A * Description:
2N/A * This function signs a block of data using the signer cert and
2N/A * returns the the signature in output
2N/A */
2N/AKMF_RETURN
2N/Akmf_sign_data(KMF_HANDLE_T handle, int numattr,
2N/A KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_ATTRIBUTE *new_attrlist = NULL;
2N/A int new_numattr = numattr;
2N/A KMF_DATA *signer_cert = NULL;
2N/A KMF_DATA *tbs_data = NULL; /* to be signed data */
2N/A KMF_DATA *output = NULL;
2N/A KMF_KEY_HANDLE sign_key, *sign_key_ptr;
2N/A KMF_ALGORITHM_INDEX AlgId = KMF_ALGID_NONE;
2N/A KMF_DATA signature = {0, NULL};
2N/A KMF_OID *oid;
2N/A KMF_POLICY_RECORD *policy;
2N/A
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
2N/A {KMF_OUT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)}
2N/A };
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Get the signer cert and check its keyUsage. */
2N/A signer_cert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A sign_key_ptr = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist,
2N/A numattr);
2N/A
2N/A if (signer_cert == NULL && sign_key_ptr == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /*
2N/A * If a signer cert was given, use it to find the private key
2N/A * to use for signing the data.
2N/A */
2N/A if (signer_cert != NULL) {
2N/A ret = check_key_usage(handle, signer_cert, KMF_KU_SIGN_DATA);
2N/A
2N/A /*
2N/A * Signing generic data does not require the
2N/A * KeyUsage extension.
2N/A */
2N/A policy = handle->policy;
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
2N/A ret = KMF_OK;
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /*
2N/A * Find the private key from the signer certificate.
2N/A */
2N/A ret = setup_findprikey_attrlist(attrlist, numattr,
2N/A &new_attrlist, &new_numattr, &sign_key, signer_cert);
2N/A if (ret != KMF_OK) {
2N/A goto cleanup;
2N/A }
2N/A
2N/A ret = kmf_find_prikey_by_cert(handle, new_numattr,
2N/A new_attrlist);
2N/A if (ret != KMF_OK) {
2N/A goto cleanup;
2N/A }
2N/A sign_key_ptr = &sign_key;
2N/A }
2N/A
2N/A /* Get the tbs_data and signed_data attributes now */
2N/A tbs_data = kmf_get_attr_ptr(KMF_DATA_ATTR, attrlist, numattr);
2N/A if (tbs_data == NULL) {
2N/A ret = KMF_ERR_BAD_PARAMETER;
2N/A goto cleanup;
2N/A }
2N/A
2N/A output = kmf_get_attr_ptr(KMF_OUT_DATA_ATTR, attrlist, numattr);
2N/A if (output == NULL) {
2N/A ret = KMF_ERR_BAD_PARAMETER;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /*
2N/A * Get the algorithm index attribute and its oid. If this attribute
2N/A * is not provided, then we use a default value.
2N/A */
2N/A oid = kmf_get_attr_ptr(KMF_OID_ATTR, attrlist, numattr);
2N/A if (oid == NULL) {
2N/A ret = kmf_get_attr(KMF_ALGORITHM_INDEX_ATTR, attrlist,
2N/A numattr, &AlgId, NULL);
2N/A /* If there was no Algorithm ID, use default based on key */
2N/A if (ret != KMF_OK)
2N/A oid = get_default_signoid(sign_key_ptr);
2N/A else
2N/A oid = x509_algid_to_algoid(AlgId);
2N/A }
2N/A if (sign_key_ptr->keyp == NULL) {
2N/A ret = KMF_ERR_BAD_PARAMETER;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* Now call the plugin function to sign it */
2N/A plugin = FindPlugin(handle, sign_key_ptr->kstype);
2N/A if (plugin == NULL || plugin->funclist->SignData == NULL) {
2N/A ret = KMF_ERR_PLUGIN_NOTFOUND;
2N/A goto cleanup;
2N/A }
2N/A
2N/A ret = plugin->funclist->SignData(handle, sign_key_ptr, oid, tbs_data,
2N/A output);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A /*
2N/A * For DSA, NSS returns an encoded signature. Decode the
2N/A * signature and expect a 40-byte DSA signature.
2N/A */
2N/A if (plugin->type == KMF_KEYSTORE_NSS &&
2N/A (IsEqualOid(oid, (KMF_OID *)&KMFOID_X9CM_DSAWithSHA1) ||
2N/A IsEqualOid(oid, (KMF_OID *)&KMFOID_SHA256WithDSA))) {
2N/A ret = DerDecodeDSASignature(output, &signature);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A output->Length = signature.Length;
2N/A (void) memcpy(output->Data, signature.Data, signature.Length);
2N/A }
2N/A
2N/Acleanup:
2N/A if (new_attrlist != NULL)
2N/A free(new_attrlist);
2N/A
2N/A if (signature.Data)
2N/A free(signature.Data);
2N/A
2N/A if (signer_cert != NULL && sign_key_ptr != NULL)
2N/A kmf_free_kmf_key(handle, sign_key_ptr);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * kmf_verify_data
2N/A *
2N/A * This routine will try to verify a block of data using
2N/A * either a public key or a certificate as the source
2N/A * of the verification (the key).
2N/A *
2N/A * The caller may provider either a KMF_KEY_HANDLE_ATTR or
2N/A * a KMF_SIGNER_CERT_DATA_ATTR (with a KMF_DATA record) to
2N/A * use for the key to the verification step. If a certificate
2N/A * is used and that certificate has the KeyUsage extension,
2N/A * the SIGN-DATA bit must be set. Also, if a certificate
2N/A * is used, the verification will be done in a specific
2N/A * keystore mechanism.
2N/A *
2N/A * If a KMF_KEY_HANDLE is given in the attribute list, the
2N/A * verification will occur in the framework itself using
2N/A * PKCS#11 C_Verify functions.
2N/A */
2N/AKMF_RETURN
2N/Akmf_verify_data(KMF_HANDLE_T handle,
2N/A int num_args,
2N/A KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_PLUGIN *plugin;
2N/A KMF_KEYSTORE_TYPE kstype;
2N/A uint32_t len;
2N/A KMF_DATA derkey = {0, NULL};
2N/A KMF_KEY_HANDLE *KMFKey;
2N/A KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_NONE;
2N/A KMF_DATA *indata;
2N/A KMF_DATA *insig;
2N/A KMF_DATA *signer_cert;
2N/A KMF_X509_SPKI spki;
2N/A KMF_POLICY_RECORD *policy;
2N/A
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_DATA_ATTR, FALSE, sizeof (KMF_DATA),
2N/A sizeof (KMF_DATA)},
2N/A {KMF_IN_SIGN_ATTR, FALSE, sizeof (KMF_DATA),
2N/A sizeof (KMF_DATA)}
2N/A };
2N/A
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, num_args, attrlist);
2N/A
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A KMFKey = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, num_args);
2N/A signer_cert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
2N/A num_args);
2N/A if (KMFKey == NULL && signer_cert == NULL) {
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A }
2N/A
2N/A /* kstype is only needed if the signer cert is not present */
2N/A if (signer_cert == NULL) {
2N/A len = sizeof (kstype);
2N/A ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, num_args,
2N/A &kstype, &len);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A }
2N/A
2N/A len = sizeof (sigAlg);
2N/A ret = kmf_get_attr(KMF_ALGORITHM_INDEX_ATTR, attrlist, num_args,
2N/A &sigAlg, &len);
2N/A
2N/A /* We only need the algorithm index if we don't have a signer cert. */
2N/A if (ret != KMF_OK && signer_cert == NULL)
2N/A return (ret);
2N/A
2N/A indata = kmf_get_attr_ptr(KMF_DATA_ATTR, attrlist, num_args);
2N/A if (indata == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A insig = kmf_get_attr_ptr(KMF_IN_SIGN_ATTR, attrlist, num_args);
2N/A if (insig == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* If the caller passed a signer cert instead of a key use it. */
2N/A if (signer_cert != NULL) {
2N/A KMF_X509_CERTIFICATE *SignerCert = NULL;
2N/A
2N/A policy = handle->policy;
2N/A ret = check_key_usage(handle, signer_cert, KMF_KU_SIGN_DATA);
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
2N/A ret = KMF_OK;
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Decode the signer cert so we can get the SPKI data */
2N/A ret = DerDecodeSignedCertificate(signer_cert, &SignerCert);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* If no algorithm specified, use the certs signature alg */
2N/A if (sigAlg == KMF_ALGID_NONE)
2N/A sigAlg = x509_algoid_to_algid(CERT_ALG_OID(SignerCert));
2N/A
2N/A if (sigAlg == KMF_ALGID_NONE) {
2N/A kmf_free_signed_cert(SignerCert);
2N/A free(SignerCert);
2N/A return (KMF_ERR_BAD_ALGORITHM);
2N/A }
2N/A
2N/A /*
2N/A * Verify the data locally (i.e. using PKCS#11).
2N/A * The verify operation uses a public key and does not
2N/A * require access to a specific keystore. Save time
2N/A * (and code) by just using the frameworks implementation
2N/A * of the verify operation using crypto framework
2N/A * APIs.
2N/A */
2N/A ret = PKCS_VerifyData(handle, sigAlg,
2N/A &SignerCert->certificate.subjectPublicKeyInfo,
2N/A indata, insig);
2N/A
2N/A kmf_free_signed_cert(SignerCert);
2N/A free(SignerCert);
2N/A } else {
2N/A /* Retrieve public key data from keystore */
2N/A plugin = FindPlugin(handle, kstype);
2N/A if (plugin != NULL &&
2N/A plugin->funclist->EncodePubkeyData != NULL) {
2N/A ret = plugin->funclist->EncodePubkeyData(handle,
2N/A KMFKey, &derkey);
2N/A } else {
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A }
2N/A
2N/A ret = DerDecodeSPKI(&derkey, &spki);
2N/A if (ret == KMF_OK)
2N/A ret = PKCS_VerifyData(handle, sigAlg, &spki,
2N/A indata, insig);
2N/A
2N/A if (derkey.Data != NULL)
2N/A free(derkey.Data);
2N/A
2N/A kmf_free_algoid(&spki.algorithm);
2N/A kmf_free_data(&spki.subjectPublicKey);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A/*
2N/A * Name: kmf_verify_cert
2N/A *
2N/A * Description:
2N/A * This function verifies that the a certificate was signed
2N/A * using a specific private key and that the certificate has not
2N/A * been altered since it was signed using that private key
2N/A * The public key used for verification may be given in the
2N/A * attribute list as a KMF_KEY_HANDLE or the caller may give
2N/A * just the signing certificate (as KMF_SIGNER_CERT_DATA_ATTR)
2N/A * from which the public key needed for verification can be
2N/A * derived.
2N/A *
2N/A * Parameters:
2N/A * handle(input) - opaque handle for KMF session
2N/A * numattr - number of attributes in the list
2N/A * attrlist - KMF_ATTRIBUTES
2N/A *
2N/A * Returns:
2N/A * A KMF_RETURN value indicating success or specifying a particular
2N/A * error condition. The value KMF_OK indicates success. All other
2N/A * values represent an error condition.
2N/A */
2N/AKMF_RETURN
2N/Akmf_verify_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_RETURN ret;
2N/A KMF_DATA derkey = {0, NULL};
2N/A KMF_PLUGIN *plugin;
2N/A KMF_KEY_HANDLE *KMFKey;
2N/A KMF_DATA *CertToBeVerified;
2N/A KMF_DATA *SignerCert;
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)}
2N/A };
2N/A
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A KMFKey = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
2N/A SignerCert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A
2N/A /*
2N/A * Caller must provide at least a key handle or a cert to use
2N/A * as the "key" for verification.
2N/A */
2N/A if (KMFKey == NULL && SignerCert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CertToBeVerified = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A if (CertToBeVerified == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (SignerCert != NULL) {
2N/A ret = verify_cert_with_cert(handle, CertToBeVerified,
2N/A SignerCert);
2N/A } else {
2N/A /*
2N/A * The keystore must extract the pubkey data because
2N/A * the framework doesn't have access to the raw key bytes
2N/A * that are needed to construct the DER encoded public
2N/A * key information needed for the verify operation.
2N/A */
2N/A plugin = FindPlugin(handle, KMFKey->kstype);
2N/A if (plugin != NULL && plugin->funclist->EncodePubkeyData !=
2N/A NULL) {
2N/A ret = plugin->funclist->EncodePubkeyData(handle,
2N/A KMFKey, &derkey);
2N/A } else {
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A }
2N/A
2N/A if (ret == KMF_OK && derkey.Length > 0) {
2N/A ret = verify_cert_with_key(handle, &derkey,
2N/A CertToBeVerified);
2N/A
2N/A if (derkey.Data != NULL)
2N/A free(derkey.Data);
2N/A }
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Name: kmf_encrypt
2N/A *
2N/A * Description:
2N/A * Uses the public key from the cert to encrypt the plaintext
2N/A * into the ciphertext.
2N/A *
2N/A * Parameters:
2N/A * handle(input) - opaque handle for KMF session
2N/A * cert(input) - pointer to a DER encoded certificate for encryption
2N/A * by using its public key
2N/A * plaintext(input) - pointer to the plaintext to be encrypted
2N/A * ciphertext(output) - pointer to the ciphertext contains
2N/A * encrypted data
2N/A *
2N/A * Returns:
2N/A * A KMF_RETURN value indicating success or specifying a particular
2N/A * error condition.
2N/A * The value KMF_OK indicates success. All other values represent
2N/A * an error condition.
2N/A *
2N/A */
2N/AKMF_RETURN
2N/Akmf_encrypt(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_RETURN ret;
2N/A KMF_X509_CERTIFICATE *x509cert = NULL;
2N/A KMF_X509_SPKI *pubkey;
2N/A KMF_OID *alg;
2N/A KMF_ALGORITHM_INDEX algid;
2N/A KMF_DATA *cert;
2N/A KMF_DATA *plaintext;
2N/A KMF_DATA *ciphertext;
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
2N/A sizeof (KMF_DATA)},
2N/A {KMF_PLAINTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
2N/A sizeof (KMF_DATA)},
2N/A {KMF_CIPHERTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
2N/A sizeof (KMF_DATA)}
2N/A };
2N/A
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A plaintext = kmf_get_attr_ptr(KMF_PLAINTEXT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A ciphertext = kmf_get_attr_ptr(KMF_CIPHERTEXT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A
2N/A if (cert == NULL || plaintext == NULL || ciphertext == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* check the keyUsage of the certificate */
2N/A policy = handle->policy;
2N/A ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA);
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
2N/A ret = KMF_OK;
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Decode the cert so we can get the SPKI data */
2N/A if ((ret = DerDecodeSignedCertificate(cert, &x509cert)) != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Get the public key info from the certificate */
2N/A pubkey = &x509cert->certificate.subjectPublicKeyInfo;
2N/A
2N/A /* Use the algorithm in SPKI to encrypt data */
2N/A alg = &pubkey->algorithm.algorithm;
2N/A
2N/A algid = x509_algoid_to_algid(alg);
2N/A
2N/A /* [EC]DSA does not support encrypt */
2N/A if (algid == KMF_ALGID_DSA ||
2N/A algid == KMF_ALGID_SHA1WithDSA ||
2N/A algid == KMF_ALGID_SHA256WithDSA ||
2N/A algid == KMF_ALGID_SHA1WithECDSA ||
2N/A algid == KMF_ALGID_SHA256WithECDSA ||
2N/A algid == KMF_ALGID_SHA384WithECDSA ||
2N/A algid == KMF_ALGID_SHA512WithECDSA ||
2N/A algid == KMF_ALGID_NONE) {
2N/A kmf_free_signed_cert(x509cert);
2N/A free(x509cert);
2N/A return (KMF_ERR_BAD_ALGORITHM);
2N/A }
2N/A
2N/A /*
2N/A * Encrypt using the crypto framework (not the KMF plugin mechanism).
2N/A */
2N/A ret = PKCS_EncryptData(handle, algid, pubkey, plaintext, ciphertext);
2N/A
2N/A kmf_free_signed_cert(x509cert);
2N/A free(x509cert);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Name: kmf_decrypt
2N/A *
2N/A * Description:
2N/A * Uses the private key associated with the cert to decrypt
2N/A * the ciphertext into the plaintext.
2N/A */
2N/AKMF_RETURN
2N/Akmf_decrypt(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_RETURN ret;
2N/A KMF_X509_CERTIFICATE *x509cert = NULL;
2N/A KMF_X509_SPKI *spki_ptr;
2N/A KMF_PLUGIN *plugin;
2N/A KMF_ALGORITHM_INDEX AlgorithmId;
2N/A KMF_ATTRIBUTE *new_attrlist = NULL;
2N/A int new_numattr;
2N/A KMF_DATA *cert = NULL;
2N/A KMF_DATA *ciphertext = NULL;
2N/A KMF_DATA *plaintext = NULL;
2N/A KMF_KEY_HANDLE prikey;
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
2N/A {KMF_PLAINTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
2N/A sizeof (KMF_DATA)},
2N/A {KMF_CIPHERTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
2N/A sizeof (KMF_DATA)},
2N/A };
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A
2N/A /* Get the cert and check its keyUsage */
2N/A cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A if (cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* check the keyUsage of the certificate */
2N/A policy = handle->policy;
2N/A ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA);
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
2N/A ret = KMF_OK;
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Get the ciphertext and plaintext attributes */
2N/A ciphertext = kmf_get_attr_ptr(KMF_CIPHERTEXT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A if (ciphertext == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A plaintext = kmf_get_attr_ptr(KMF_PLAINTEXT_DATA_ATTR, attrlist,
2N/A numattr);
2N/A if (plaintext == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /*
2N/A * Retrieve the private key from the keystore based on
2N/A * the certificate.
2N/A */
2N/A ret = setup_findprikey_attrlist(attrlist, numattr, &new_attrlist,
2N/A &new_numattr, &prikey, cert);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A ret = kmf_find_prikey_by_cert(handle, new_numattr, new_attrlist);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A /* Decode the cert so we can get the alogorithm */
2N/A ret = DerDecodeSignedCertificate(cert, &x509cert);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A spki_ptr = &x509cert->certificate.subjectPublicKeyInfo;
2N/A AlgorithmId = x509_algoid_to_algid((KMF_OID *)
2N/A &spki_ptr->algorithm.algorithm);
2N/A
2N/A /* [EC]DSA does not support decrypt */
2N/A if (AlgorithmId == KMF_ALGID_DSA ||
2N/A AlgorithmId == KMF_ALGID_ECDSA) {
2N/A ret = KMF_ERR_BAD_ALGORITHM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A plugin = FindPlugin(handle, prikey.kstype);
2N/A
2N/A if (plugin != NULL && plugin->funclist->DecryptData != NULL) {
2N/A ret = plugin->funclist->DecryptData(handle,
2N/A &prikey, &spki_ptr->algorithm.algorithm,
2N/A ciphertext, plaintext);
2N/A } else {
2N/A ret = KMF_ERR_PLUGIN_NOTFOUND;
2N/A }
2N/A
2N/Acleanup:
2N/A if (new_attrlist != NULL)
2N/A free(new_attrlist);
2N/A
2N/A kmf_free_kmf_key(handle, &prikey);
2N/A kmf_free_signed_cert(x509cert);
2N/A free(x509cert);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_store_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_KEYSTORE_TYPE kstype;
2N/A
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
2N/A };
2N/A
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
2N/A &kstype, NULL);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A plugin = FindPlugin(handle, kstype);
2N/A if (plugin == NULL || plugin->funclist->StoreCert == NULL)
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A
2N/A return (plugin->funclist->StoreCert(handle, numattr, attrlist));
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_import_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_KEYSTORE_TYPE kstype;
2N/A
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_CERT_FILENAME_ATTR, TRUE, 1, 0},
2N/A };
2N/A
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs, 0, NULL,
2N/A numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
2N/A &kstype, NULL);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A plugin = FindPlugin(handle, kstype);
2N/A if (plugin == NULL || plugin->funclist->ImportCert == NULL)
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A
2N/A return (plugin->funclist->ImportCert(handle, numattr, attrlist));
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_delete_cert_from_keystore(KMF_HANDLE_T handle, int numattr,
2N/A KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_KEYSTORE_TYPE kstype;
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)}
2N/A };
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
2N/A &kstype, NULL);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A plugin = FindPlugin(handle, kstype);
2N/A if (plugin == NULL || plugin->funclist->DeleteCert == NULL)
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A
2N/A return (plugin->funclist->DeleteCert(handle, numattr, attrlist));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * This function gets the CRL URI entries from the certificate's Distribution
2N/A * points extension, and downloads the CRL file. The function also returns
2N/A * the URI string and the format of the CRL file. The caller should free
2N/A * the space allocated for the returned URI string.
2N/A */
2N/Astatic KMF_RETURN
2N/Acert_get_crl(KMF_HANDLE_T handle, const KMF_DATA *cert, char *proxy,
2N/A char *filename, char **retn_uri, KMF_ENCODE_FORMAT *format)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_X509EXT_CRLDISTPOINTS crl_dps;
2N/A boolean_t done = B_FALSE;
2N/A char uri[1024];
2N/A char *proxyname = NULL;
2N/A char *proxy_port_s = NULL;
2N/A int proxy_port = 0;
2N/A int i, j;
2N/A char *path = NULL;
2N/A
2N/A if (handle == NULL || cert == NULL || filename == NULL ||
2N/A retn_uri == NULL || format == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* Get the proxy info */
2N/A if (proxy != NULL) {
2N/A proxyname = strtok(proxy, ":");
2N/A proxy_port_s = strtok(NULL, "\0");
2N/A if (proxy_port_s != NULL) {
2N/A proxy_port = strtol(proxy_port_s, NULL, 0);
2N/A } else {
2N/A proxy_port = 8080; /* default */
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Get the CRL URI from the certificate's CRL Distribution
2N/A * Points extension and download the CRL file. There maybe more than
2N/A * one CRL URI entries in the DP extension, so we will continue
2N/A * the process until a CRL file is successfully downloaded or we
2N/A * are running out the CRL URI's.
2N/A */
2N/A ret = kmf_get_cert_crl_dist_pts((const KMF_DATA *)cert,
2N/A &crl_dps);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A
2N/A for (i = 0; i < crl_dps.number; i++) {
2N/A KMF_CRL_DIST_POINT *dp = &(crl_dps.dplist[i]);
2N/A KMF_GENERALNAMES *fullname = &(dp->name.full_name);
2N/A KMF_DATA *data;
2N/A
2N/A if (done)
2N/A break;
2N/A for (j = 0; j < fullname->number; j++) {
2N/A data = &(fullname->namelist[j].name);
2N/A (void) memcpy(uri, data->Data, data->Length);
2N/A uri[data->Length] = '\0';
2N/A ret = kmf_download_crl(handle, uri, proxyname,
2N/A proxy_port, 30, filename, format);
2N/A if (ret == KMF_OK) {
2N/A done = B_TRUE;
2N/A path = malloc(data->Length + 1);
2N/A if (path == NULL) {
2N/A ret = KMF_ERR_MEMORY;
2N/A goto out;
2N/A }
2N/A (void) strncpy(path, uri, data->Length);
2N/A *retn_uri = path;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/Aout:
2N/A kmf_free_crl_dist_pts(&crl_dps);
2N/A return (ret);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Acheck_crl_validity(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE kstype,
2N/A char *crlfilename, KMF_DATA *issuer_cert)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_POLICY_RECORD *policy;
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A policy = handle->policy;
2N/A
2N/A /*
2N/A * NSS CRL is not file based, and its signature
2N/A * has been verified during CRL import.
2N/A * We only check CRL validity for file-based CRLs,
2N/A * NSS handles these checks internally.
2N/A */
2N/A if (kstype == KMF_KEYSTORE_NSS)
2N/A return (KMF_OK);
2N/A
2N/A /*
2N/A * Check the CRL signature if needed.
2N/A */
2N/A if (!policy->validation_info.crl_info.ignore_crl_sign) {
2N/A ret = kmf_verify_crl_file(handle, crlfilename,
2N/A issuer_cert);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A }
2N/A /*
2N/A * Check the CRL validity if needed.
2N/A */
2N/A if (!policy->validation_info.crl_info.ignore_crl_date) {
2N/A ret = kmf_check_crl_date(handle, crlfilename);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Acert_crl_check(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
2N/A KMF_DATA *user_cert, KMF_DATA *issuer_cert)
2N/A{
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_ATTRIBUTE attrlist[16];
2N/A int numattr = 0;
2N/A int fd, temp_fd;
2N/A boolean_t crlchk;
2N/A char user_certfile[MAXPATHLEN];
2N/A char crlfile_tmp[MAXPATHLEN];
2N/A char *basefilename = NULL;
2N/A char *dir = NULL;
2N/A char *crlfilename = NULL;
2N/A char *proxy = NULL;
2N/A char *uri = NULL;
2N/A KMF_ENCODE_FORMAT format;
2N/A
2N/A if (handle == NULL || kstype == NULL || user_cert == NULL ||
2N/A issuer_cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (!is_valid_keystore_type(*kstype))
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A policy = handle->policy;
2N/A
2N/A /*
2N/A * If the get-crl-uri policy is TRUE, then download the CRL
2N/A * file first. The newly downloaded file will be stored in the
2N/A * NSS internal database for NSS keystore, and stored in a file for
2N/A * the File-based CRL plugins (OpenSSL and PKCS11).
2N/A *
2N/A * For file-based plugins, if the get-crl-uri policy is FALSE,
2N/A * then the caller should provide a CRL file in the policy.
2N/A * Also, after this step is done, the "crlfilename" variable should
2N/A * contain the proper CRL file to be used for the rest of CRL
2N/A * validation process.
2N/A */
2N/A basefilename = policy->validation_info.crl_info.basefilename;
2N/A dir = policy->validation_info.crl_info.directory;
2N/A if (policy->validation_info.crl_info.get_crl_uri) {
2N/A /*
2N/A * Check to see if we already have this CRL.
2N/A */
2N/A if (basefilename == NULL)
2N/A basefilename = basename(uri);
2N/A
2N/A crlfilename = get_fullpath(dir == NULL ? "./" : dir,
2N/A basefilename);
2N/A if (crlfilename == NULL) {
2N/A ret = KMF_ERR_BAD_CRLFILE;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /*
2N/A * If this file already exists and is valid, we don't need to
2N/A * download a new one.
2N/A */
2N/A if ((fd = open(crlfilename, O_RDONLY)) != -1) {
2N/A (void) close(fd);
2N/A if ((ret = check_crl_validity(handle, *kstype,
2N/A crlfilename, issuer_cert)) == KMF_OK) {
2N/A goto checkcrl;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Create a temporary file to hold the new CRL file initially.
2N/A */
2N/A (void) strlcpy(crlfile_tmp, CRLFILE_TEMPNAME,
2N/A sizeof (crlfile_tmp));
2N/A if ((temp_fd = mkstemp(crlfile_tmp)) == -1) {
2N/A ret = KMF_ERR_INTERNAL;
2N/A goto cleanup;
2N/A }
2N/A (void) close(temp_fd);
2N/A
2N/A /*
2N/A * Get the URI entry from the certificate's CRL distribution
2N/A * points extension and download the CRL file.
2N/A */
2N/A proxy = policy->validation_info.crl_info.proxy;
2N/A ret = cert_get_crl(handle, user_cert, proxy, crlfile_tmp,
2N/A &uri, &format);
2N/A if (ret != KMF_OK) {
2N/A (void) unlink(crlfile_tmp);
2N/A goto cleanup;
2N/A }
2N/A /*
2N/A * If we just downloaded one, make sure it is OK.
2N/A */
2N/A if ((ret = check_crl_validity(handle, *kstype, crlfile_tmp,
2N/A issuer_cert)) != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Cache the CRL file. */
2N/A if (*kstype == KMF_KEYSTORE_NSS) {
2N/A /*
2N/A * For NSS keystore, import this CRL file into th
2N/A * internal database.
2N/A */
2N/A numattr = 0;
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_KEYSTORE_TYPE_ATTR, kstype, sizeof (kstype));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_CRL_FILENAME_ATTR, crlfile_tmp,
2N/A strlen(crlfile_tmp));
2N/A numattr++;
2N/A
2N/A crlchk = B_FALSE;
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_CRL_CHECK_ATTR, &crlchk, sizeof (boolean_t));
2N/A numattr++;
2N/A
2N/A ret = kmf_import_crl(handle, numattr, attrlist);
2N/A (void) unlink(crlfile_tmp);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A } else {
2N/A if (rename(crlfile_tmp, crlfilename) == -1) {
2N/A (void) unlink(crlfile_tmp);
2N/A ret = KMF_ERR_WRITE_FILE;
2N/A goto cleanup;
2N/A }
2N/A }
2N/A } else {
2N/A /*
2N/A * If the get_crl_uri policy is FALSE, for File-based CRL
2N/A * plugins, get the input CRL file from the policy.
2N/A */
2N/A if (*kstype != KMF_KEYSTORE_NSS) {
2N/A if (basefilename == NULL) {
2N/A ret = KMF_ERR_BAD_PARAMETER;
2N/A goto cleanup;
2N/A }
2N/A
2N/A crlfilename = get_fullpath(dir == NULL ? "./" : dir,
2N/A basefilename);
2N/A if (crlfilename == NULL) {
2N/A ret = KMF_ERR_BAD_CRLFILE;
2N/A goto cleanup;
2N/A }
2N/A /*
2N/A * Make sure this CRL is still valid.
2N/A */
2N/A if ((ret = check_crl_validity(handle, *kstype,
2N/A crlfilename, issuer_cert)) != KMF_OK)
2N/A return (ret);
2N/A }
2N/A }
2N/A
2N/Acheckcrl:
2N/A /*
2N/A * Check the CRL revocation for the certificate.
2N/A */
2N/A numattr = 0;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
2N/A kstype, sizeof (kstype));
2N/A numattr++;
2N/A
2N/A switch (*kstype) {
2N/A case KMF_KEYSTORE_NSS:
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_CERT_DATA_ATTR, user_cert, sizeof (KMF_DATA));
2N/A numattr++;
2N/A break;
2N/A case KMF_KEYSTORE_PK11TOKEN:
2N/A case KMF_KEYSTORE_OPENSSL:
2N/A /*
2N/A * Create temporary file to hold the user certificate.
2N/A */
2N/A (void) strlcpy(user_certfile, CERTFILE_TEMPNAME,
2N/A sizeof (user_certfile));
2N/A if ((temp_fd = mkstemp(user_certfile)) == -1) {
2N/A ret = KMF_ERR_INTERNAL;
2N/A goto cleanup;
2N/A }
2N/A (void) close(temp_fd);
2N/A
2N/A ret = kmf_create_cert_file(user_cert, KMF_FORMAT_ASN1,
2N/A user_certfile);
2N/A if (ret != KMF_OK) {
2N/A goto cleanup;
2N/A }
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_CERT_FILENAME_ATTR,
2N/A user_certfile, strlen(user_certfile));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_CRL_FILENAME_ATTR,
2N/A crlfilename, strlen(crlfilename));
2N/A numattr++;
2N/A break;
2N/A default:
2N/A ret = KMF_ERR_PLUGIN_NOTFOUND;
2N/A goto cleanup;
2N/A }
2N/A
2N/A ret = kmf_find_cert_in_crl(handle, numattr, attrlist);
2N/A if (ret == KMF_ERR_NOT_REVOKED) {
2N/A ret = KMF_OK;
2N/A }
2N/A
2N/Acleanup:
2N/A (void) unlink(user_certfile);
2N/A
2N/A if (crlfilename != NULL)
2N/A free(crlfilename);
2N/A
2N/A if (uri != NULL)
2N/A free(uri);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Acert_ocsp_check(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
2N/A KMF_DATA *user_cert, KMF_DATA *issuer_cert, KMF_DATA *response,
2N/A char *slotlabel, char *dirpath)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_DATA *new_response = NULL;
2N/A boolean_t ignore_response_sign = B_FALSE;
2N/A uint32_t ltime = 0;
2N/A KMF_DATA *signer_cert = NULL;
2N/A KMF_BIGINT sernum = { NULL, 0 };
2N/A int response_status;
2N/A int reason;
2N/A int cert_status;
2N/A KMF_ATTRIBUTE attrlist[32];
2N/A int numattr;
2N/A
2N/A if (handle == NULL || kstype == NULL || user_cert == NULL ||
2N/A issuer_cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A policy = handle->policy;
2N/A
2N/A /*
2N/A * Get the response lifetime from policy.
2N/A */
2N/A if (policy->VAL_OCSP_BASIC.response_lifetime != NULL &&
2N/A (str2lifetime(policy->VAL_OCSP_BASIC.response_lifetime, &ltime)
2N/A < 0))
2N/A return (KMF_ERR_OCSP_RESPONSE_LIFETIME);
2N/A
2N/A /*
2N/A * Get the ignore_response_sign policy.
2N/A *
2N/A * If ignore_response_sign is FALSE, we need to verify the response.
2N/A * Find the OCSP Responder certificate if it is specified in the OCSP
2N/A * policy.
2N/A */
2N/A ignore_response_sign = policy->VAL_OCSP_BASIC.ignore_response_sign;
2N/A
2N/A if (ignore_response_sign == B_FALSE &&
2N/A policy->VAL_OCSP.has_resp_cert == B_TRUE) {
2N/A char *signer_name;
2N/A KMF_X509_DER_CERT signer_retrcert;
2N/A uchar_t *bytes = NULL;
2N/A size_t bytelen;
2N/A uint32_t num = 0;
2N/A KMF_ATTRIBUTE fc_attrlist[16];
2N/A int fc_numattr = 0;
2N/A char *dir = "./";
2N/A
2N/A if (policy->VAL_OCSP_RESP_CERT.name == NULL ||
2N/A policy->VAL_OCSP_RESP_CERT.serial == NULL)
2N/A return (KMF_ERR_POLICY_NOT_FOUND);
2N/A
2N/A signer_cert = malloc(sizeof (KMF_DATA));
2N/A if (signer_cert == NULL) {
2N/A ret = KMF_ERR_MEMORY;
2N/A goto out;
2N/A }
2N/A (void) memset(signer_cert, 0, sizeof (KMF_DATA));
2N/A
2N/A signer_name = policy->VAL_OCSP_RESP_CERT.name;
2N/A ret = kmf_hexstr_to_bytes(
2N/A (uchar_t *)policy->VAL_OCSP_RESP_CERT.serial,
2N/A &bytes, &bytelen);
2N/A if (ret != KMF_OK || bytes == NULL) {
2N/A ret = KMF_ERR_OCSP_POLICY;
2N/A goto out;
2N/A }
2N/A sernum.val = bytes;
2N/A sernum.len = bytelen;
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_KEYSTORE_TYPE_ATTR, kstype,
2N/A sizeof (KMF_KEYSTORE_TYPE));
2N/A fc_numattr++;
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_SUBJECT_NAME_ATTR, signer_name, strlen(signer_name));
2N/A fc_numattr++;
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_BIGINT_ATTR,
2N/A &sernum, sizeof (KMF_BIGINT));
2N/A fc_numattr++;
2N/A
2N/A if (*kstype == KMF_KEYSTORE_NSS && slotlabel != NULL) {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_TOKEN_LABEL_ATTR, slotlabel,
2N/A strlen(slotlabel));
2N/A fc_numattr++;
2N/A }
2N/A
2N/A if (*kstype == KMF_KEYSTORE_OPENSSL) {
2N/A if (dirpath == NULL) {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_DIRPATH_ATTR, dir, strlen(dir));
2N/A fc_numattr++;
2N/A } else {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_DIRPATH_ATTR, dirpath,
2N/A strlen(dirpath));
2N/A fc_numattr++;
2N/A }
2N/A }
2N/A
2N/A num = 0;
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_COUNT_ATTR, &num, sizeof (uint32_t));
2N/A fc_numattr++;
2N/A
2N/A ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
2N/A if (ret != KMF_OK || num != 1) {
2N/A if (num == 0)
2N/A ret = KMF_ERR_CERT_NOT_FOUND;
2N/A if (num > 0)
2N/A ret = KMF_ERR_CERT_MULTIPLE_FOUND;
2N/A goto out;
2N/A }
2N/A
2N/A (void) memset(&signer_retrcert, 0, sizeof (KMF_X509_DER_CERT));
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_X509_DER_CERT_ATTR, &signer_retrcert,
2N/A sizeof (KMF_X509_DER_CERT));
2N/A fc_numattr++;
2N/A
2N/A ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
2N/A if (ret == KMF_OK) {
2N/A signer_cert->Length =
2N/A signer_retrcert.certificate.Length;
2N/A signer_cert->Data = signer_retrcert.certificate.Data;
2N/A } else {
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If the caller provides an OCSP response, we will use it directly.
2N/A * Otherwise, we will try to fetch an OCSP response for the given
2N/A * certificate now.
2N/A */
2N/A if (response == NULL) {
2N/A new_response = (KMF_DATA *) malloc(sizeof (KMF_DATA));
2N/A if (new_response == NULL) {
2N/A ret = KMF_ERR_MEMORY;
2N/A goto out;
2N/A }
2N/A new_response->Data = NULL;
2N/A new_response->Length = 0;
2N/A
2N/A ret = kmf_get_ocsp_for_cert(handle, user_cert, issuer_cert,
2N/A new_response);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Process the OCSP response and retrieve the certificate status.
2N/A */
2N/A numattr = 0;
2N/A kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_CERT_DATA_ATTR,
2N/A issuer_cert, sizeof (KMF_DATA));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr, KMF_USER_CERT_DATA_ATTR,
2N/A user_cert, sizeof (KMF_DATA));
2N/A numattr++;
2N/A
2N/A if (signer_cert != NULL) {
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_SIGNER_CERT_DATA_ATTR, user_cert, sizeof (KMF_DATA));
2N/A numattr++;
2N/A }
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr, KMF_OCSP_RESPONSE_DATA_ATTR,
2N/A response == NULL ? new_response : response, sizeof (KMF_DATA));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr, KMF_RESPONSE_LIFETIME_ATTR,
2N/A &ltime, sizeof (uint32_t));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_IGNORE_RESPONSE_SIGN_ATTR, &ignore_response_sign,
2N/A sizeof (boolean_t));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_OCSP_RESPONSE_STATUS_ATTR, &response_status, sizeof (int));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_OCSP_RESPONSE_REASON_ATTR, &reason, sizeof (int));
2N/A numattr++;
2N/A
2N/A kmf_set_attr_at_index(attrlist, numattr,
2N/A KMF_OCSP_RESPONSE_CERT_STATUS_ATTR, &cert_status, sizeof (int));
2N/A numattr++;
2N/A
2N/A ret = kmf_get_ocsp_status_for_cert(handle, numattr, attrlist);
2N/A if (ret == KMF_OK) {
2N/A switch (cert_status) {
2N/A case OCSP_GOOD:
2N/A break;
2N/A case OCSP_UNKNOWN:
2N/A ret = KMF_ERR_OCSP_UNKNOWN_CERT;
2N/A break;
2N/A case OCSP_REVOKED:
2N/A ret = KMF_ERR_OCSP_REVOKED;
2N/A break;
2N/A }
2N/A }
2N/A
2N/Aout:
2N/A if (new_response) {
2N/A kmf_free_data(new_response);
2N/A free(new_response);
2N/A }
2N/A
2N/A if (signer_cert) {
2N/A kmf_free_data(signer_cert);
2N/A free(signer_cert);
2N/A }
2N/A
2N/A if (sernum.val != NULL)
2N/A free(sernum.val);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Acert_ku_check(KMF_HANDLE_T handle, KMF_DATA *cert)
2N/A{
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_X509EXT_KEY_USAGE keyusage;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_X509EXT_BASICCONSTRAINTS constraint;
2N/A KMF_BOOL critical = B_FALSE;
2N/A
2N/A if (handle == NULL || cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A policy = handle->policy;
2N/A (void) memset(&keyusage, 0, sizeof (keyusage));
2N/A ret = kmf_get_cert_ku(cert, &keyusage);
2N/A
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND) {
2N/A if (policy->ku_bits) {
2N/A /* keyusage is not set in cert but is set in policy */
2N/A return (KMF_ERR_KEYUSAGE);
2N/A } else {
2N/A /* no keyusage set in both cert and policy */
2N/A return (KMF_OK);
2N/A }
2N/A }
2N/A
2N/A if (ret != KMF_OK) {
2N/A /* real error */
2N/A return (ret);
2N/A }
2N/A
2N/A /*
2N/A * If KeyCertSign is set, then constraints.cA must be TRUE and
2N/A * marked critical.
2N/A */
2N/A if ((keyusage.KeyUsageBits & KMF_keyCertSign)) {
2N/A (void) memset(&constraint, 0, sizeof (constraint));
2N/A ret = kmf_get_cert_basic_constraint(cert,
2N/A &critical, &constraint);
2N/A
2N/A if (ret != KMF_OK) {
2N/A /* real error */
2N/A return (ret);
2N/A }
2N/A if (!constraint.cA || !critical)
2N/A return (KMF_ERR_KEYUSAGE);
2N/A }
2N/A
2N/A /*
2N/A * Rule: if the KU bit is set in policy, the corresponding KU bit
2N/A * must be set in the certificate (but not vice versa).
2N/A */
2N/A if ((policy->ku_bits & keyusage.KeyUsageBits) == policy->ku_bits) {
2N/A return (KMF_OK);
2N/A } else {
2N/A return (KMF_ERR_KEYUSAGE);
2N/A }
2N/A
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Acert_eku_check(KMF_HANDLE_T handle, KMF_DATA *cert)
2N/A{
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_X509EXT_EKU eku;
2N/A uint16_t cert_eku = 0, policy_eku = 0;
2N/A int i;
2N/A
2N/A if (handle == NULL || cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A policy = handle->policy;
2N/A
2N/A /*
2N/A * If the policy does not have any EKU, then there is
2N/A * nothing further to check.
2N/A */
2N/A if (policy->eku_set.eku_count == 0)
2N/A return (KMF_OK);
2N/A
2N/A ret = kmf_get_cert_eku(cert, &eku);
2N/A if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) {
2N/A /* real error */
2N/A return (ret);
2N/A }
2N/A
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND) {
2N/A cert_eku = 0;
2N/A } else {
2N/A /*
2N/A * Build the EKU bitmap based on the certificate
2N/A */
2N/A for (i = 0; i < eku.nEKUs; i++) {
2N/A if (IsEqualOid(&eku.keyPurposeIdList[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) {
2N/A cert_eku |= KMF_EKU_SERVERAUTH;
2N/A } else if (IsEqualOid(&eku.keyPurposeIdList[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) {
2N/A cert_eku |= KMF_EKU_CLIENTAUTH;
2N/A } else if (IsEqualOid(&eku.keyPurposeIdList[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) {
2N/A cert_eku |= KMF_EKU_CODESIGNING;
2N/A } else if (IsEqualOid(&eku.keyPurposeIdList[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) {
2N/A cert_eku |= KMF_EKU_EMAIL;
2N/A } else if (IsEqualOid(&eku.keyPurposeIdList[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) {
2N/A cert_eku |= KMF_EKU_TIMESTAMP;
2N/A } else if (IsEqualOid(&eku.keyPurposeIdList[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) {
2N/A cert_eku |= KMF_EKU_OCSPSIGNING;
2N/A } else if (!policy->ignore_unknown_ekus) {
2N/A return (KMF_ERR_KEYUSAGE);
2N/A }
2N/A } /* for */
2N/A }
2N/A
2N/A
2N/A /*
2N/A * Build the EKU bitmap based on the policy
2N/A */
2N/A for (i = 0; i < policy->eku_set.eku_count; i++) {
2N/A if (IsEqualOid(&policy->eku_set.ekulist[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) {
2N/A policy_eku |= KMF_EKU_SERVERAUTH;
2N/A } else if (IsEqualOid(&policy->eku_set.ekulist[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) {
2N/A policy_eku |= KMF_EKU_CLIENTAUTH;
2N/A } else if (IsEqualOid(&policy->eku_set.ekulist[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) {
2N/A policy_eku |= KMF_EKU_CODESIGNING;
2N/A } else if (IsEqualOid(&policy->eku_set.ekulist[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) {
2N/A policy_eku |= KMF_EKU_EMAIL;
2N/A } else if (IsEqualOid(&policy->eku_set.ekulist[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) {
2N/A policy_eku |= KMF_EKU_TIMESTAMP;
2N/A } else if (IsEqualOid(&policy->eku_set.ekulist[i],
2N/A (KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) {
2N/A policy_eku |= KMF_EKU_OCSPSIGNING;
2N/A } else if (!policy->ignore_unknown_ekus) {
2N/A return (KMF_ERR_KEYUSAGE);
2N/A }
2N/A } /* for */
2N/A
2N/A /*
2N/A * Rule: if the EKU OID is set in policy, the corresponding EKU OID
2N/A * must be set in the certificate (but not vice versa).
2N/A */
2N/A if ((policy_eku & cert_eku) == policy_eku) {
2N/A return (KMF_OK);
2N/A } else {
2N/A return (KMF_ERR_KEYUSAGE);
2N/A }
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Afind_issuer_cert(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
2N/A char *user_issuer, KMF_DATA *issuer_cert,
2N/A char *slotlabel, char *dirpath)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_X509_DER_CERT *certlist = NULL;
2N/A uint32_t i, num = 0;
2N/A time_t t_notbefore;
2N/A time_t t_notafter;
2N/A time_t latest;
2N/A KMF_DATA tmp_cert = {0, NULL};
2N/A KMF_ATTRIBUTE fc_attrlist[16];
2N/A int fc_numattr = 0;
2N/A char *dir = "./";
2N/A
2N/A if (handle == NULL || kstype == NULL || user_issuer == NULL ||
2N/A issuer_cert == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (!is_valid_keystore_type(*kstype))
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_KEYSTORE_TYPE_ATTR,
2N/A kstype, sizeof (KMF_KEYSTORE_TYPE));
2N/A fc_numattr++;
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_SUBJECT_NAME_ATTR,
2N/A user_issuer, strlen(user_issuer));
2N/A fc_numattr++;
2N/A
2N/A if (*kstype == KMF_KEYSTORE_NSS && slotlabel != NULL) {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_TOKEN_LABEL_ATTR, slotlabel, strlen(slotlabel));
2N/A fc_numattr++;
2N/A }
2N/A
2N/A if (*kstype == KMF_KEYSTORE_OPENSSL) {
2N/A if (dirpath == NULL) {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_DIRPATH_ATTR, dir, strlen(dir));
2N/A fc_numattr++;
2N/A } else {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_DIRPATH_ATTR, dirpath, strlen(dirpath));
2N/A fc_numattr++;
2N/A }
2N/A }
2N/A
2N/A num = 0;
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_COUNT_ATTR, &num, sizeof (uint32_t));
2N/A fc_numattr++;
2N/A
2N/A ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
2N/A
2N/A if (ret == KMF_OK && num > 0) {
2N/A certlist = (KMF_X509_DER_CERT *)malloc(num *
2N/A sizeof (KMF_X509_DER_CERT));
2N/A
2N/A if (certlist == NULL) {
2N/A ret = KMF_ERR_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_X509_DER_CERT_ATTR, certlist,
2N/A sizeof (KMF_X509_DER_CERT));
2N/A fc_numattr++;
2N/A
2N/A ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
2N/A if (ret != KMF_OK) {
2N/A free(certlist);
2N/A certlist = NULL;
2N/A goto out;
2N/A }
2N/A } else {
2N/A goto out;
2N/A }
2N/A
2N/A if (num == 1) {
2N/A /* only one issuer cert is found */
2N/A tmp_cert.Length = certlist[0].certificate.Length;
2N/A tmp_cert.Data = certlist[0].certificate.Data;
2N/A } else {
2N/A /*
2N/A * More than one issuer certs are found. We will
2N/A * pick the latest one.
2N/A */
2N/A latest = 0;
2N/A for (i = 0; i < num; i++) {
2N/A ret = kmf_get_cert_validity(&certlist[i].certificate,
2N/A &t_notbefore, &t_notafter);
2N/A if (ret != KMF_OK) {
2N/A ret = KMF_ERR_VALIDITY_PERIOD;
2N/A goto out;
2N/A }
2N/A
2N/A if (t_notbefore > latest) {
2N/A tmp_cert.Length =
2N/A certlist[i].certificate.Length;
2N/A tmp_cert.Data =
2N/A certlist[i].certificate.Data;
2N/A latest = t_notbefore;
2N/A }
2N/A
2N/A }
2N/A }
2N/A
2N/A issuer_cert->Length = tmp_cert.Length;
2N/A issuer_cert->Data = malloc(tmp_cert.Length);
2N/A if (issuer_cert->Data == NULL) {
2N/A ret = KMF_ERR_MEMORY;
2N/A goto out;
2N/A }
2N/A (void) memcpy(issuer_cert->Data, tmp_cert.Data,
2N/A tmp_cert.Length);
2N/A
2N/Aout:
2N/A if (certlist != NULL) {
2N/A for (i = 0; i < num; i++)
2N/A kmf_free_kmf_cert(handle, &certlist[i]);
2N/A free(certlist);
2N/A }
2N/A
2N/A return (ret);
2N/A
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Afind_ta_cert(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
2N/A KMF_DATA *ta_cert, KMF_X509_NAME *user_issuerDN,
2N/A char *slotlabel, char *dirpath)
2N/A{
2N/A KMF_POLICY_RECORD *policy;
2N/A KMF_RETURN ret = KMF_OK;
2N/A uint32_t num = 0;
2N/A char *ta_name;
2N/A KMF_BIGINT serial = { NULL, 0 };
2N/A uchar_t *bytes = NULL;
2N/A size_t bytelen;
2N/A KMF_X509_DER_CERT ta_retrCert;
2N/A char *ta_subject = NULL;
2N/A KMF_X509_NAME ta_subjectDN;
2N/A KMF_ATTRIBUTE fc_attrlist[16];
2N/A int fc_numattr = 0;
2N/A char *dir = "./";
2N/A
2N/A if (handle == NULL || kstype == NULL || ta_cert == NULL ||
2N/A user_issuerDN == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (!is_valid_keystore_type(*kstype))
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /* Get the TA name and serial number from the policy */
2N/A policy = handle->policy;
2N/A ta_name = policy->ta_name;
2N/A
2N/A /*
2N/A * Use name and serial from policy.
2N/A */
2N/A ret = kmf_hexstr_to_bytes((uchar_t *)policy->ta_serial,
2N/A &bytes, &bytelen);
2N/A if (ret != KMF_OK || bytes == NULL) {
2N/A ret = KMF_ERR_TA_POLICY;
2N/A goto out;
2N/A }
2N/A serial.val = bytes;
2N/A serial.len = bytelen;
2N/A
2N/A /* set up fc_attrlist for kmf_find_cert */
2N/A kmf_set_attr_at_index(fc_attrlist,
2N/A fc_numattr++, KMF_BIGINT_ATTR,
2N/A &serial, sizeof (KMF_BIGINT));
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist,
2N/A fc_numattr++, KMF_SUBJECT_NAME_ATTR,
2N/A ta_name, strlen(ta_name));
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr++, KMF_KEYSTORE_TYPE_ATTR,
2N/A kstype, sizeof (KMF_KEYSTORE_TYPE));
2N/A
2N/A if (*kstype == KMF_KEYSTORE_NSS && slotlabel != NULL) {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
2N/A KMF_TOKEN_LABEL_ATTR, slotlabel, strlen(slotlabel));
2N/A }
2N/A
2N/A if (*kstype == KMF_KEYSTORE_OPENSSL) {
2N/A if (dirpath == NULL) {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
2N/A KMF_DIRPATH_ATTR, dir, strlen(dir));
2N/A } else {
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
2N/A KMF_DIRPATH_ATTR, dirpath, strlen(dirpath));
2N/A }
2N/A }
2N/A
2N/A num = 0;
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
2N/A KMF_COUNT_ATTR, &num, sizeof (uint32_t));
2N/A
2N/A ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
2N/A if (ret != KMF_OK || num != 1) {
2N/A if (num == 0)
2N/A ret = KMF_ERR_CERT_NOT_FOUND;
2N/A if (num > 1)
2N/A ret = KMF_ERR_CERT_MULTIPLE_FOUND;
2N/A goto out;
2N/A }
2N/A
2N/A kmf_set_attr_at_index(fc_attrlist, fc_numattr,
2N/A KMF_X509_DER_CERT_ATTR, &ta_retrCert, sizeof (KMF_X509_DER_CERT));
2N/A fc_numattr++;
2N/A
2N/A ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
2N/A if (ret == KMF_OK) {
2N/A ta_cert->Length = ta_retrCert.certificate.Length;
2N/A ta_cert->Data = malloc(ta_retrCert.certificate.Length);
2N/A if (ta_cert->Data == NULL) {
2N/A ret = KMF_ERR_MEMORY;
2N/A goto out;
2N/A }
2N/A (void) memcpy(ta_cert->Data, ta_retrCert.certificate.Data,
2N/A ta_retrCert.certificate.Length);
2N/A } else {
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * The found TA's name must be matching with issuer name in
2N/A * subscriber's certificate.
2N/A */
2N/A (void) memset(&ta_subjectDN, 0, sizeof (ta_subjectDN));
2N/A
2N/A ret = kmf_get_cert_subject_str(handle, ta_cert, &ta_subject);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A
2N/A ret = kmf_dn_parser(ta_subject, &ta_subjectDN);
2N/A if (ret != KMF_OK)
2N/A goto out;
2N/A
2N/A if (kmf_compare_rdns(user_issuerDN, &ta_subjectDN) != 0)
2N/A ret = KMF_ERR_CERT_NOT_FOUND;
2N/A
2N/A kmf_free_dn(&ta_subjectDN);
2N/A
2N/A /* Make sure the TA cert has the correct extensions */
2N/A if (ret == KMF_OK) {
2N/A ret = check_key_usage(handle, ta_cert, KMF_KU_SIGN_CERT);
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
2N/A ret = KMF_OK;
2N/A }
2N/Aout:
2N/A if (ta_retrCert.certificate.Data)
2N/A kmf_free_kmf_cert(handle, &ta_retrCert);
2N/A
2N/A if ((ret != KMF_OK))
2N/A kmf_free_data(ta_cert);
2N/A
2N/A if (ta_subject != NULL)
2N/A free(ta_subject);
2N/A
2N/A if (serial.val != NULL)
2N/A free(serial.val);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_KEYSTORE_TYPE *kstype = NULL;
2N/A KMF_DATA *pcert = NULL;
2N/A int *result = NULL;
2N/A char *slotlabel = NULL;
2N/A char *dirpath = NULL;
2N/A KMF_DATA *ocsp_response = NULL;
2N/A KMF_DATA ta_cert = {0, NULL};
2N/A KMF_DATA issuer_cert = {0, NULL};
2N/A char *user_issuer = NULL, *user_subject = NULL;
2N/A KMF_X509_NAME user_issuerDN, user_subjectDN;
2N/A boolean_t self_signed = B_FALSE;
2N/A KMF_POLICY_RECORD *policy;
2N/A
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
2N/A {KMF_VALIDATE_RESULT_ATTR, FALSE, 1, sizeof (int)}
2N/A };
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs,
2N/A 0, NULL, numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A policy = handle->policy;
2N/A
2N/A /* Get the attribute values */
2N/A kstype = kmf_get_attr_ptr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr);
2N/A pcert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
2N/A result = kmf_get_attr_ptr(KMF_VALIDATE_RESULT_ATTR, attrlist, numattr);
2N/A if (kstype == NULL || pcert == NULL || result == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A slotlabel = kmf_get_attr_ptr(KMF_TOKEN_LABEL_ATTR, attrlist, numattr);
2N/A dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
2N/A ocsp_response = kmf_get_attr_ptr(KMF_OCSP_RESPONSE_DATA_ATTR, attrlist,
2N/A numattr);
2N/A
2N/A /* Initialize the returned result */
2N/A *result = KMF_CERT_VALIDATE_OK;
2N/A
2N/A /*
2N/A * Get the issuer information from the input certificate first.
2N/A */
2N/A if ((ret = kmf_get_cert_issuer_str(handle, pcert,
2N/A &user_issuer)) != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_USER;
2N/A } else if ((ret = kmf_dn_parser(user_issuer, &user_issuerDN)) !=
2N/A KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_USER;
2N/A }
2N/A
2N/A /*
2N/A * Check if the certificate is a self-signed cert.
2N/A */
2N/A if ((ret = kmf_get_cert_subject_str(handle, pcert,
2N/A &user_subject)) != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_USER;
2N/A } else if ((ret = kmf_dn_parser(user_subject, &user_subjectDN)) !=
2N/A KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_USER;
2N/A }
2N/A
2N/A if ((*result & KMF_CERT_VALIDATE_ERR_USER) == 0 &&
2N/A (kmf_compare_rdns(&user_issuerDN, &user_subjectDN)) == 0) {
2N/A /*
2N/A * this is a self-signed cert
2N/A */
2N/A self_signed = B_TRUE;
2N/A }
2N/A
2N/A kmf_free_dn(&user_subjectDN);
2N/A
2N/A /*
2N/A * Check KeyUsage extension of the subscriber's certificate
2N/A */
2N/A ret = cert_ku_check(handle, pcert);
2N/A if (ret != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_KEYUSAGE;
2N/A }
2N/A
2N/A /*
2N/A * Validate Extended KeyUsage extension
2N/A */
2N/A ret = cert_eku_check(handle, pcert);
2N/A if (ret != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE;
2N/A }
2N/A
2N/A /*
2N/A * Check the certificate's validity period
2N/A *
2N/A * This step is needed when "ignore_date" in policy is set
2N/A * to false.
2N/A */
2N/A if (!policy->ignore_date) {
2N/A /*
2N/A * Validate expiration date
2N/A */
2N/A ret = kmf_check_cert_date(handle, pcert);
2N/A if (ret != KMF_OK)
2N/A *result |= KMF_CERT_VALIDATE_ERR_TIME;
2N/A }
2N/A
2N/A /*
2N/A * When "ignore_trust_anchor" in policy is set to FALSE,
2N/A * we will try to find the TA cert based on the TA policy
2N/A * attributes.
2N/A *
2N/A * TA's subject name (ta_name) and serial number (ta_serial)
2N/A * are defined as optional attributes in policy dtd, but they
2N/A * should exist in policy when "ignore_trust_anchor" is set
2N/A * to FALSE. The policy verification code has enforced that.
2N/A *
2N/A * The serial number may be NULL if the ta_name == "search"
2N/A * which indicates that KMF should try to locate the issuer
2N/A * of the subject cert instead of using a specific TA name.
2N/A */
2N/A if (policy->ignore_trust_anchor) {
2N/A goto check_revocation;
2N/A }
2N/A
2N/A /*
2N/A * Verify the signature of subscriber's certificate using
2N/A * TA certificate.
2N/A */
2N/A if (self_signed) {
2N/A ret = verify_cert_with_cert(handle, pcert, pcert);
2N/A if (ret != KMF_OK)
2N/A *result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
2N/A } else if (user_issuer != NULL) {
2N/A if (policy->ta_name != NULL &&
2N/A strcasecmp(policy->ta_name, "search") == 0) {
2N/A ret = find_issuer_cert(handle, kstype, user_issuer,
2N/A &issuer_cert, slotlabel, dirpath);
2N/A if (ret != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_TA;
2N/A } else {
2N/A ta_cert = issuer_cert; /* used later */
2N/A }
2N/A } else {
2N/A /*
2N/A * If we didnt find the user_issuer string, we
2N/A * won't have a "user_issuerDN" either.
2N/A */
2N/A ret = find_ta_cert(handle, kstype, &ta_cert,
2N/A &user_issuerDN, slotlabel, dirpath);
2N/A }
2N/A if (ret != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_TA;
2N/A }
2N/A
2N/A /* Only verify if we got the TA without an error. */
2N/A if ((*result & KMF_CERT_VALIDATE_ERR_TA) == 0) {
2N/A ret = verify_cert_with_cert(handle, pcert,
2N/A &ta_cert);
2N/A if (ret != KMF_OK)
2N/A *result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
2N/A }
2N/A } else {
2N/A /* No issuer was found, so we cannot find a trust anchor */
2N/A *result |= KMF_CERT_VALIDATE_ERR_TA;
2N/A }
2N/A
2N/Acheck_revocation:
2N/A /*
2N/A * Check certificate revocation
2N/A */
2N/A if (self_signed) {
2N/A /* skip revocation checking */
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * When CRL or OCSP revocation method is set in the policy,
2N/A * we will try to find the issuer of the subscriber certificate
2N/A * using the issuer name of the subscriber certificate. The
2N/A * issuer certificate will be used to do the CRL checking
2N/A * and OCSP checking.
2N/A */
2N/A if (!(policy->revocation & KMF_REVOCATION_METHOD_CRL) &&
2N/A !(policy->revocation & KMF_REVOCATION_METHOD_OCSP)) {
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * If we did not find the issuer cert earlier
2N/A * (when policy->ta_name == "search"), get it here.
2N/A * We need the issuer cert if the revocation method is
2N/A * CRL or OCSP.
2N/A */
2N/A if (issuer_cert.Length == 0 &&
2N/A policy->revocation & KMF_REVOCATION_METHOD_CRL ||
2N/A policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
2N/A ret = find_issuer_cert(handle, kstype, user_issuer,
2N/A &issuer_cert, slotlabel, dirpath);
2N/A if (ret != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_ISSUER;
2N/A }
2N/A }
2N/A
2N/A if (policy->revocation & KMF_REVOCATION_METHOD_CRL &&
2N/A (*result & KMF_CERT_VALIDATE_ERR_ISSUER) == 0) {
2N/A ret = cert_crl_check(handle, kstype, pcert, &issuer_cert);
2N/A if (ret != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_CRL;
2N/A }
2N/A }
2N/A
2N/A if (policy->revocation & KMF_REVOCATION_METHOD_OCSP &&
2N/A (*result & KMF_CERT_VALIDATE_ERR_ISSUER) == 0) {
2N/A ret = cert_ocsp_check(handle, kstype, pcert, &issuer_cert,
2N/A ocsp_response, slotlabel, dirpath);
2N/A if (ret != KMF_OK) {
2N/A *result |= KMF_CERT_VALIDATE_ERR_OCSP;
2N/A }
2N/A }
2N/Aout:
2N/A if (user_issuer) {
2N/A kmf_free_dn(&user_issuerDN);
2N/A free(user_issuer);
2N/A }
2N/A
2N/A if (user_subject)
2N/A free(user_subject);
2N/A
2N/A /*
2N/A * If we did not copy ta_cert to issuer_cert, free it.
2N/A */
2N/A if (issuer_cert.Data &&
2N/A issuer_cert.Data != ta_cert.Data)
2N/A kmf_free_data(&issuer_cert);
2N/A
2N/A kmf_free_data(&ta_cert);
2N/A
2N/A /*
2N/A * If we got an error flag from any of the checks,
2N/A * remap the return code to a generic "CERT_VALIDATION"
2N/A * error so the caller knows to check the individual flags.
2N/A */
2N/A if (*result != 0)
2N/A ret = KMF_ERR_CERT_VALIDATION;
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_create_cert_file(const KMF_DATA *certdata, KMF_ENCODE_FORMAT format,
2N/A char *certfile)
2N/A{
2N/A KMF_RETURN rv = KMF_OK;
2N/A int fd = -1;
2N/A KMF_DATA pemdata = {NULL, 0};
2N/A
2N/A if (certdata == NULL || certfile == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (format != KMF_FORMAT_PEM && format != KMF_FORMAT_ASN1)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (format == KMF_FORMAT_PEM) {
2N/A int len;
2N/A rv = kmf_der_to_pem(KMF_CERT,
2N/A certdata->Data, certdata->Length,
2N/A &pemdata.Data, &len);
2N/A if (rv != KMF_OK)
2N/A goto cleanup;
2N/A pemdata.Length = (size_t)len;
2N/A }
2N/A
2N/A if ((fd = open(certfile, O_CREAT | O_RDWR | O_TRUNC, 0644)) == -1) {
2N/A rv = KMF_ERR_OPEN_FILE;
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (format == KMF_FORMAT_PEM) {
2N/A if (write(fd, pemdata.Data, pemdata.Length) !=
2N/A pemdata.Length) {
2N/A rv = KMF_ERR_WRITE_FILE;
2N/A }
2N/A } else {
2N/A if (write(fd, certdata->Data, certdata->Length) !=
2N/A certdata->Length) {
2N/A rv = KMF_ERR_WRITE_FILE;
2N/A }
2N/A }
2N/A
2N/Acleanup:
2N/A if (fd != -1)
2N/A (void) close(fd);
2N/A
2N/A kmf_free_data(&pemdata);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * kmf_is_cert_data
2N/A *
2N/A * Determine if a KMF_DATA buffer contains an encoded X.509 certificate.
2N/A *
2N/A * Return:
2N/A * KMF_OK if it is a certificate
2N/A * KMF_ERR_ENCODING (or other error) if not.
2N/A */
2N/AKMF_RETURN
2N/Akmf_is_cert_data(KMF_DATA *data, KMF_ENCODE_FORMAT *fmt)
2N/A{
2N/A KMF_RETURN rv = KMF_OK;
2N/A KMF_X509_CERTIFICATE *x509 = NULL;
2N/A KMF_DATA oldpem = {0, NULL};
2N/A uchar_t *d = NULL;
2N/A int len = 0;
2N/A
2N/A if (data == NULL || fmt == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A rv = kmf_get_data_format(data, fmt);
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A switch (*fmt) {
2N/A case KMF_FORMAT_ASN1:
2N/A rv = DerDecodeSignedCertificate(data, &x509);
2N/A break;
2N/A case KMF_FORMAT_PEM:
2N/A /* Convert to ASN.1 DER first */
2N/A rv = kmf_pem_to_der(data->Data, data->Length,
2N/A &d, &len);
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A oldpem.Data = d;
2N/A oldpem.Length = len;
2N/A rv = DerDecodeSignedCertificate(&oldpem, &x509);
2N/A kmf_free_data(&oldpem);
2N/A break;
2N/A case KMF_FORMAT_PKCS12:
2N/A case KMF_FORMAT_UNDEF:
2N/A default:
2N/A return (KMF_ERR_ENCODING);
2N/A }
2N/A
2N/A if (x509 != NULL) {
2N/A kmf_free_signed_cert(x509);
2N/A free(x509);
2N/A }
2N/A return (rv);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_is_cert_file(KMF_HANDLE_T handle, char *filename,
2N/A KMF_ENCODE_FORMAT *pformat)
2N/A{
2N/A KMF_RETURN ret;
2N/A KMF_DATA filedata;
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A if (filename == NULL || pformat == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A ret = kmf_read_input_file(handle, filename, &filedata);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = kmf_is_cert_data(&filedata, pformat);
2N/A if (ret == KMF_ERR_BAD_CERT_FORMAT)
2N/A ret = KMF_ERR_BAD_CERTFILE;
2N/A
2N/A kmf_free_data(&filedata);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * This function checks the validity period of a der-encoded certificate.
2N/A */
2N/AKMF_RETURN
2N/Akmf_check_cert_date(KMF_HANDLE_T handle, const KMF_DATA *cert)
2N/A{
2N/A KMF_RETURN rv;
2N/A struct tm *gmt;
2N/A time_t t_now;
2N/A time_t t_notbefore;
2N/A time_t t_notafter;
2N/A KMF_POLICY_RECORD *policy;
2N/A uint32_t adj;
2N/A
2N/A CLEAR_ERROR(handle, rv);
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A
2N/A if (cert == NULL || cert->Data == NULL || cert->Length == 0)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A policy = handle->policy;
2N/A rv = kmf_get_cert_validity(cert, &t_notbefore, &t_notafter);
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A
2N/A /*
2N/A * Get the current time. The time returned from time() is local which
2N/A * cannot be used directly. It must be converted to UTC/GMT first.
2N/A */
2N/A t_now = time(NULL);
2N/A gmt = gmtime(&t_now);
2N/A t_now = mktime(gmt);
2N/A
2N/A /*
2N/A * Adjust the validity time
2N/A */
2N/A if (policy->validity_adjusttime != NULL) {
2N/A if (str2lifetime(policy->validity_adjusttime, &adj) < 0)
2N/A return (KMF_ERR_VALIDITY_PERIOD);
2N/A } else {
2N/A adj = 0;
2N/A }
2N/A
2N/A t_notafter += adj;
2N/A t_notbefore -= adj;
2N/A
2N/A if (t_now <= t_notafter && t_now >= t_notbefore) {
2N/A rv = KMF_OK;
2N/A } else {
2N/A rv = KMF_ERR_VALIDITY_PERIOD;
2N/A }
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Akmf_export_pk12(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
2N/A{
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_KEYSTORE_TYPE kstype;
2N/A
2N/A KMF_ATTRIBUTE_TESTER required_attrs[] = {
2N/A {KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
2N/A {KMF_OUTPUT_FILENAME_ATTR, TRUE, 1, 0},
2N/A };
2N/A
2N/A int num_req_attrs = sizeof (required_attrs) /
2N/A sizeof (KMF_ATTRIBUTE_TESTER);
2N/A
2N/A if (handle == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A CLEAR_ERROR(handle, ret);
2N/A
2N/A ret = test_attributes(num_req_attrs, required_attrs, 0, NULL,
2N/A numattr, attrlist);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
2N/A &kstype, NULL);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A plugin = FindPlugin(handle, kstype);
2N/A if (plugin == NULL || plugin->funclist->ExportPK12 == NULL)
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A
2N/A return (plugin->funclist->ExportPK12(handle, numattr, attrlist));
2N/A}
2N/A
2N/A
2N/AKMF_RETURN
2N/Akmf_build_pk12(KMF_HANDLE_T handle, int numcerts,
2N/A KMF_X509_DER_CERT *certlist, int numkeys, KMF_KEY_HANDLE *keylist,
2N/A KMF_CREDENTIAL *p12cred, char *filename)
2N/A{
2N/A KMF_RETURN rv;
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN (*buildpk12)(KMF_HANDLE *, int, KMF_X509_DER_CERT *,
2N/A int, KMF_KEY_HANDLE *, KMF_CREDENTIAL *, char *);
2N/A
2N/A CLEAR_ERROR(handle, rv);
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A
2N/A if (filename == NULL || p12cred == NULL ||
2N/A (certlist == NULL && keylist == NULL))
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
2N/A if (plugin == NULL || plugin->dldesc == NULL) {
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A }
2N/A
2N/A buildpk12 = (KMF_RETURN(*)())dlsym(plugin->dldesc,
2N/A "openssl_build_pk12");
2N/A if (buildpk12 == NULL) {
2N/A return (KMF_ERR_FUNCTION_NOT_FOUND);
2N/A }
2N/A
2N/A rv = buildpk12(handle, numcerts, certlist, numkeys, keylist, p12cred,
2N/A filename);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A
2N/AKMF_RETURN
2N/Akmf_import_objects(KMF_HANDLE_T handle, char *filename,
2N/A KMF_CREDENTIAL *cred,
2N/A KMF_X509_DER_CERT **certs, int *ncerts,
2N/A KMF_RAW_KEY_DATA **rawkeys, int *nkeys)
2N/A{
2N/A KMF_RETURN rv;
2N/A KMF_PLUGIN *plugin;
2N/A KMF_RETURN (*import_objects)(KMF_HANDLE *, char *, KMF_CREDENTIAL *,
2N/A KMF_X509_DER_CERT **, int *, KMF_RAW_KEY_DATA **, int *);
2N/A
2N/A CLEAR_ERROR(handle, rv);
2N/A if (rv != KMF_OK)
2N/A return (rv);
2N/A
2N/A if (filename == NULL || cred == NULL || certs == NULL ||
2N/A ncerts == NULL ||rawkeys == NULL || nkeys == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /*
2N/A * Use the Keypair reader from the OpenSSL plugin.
2N/A */
2N/A plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
2N/A if (plugin == NULL || plugin->dldesc == NULL) {
2N/A return (KMF_ERR_PLUGIN_NOTFOUND);
2N/A }
2N/A
2N/A import_objects = (KMF_RETURN(*)())dlsym(plugin->dldesc,
2N/A "openssl_import_objects");
2N/A if (import_objects == NULL) {
2N/A return (KMF_ERR_FUNCTION_NOT_FOUND);
2N/A }
2N/A
2N/A /* Use OpenSSL interfaces to get raw key and cert data */
2N/A rv = import_objects(handle, filename, cred, certs, ncerts,
2N/A rawkeys, nkeys);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/AKMF_BOOL
2N/AIsEqualOid(KMF_OID *Oid1, KMF_OID *Oid2)
2N/A{
2N/A return ((Oid1->Length == Oid2->Length) &&
2N/A !memcmp(Oid1->Data, Oid2->Data, Oid1->Length));
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Aset_algoid(KMF_X509_ALGORITHM_IDENTIFIER *destid,
2N/A KMF_OID *newoid)
2N/A{
2N/A if (destid == NULL || newoid == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A destid->algorithm.Length = newoid->Length;
2N/A destid->algorithm.Data = malloc(destid->algorithm.Length);
2N/A if (destid->algorithm.Data == NULL)
2N/A return (KMF_ERR_MEMORY);
2N/A
2N/A (void) memcpy(destid->algorithm.Data, newoid->Data,
2N/A destid->algorithm.Length);
2N/A
2N/A return (KMF_OK);
2N/A}
2N/A
2N/AKMF_RETURN
2N/Acopy_algoid(KMF_X509_ALGORITHM_IDENTIFIER *destid,
2N/A KMF_X509_ALGORITHM_IDENTIFIER *srcid)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A if (!destid || !srcid)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A destid->algorithm.Length = srcid->algorithm.Length;
2N/A destid->algorithm.Data = malloc(destid->algorithm.Length);
2N/A if (destid->algorithm.Data == NULL)
2N/A return (KMF_ERR_MEMORY);
2N/A
2N/A (void) memcpy(destid->algorithm.Data, srcid->algorithm.Data,
2N/A destid->algorithm.Length);
2N/A
2N/A destid->parameters.Length = srcid->parameters.Length;
2N/A if (destid->parameters.Length > 0) {
2N/A destid->parameters.Data = malloc(destid->parameters.Length);
2N/A if (destid->parameters.Data == NULL)
2N/A return (KMF_ERR_MEMORY);
2N/A
2N/A (void) memcpy(destid->parameters.Data, srcid->parameters.Data,
2N/A destid->parameters.Length);
2N/A } else {
2N/A destid->parameters.Data = NULL;
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Asign_cert(KMF_HANDLE_T handle,
2N/A const KMF_DATA *SubjectCert,
2N/A KMF_KEY_HANDLE *Signkey,
2N/A KMF_OID *signature_oid,
2N/A KMF_DATA *SignedCert)
2N/A{
2N/A KMF_X509_CERTIFICATE *subj_cert = NULL;
2N/A KMF_DATA data_to_sign = {0, NULL};
2N/A KMF_DATA signed_data = {0, NULL};
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_ALGORITHM_INDEX algid;
2N/A int i = 0;
2N/A KMF_ATTRIBUTE attrlist[8];
2N/A
2N/A if (!SignedCert)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A SignedCert->Length = 0;
2N/A SignedCert->Data = NULL;
2N/A
2N/A if (!SubjectCert)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (!SubjectCert->Data || !SubjectCert->Length)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A /*
2N/A * Shortcut - just extract the already encoded TBS cert data from
2N/A * the original data buffer. Since we haven't changed anything,
2N/A * there is no need to re-encode it.
2N/A */
2N/A ret = ExtractX509CertParts((KMF_DATA *)SubjectCert,
2N/A &data_to_sign, NULL);
2N/A if (ret != KMF_OK) {
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* Estimate the signed data length generously */
2N/A signed_data.Length = data_to_sign.Length*2;
2N/A signed_data.Data = calloc(1, signed_data.Length);
2N/A if (!signed_data.Data) {
2N/A ret = KMF_ERR_MEMORY;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /*
2N/A * If we got here OK, decode into a structure and then re-encode
2N/A * the complete certificate.
2N/A */
2N/A ret = DerDecodeSignedCertificate(SubjectCert, &subj_cert);
2N/A if (ret != KMF_OK) {
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* We are re-signing this cert, so clear out old signature data */
2N/A if (!IsEqualOid(&subj_cert->signature.algorithmIdentifier.algorithm,
2N/A signature_oid)) {
2N/A kmf_free_algoid(&subj_cert->signature.algorithmIdentifier);
2N/A ret = set_algoid(&subj_cert->signature.algorithmIdentifier,
2N/A signature_oid);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A ret = set_algoid(&subj_cert->certificate.signature,
2N/A signature_oid);
2N/A if (ret)
2N/A goto cleanup;
2N/A
2N/A /* Free the previous "data to be signed" block */
2N/A kmf_free_data(&data_to_sign);
2N/A
2N/A /*
2N/A * We changed the cert (updated the signature OID), so we
2N/A * need to re-encode it so the correct data gets signed.
2N/A */
2N/A ret = DerEncodeTbsCertificate(&subj_cert->certificate,
2N/A &data_to_sign);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A }
2N/A kmf_set_attr_at_index(attrlist, i, KMF_KEYSTORE_TYPE_ATTR,
2N/A &Signkey->kstype, sizeof (KMF_KEYSTORE_TYPE));
2N/A i++;
2N/A kmf_set_attr_at_index(attrlist, i, KMF_KEY_HANDLE_ATTR,
2N/A Signkey, sizeof (KMF_KEY_HANDLE));
2N/A i++;
2N/A kmf_set_attr_at_index(attrlist, i, KMF_DATA_ATTR,
2N/A &data_to_sign, sizeof (KMF_DATA));
2N/A i++;
2N/A kmf_set_attr_at_index(attrlist, i, KMF_OUT_DATA_ATTR,
2N/A &signed_data, sizeof (KMF_DATA));
2N/A i++;
2N/A kmf_set_attr_at_index(attrlist, i, KMF_OID_ATTR,
2N/A signature_oid, sizeof (KMF_OID));
2N/A i++;
2N/A
2N/A /* Sign the data */
2N/A ret = kmf_sign_data(handle, i, attrlist);
2N/A
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A algid = x509_algoid_to_algid(signature_oid);
2N/A
2N/A if (algid == KMF_ALGID_SHA1WithECDSA ||
2N/A algid == KMF_ALGID_SHA256WithECDSA ||
2N/A algid == KMF_ALGID_SHA384WithECDSA ||
2N/A algid == KMF_ALGID_SHA512WithECDSA) {
2N/A /* ASN.1 encode ECDSA signature */
2N/A KMF_DATA signature;
2N/A
2N/A ret = DerEncodeECDSASignature(&signed_data, &signature);
2N/A kmf_free_data(&signed_data);
2N/A
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A subj_cert->signature.encrypted = signature;
2N/A } else if (algid == KMF_ALGID_SHA1WithDSA ||
2N/A algid == KMF_ALGID_SHA256WithDSA) {
2N/A /*
2N/A * For DSA, kmf_sign_data() returns a 40-byte
2N/A * signature. We must encode the signature correctly.
2N/A */
2N/A KMF_DATA signature;
2N/A
2N/A ret = DerEncodeDSASignature(&signed_data, &signature);
2N/A kmf_free_data(&signed_data);
2N/A
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A subj_cert->signature.encrypted = signature;
2N/A } else {
2N/A ret = copy_data(&subj_cert->signature.encrypted, &signed_data);
2N/A kmf_free_data(&signed_data);
2N/A
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* Now, re-encode the cert with the new signature */
2N/A ret = DerEncodeSignedCertificate(subj_cert, SignedCert);
2N/A
2N/Acleanup:
2N/A /* Cleanup & return */
2N/A if (ret != KMF_OK)
2N/A kmf_free_data(SignedCert);
2N/A
2N/A kmf_free_data(&data_to_sign);
2N/A
2N/A if (subj_cert != NULL) {
2N/A kmf_free_signed_cert(subj_cert);
2N/A free(subj_cert);
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic KMF_RETURN
2N/Averify_cert_with_key(KMF_HANDLE_T handle,
2N/A KMF_DATA *derkey,
2N/A const KMF_DATA *CertToBeVerified)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_X509_CERTIFICATE *signed_cert = NULL;
2N/A KMF_X509_SPKI spki;
2N/A KMF_DATA data_to_verify = {0, NULL};
2N/A KMF_DATA signed_data = {0, NULL};
2N/A KMF_DATA signature = { 0, NULL };
2N/A KMF_ALGORITHM_INDEX algid;
2N/A
2N/A /* check the caller and do other setup for this SPI call */
2N/A if (handle == NULL || CertToBeVerified == NULL ||
2N/A derkey == NULL || derkey->Data == NULL)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A (void) memset(&spki, 0, sizeof (KMF_X509_SPKI));
2N/A
2N/A ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerified,
2N/A &data_to_verify, &signed_data);
2N/A
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A ret = DerDecodeSPKI(derkey, &spki);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A /* Decode the signer cert so we can get the Algorithm data */
2N/A ret = DerDecodeSignedCertificate(CertToBeVerified, &signed_cert);
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A algid = x509_algoid_to_algid(CERT_SIG_OID(signed_cert));
2N/A
2N/A if (algid == KMF_ALGID_NONE)
2N/A return (KMF_ERR_BAD_ALGORITHM);
2N/A
2N/A if (algid == KMF_ALGID_SHA1WithDSA ||
2N/A algid == KMF_ALGID_SHA256WithDSA) {
2N/A ret = DerDecodeDSASignature(&signed_data, &signature);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A } else if (algid == KMF_ALGID_SHA1WithECDSA ||
2N/A algid == KMF_ALGID_SHA256WithECDSA ||
2N/A algid == KMF_ALGID_SHA384WithECDSA ||
2N/A algid == KMF_ALGID_SHA512WithECDSA) {
2N/A ret = DerDecodeECDSASignature(&signed_data, &signature);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A } else {
2N/A signature.Data = signed_data.Data;
2N/A signature.Length = signed_data.Length;
2N/A }
2N/A
2N/A ret = PKCS_VerifyData(handle, algid, &spki,
2N/A &data_to_verify, &signature);
2N/A
2N/Acleanup:
2N/A if (data_to_verify.Data != NULL)
2N/A free(data_to_verify.Data);
2N/A
2N/A if (signed_data.Data != NULL)
2N/A free(signed_data.Data);
2N/A
2N/A if (signed_cert) {
2N/A kmf_free_signed_cert(signed_cert);
2N/A free(signed_cert);
2N/A }
2N/A if (algid == KMF_ALGID_SHA1WithDSA ||
2N/A algid == KMF_ALGID_SHA256WithDSA ||
2N/A algid == KMF_ALGID_SHA1WithECDSA ||
2N/A algid == KMF_ALGID_SHA256WithECDSA ||
2N/A algid == KMF_ALGID_SHA384WithECDSA ||
2N/A algid == KMF_ALGID_SHA512WithECDSA) {
2N/A free(signature.Data);
2N/A }
2N/A
2N/A kmf_free_algoid(&spki.algorithm);
2N/A kmf_free_data(&spki.subjectPublicKey);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Use a signer cert to verify another certificate's signature.
2N/A * This code forces the use of the PKCS11 mechanism for the verify
2N/A * operation for the Cryptographic Framework's FIPS-140 boundary.
2N/A */
2N/Astatic KMF_RETURN
2N/Averify_cert_with_cert(KMF_HANDLE_T handle,
2N/A const KMF_DATA *CertToBeVerifiedData,
2N/A const KMF_DATA *SignerCertData)
2N/A{
2N/A KMF_RETURN ret = KMF_OK;
2N/A KMF_X509_CERTIFICATE *SignerCert = NULL;
2N/A KMF_X509_CERTIFICATE *ToBeVerifiedCert = NULL;
2N/A KMF_DATA data_to_verify = {0, NULL};
2N/A KMF_DATA signed_data = {0, NULL};
2N/A KMF_DATA signature;
2N/A KMF_ALGORITHM_INDEX algid;
2N/A KMF_POLICY_RECORD *policy;
2N/A
2N/A if (handle == NULL ||
2N/A !CertToBeVerifiedData ||
2N/A !CertToBeVerifiedData->Data ||
2N/A !CertToBeVerifiedData->Length)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A if (!SignerCertData ||
2N/A !SignerCertData->Data ||
2N/A !SignerCertData->Length)
2N/A return (KMF_ERR_BAD_PARAMETER);
2N/A
2N/A policy = handle->policy;
2N/A
2N/A /* Make sure the signer has proper key usage bits */
2N/A ret = check_key_usage(handle, SignerCertData, KMF_KU_SIGN_CERT);
2N/A if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
2N/A ret = KMF_OK;
2N/A if (ret != KMF_OK)
2N/A return (ret);
2N/A
2N/A /* Decode the cert into parts for verification */
2N/A ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerifiedData,
2N/A &data_to_verify, &signed_data);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A /* Decode the to-be-verified cert so we know what algorithm to use */
2N/A ret = DerDecodeSignedCertificate(CertToBeVerifiedData,
2N/A &ToBeVerifiedCert);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A algid = x509_algoid_to_algid(CERT_SIG_OID(ToBeVerifiedCert));
2N/A
2N/A if (algid == KMF_ALGID_SHA1WithDSA ||
2N/A algid == KMF_ALGID_SHA256WithDSA) {
2N/A ret = DerDecodeDSASignature(&signed_data, &signature);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A } else if (algid == KMF_ALGID_SHA1WithECDSA ||
2N/A algid == KMF_ALGID_SHA256WithECDSA ||
2N/A algid == KMF_ALGID_SHA384WithECDSA ||
2N/A algid == KMF_ALGID_SHA512WithECDSA) {
2N/A ret = DerDecodeECDSASignature(&signed_data, &signature);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A } else {
2N/A signature.Data = signed_data.Data;
2N/A signature.Length = signed_data.Length;
2N/A }
2N/A
2N/A ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert);
2N/A if (ret != KMF_OK)
2N/A goto cleanup;
2N/A
2N/A /*
2N/A * Force use of PKCS11 API for kcfd/libelfsign. This is
2N/A * required for the Cryptographic Framework's FIPS-140 boundary.
2N/A */
2N/A ret = PKCS_VerifyData(handle, algid,
2N/A &SignerCert->certificate.subjectPublicKeyInfo,
2N/A &data_to_verify, &signature);
2N/A
2N/Acleanup:
2N/A kmf_free_data(&data_to_verify);
2N/A kmf_free_data(&signed_data);
2N/A
2N/A if (SignerCert) {
2N/A kmf_free_signed_cert(SignerCert);
2N/A free(SignerCert);
2N/A }
2N/A
2N/A if (ToBeVerifiedCert) {
2N/A kmf_free_signed_cert(ToBeVerifiedCert);
2N/A free(ToBeVerifiedCert);
2N/A }
2N/A
2N/A if (algid == KMF_ALGID_SHA1WithDSA ||
2N/A algid == KMF_ALGID_SHA256WithDSA ||
2N/A algid == KMF_ALGID_SHA1WithECDSA ||
2N/A algid == KMF_ALGID_SHA256WithECDSA ||
2N/A algid == KMF_ALGID_SHA384WithECDSA ||
2N/A algid == KMF_ALGID_SHA512WithECDSA) {
2N/A free(signature.Data);
2N/A }
2N/A
2N/A return (ret);
2N/A}