#include <stdio.h>
#include <link.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <ber_der.h>
#include <kmfapiP.h>
#include <pem_encode.h>
#include <libgen.h>
#include <cryptoutil.h>
#define CERTFILE_TEMPNAME "/tmp/user.certXXXXXX"
#define CRLFILE_TEMPNAME "/tmp/crlXXXXXX"
#define X509_FORMAT_VERSION 2
static KMF_RETURN
sign_cert(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *,
KMF_OID *, KMF_DATA *);
static KMF_RETURN
verify_cert_with_key(KMF_HANDLE_T, KMF_DATA *, const KMF_DATA *);
static KMF_RETURN
verify_cert_with_cert(KMF_HANDLE_T, const KMF_DATA *, const KMF_DATA *);
static KMF_RETURN
get_keyalg_from_cert(KMF_DATA *cert, KMF_KEY_ALG *keyalg)
{
KMF_RETURN rv;
KMF_X509_CERTIFICATE *SignerCert = NULL;
KMF_ALGORITHM_INDEX AlgorithmId;
rv = DerDecodeSignedCertificate(cert, &SignerCert);
if (rv != KMF_OK)
return (rv);
AlgorithmId = x509_algoid_to_algid(
&SignerCert->signature.algorithmIdentifier.algorithm);
switch (AlgorithmId) {
case KMF_ALGID_MD5WithRSA:
case KMF_ALGID_SHA1WithRSA:
case KMF_ALGID_SHA256WithRSA:
case KMF_ALGID_SHA384WithRSA:
case KMF_ALGID_SHA512WithRSA:
*keyalg = KMF_RSA;
break;
case KMF_ALGID_SHA1WithDSA:
case KMF_ALGID_SHA256WithDSA:
*keyalg = KMF_DSA;
break;
case KMF_ALGID_SHA1WithECDSA:
case KMF_ALGID_SHA256WithECDSA:
case KMF_ALGID_SHA384WithECDSA:
case KMF_ALGID_SHA512WithECDSA:
case KMF_ALGID_ECDSA:
*keyalg = KMF_ECDSA;
break;
default:
rv = KMF_ERR_BAD_ALGORITHM;
}
kmf_free_signed_cert(SignerCert);
free(SignerCert);
return (rv);
}
KMF_RETURN
kmf_find_prikey_by_cert(KMF_HANDLE_T handle, int numattr,
KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret = KMF_OK;
KMF_KEYSTORE_TYPE kstype;
KMF_KEY_ALG keyalg;
KMF_KEY_HANDLE *key = NULL;
KMF_DATA *cert = NULL;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
{KMF_KEY_HANDLE_ATTR, TRUE, sizeof (KMF_KEY_HANDLE),
sizeof (KMF_KEY_HANDLE)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
if (cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
ret = get_keyalg_from_cert(cert, &keyalg);
if (ret != KMF_OK)
return (ret);
key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
if (key == NULL)
return (KMF_ERR_BAD_PARAMETER);
key->keyalg = keyalg;
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, NULL);
if (ret != KMF_OK)
return (ret);
plugin = FindPlugin(handle, kstype);
if (plugin == NULL || plugin->funclist->FindPrikeyByCert == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
return (plugin->funclist->FindPrikeyByCert(handle, numattr, attrlist));
}
KMF_RETURN
check_key_usage(void *handle,
const KMF_DATA *cert,
const KMF_KU_PURPOSE purpose)
{
KMF_X509EXT_BASICCONSTRAINTS constraint;
KMF_BOOL critical = B_FALSE;
KMF_X509EXT_KEY_USAGE keyusage;
KMF_RETURN ret = KMF_OK;
if (handle == NULL || cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
(void) memset(&constraint, 0, sizeof (KMF_X509EXT_BASICCONSTRAINTS));
(void) memset(&keyusage, 0, sizeof (KMF_X509EXT_KEY_USAGE));
ret = kmf_get_cert_ku(cert, &keyusage);
if (ret != KMF_OK)
return (ret);
switch (purpose) {
case KMF_KU_SIGN_CERT:
if (keyusage.KeyUsageBits & KMF_keyCertSign) {
ret = kmf_get_cert_basic_constraint(cert,
&critical, &constraint);
if (ret != KMF_OK)
return (ret);
if ((!critical) || (!constraint.cA))
return (KMF_ERR_KEYUSAGE);
} else {
return (KMF_ERR_KEYUSAGE);
}
break;
case KMF_KU_SIGN_DATA:
if (!(keyusage.KeyUsageBits & KMF_digitalSignature))
return (KMF_ERR_KEYUSAGE);
break;
case KMF_KU_ENCRYPT_DATA:
if (!(keyusage.KeyUsageBits & KMF_dataEncipherment))
return (KMF_ERR_KEYUSAGE);
break;
default:
return (KMF_ERR_BAD_PARAMETER);
}
return (KMF_OK);
}
KMF_RETURN
kmf_find_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret = KMF_OK;
KMF_KEYSTORE_TYPE kstype;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_COUNT_ATTR, FALSE, sizeof (uint32_t), sizeof (uint32_t)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, NULL);
if (ret != KMF_OK)
return (ret);
plugin = FindPlugin(handle, kstype);
if (plugin == NULL || plugin->funclist->FindCert == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
return (plugin->funclist->FindCert(handle, numattr, attrlist));
}
#define NODATA(d) (d.Data == NULL || d.Length == 0)
KMF_RETURN
kmf_encode_cert_record(KMF_X509_CERTIFICATE *CertData, KMF_DATA *encodedCert)
{
KMF_RETURN ret;
KMF_X509_TBS_CERT *tbs_cert;
if (CertData == NULL || encodedCert == NULL)
return (KMF_ERR_BAD_PARAMETER);
tbs_cert = &(CertData->certificate);
if (NODATA(tbs_cert->version) ||
NODATA(tbs_cert->signature.algorithm) ||
NODATA(tbs_cert->subjectPublicKeyInfo.subjectPublicKey) ||
tbs_cert->serialNumber.val == NULL ||
tbs_cert->serialNumber.len == 0 ||
tbs_cert->subject.numberOfRDNs == 0 ||
tbs_cert->issuer.numberOfRDNs == 0) {
return (KMF_ERR_INCOMPLETE_TBS_CERT);
}
encodedCert->Length = 0;
encodedCert->Data = NULL;
ret = DerEncodeSignedCertificate(CertData, encodedCert);
return (ret);
}
static KMF_RETURN
setup_findprikey_attrlist(KMF_ATTRIBUTE *src_attrlist, int src_num,
KMF_ATTRIBUTE **new_attrlist, int *new_num, KMF_KEY_HANDLE *key,
KMF_DATA *cert)
{
KMF_ATTRIBUTE *attrlist = NULL;
int cur_num = src_num;
int index;
int i;
if (src_attrlist == NULL || new_num == NULL || key == NULL ||
cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
attrlist = (KMF_ATTRIBUTE *) malloc(
(src_num + 2) * sizeof (KMF_ATTRIBUTE));
if (attrlist == NULL)
return (KMF_ERR_MEMORY);
for (i = 0; i < src_num; i++) {
attrlist[i].type = src_attrlist[i].type;
attrlist[i].pValue = src_attrlist[i].pValue;
attrlist[i].valueLen = src_attrlist[i].valueLen;
}
index = kmf_find_attr(KMF_KEY_HANDLE_ATTR, attrlist, cur_num);
if (index == -1) {
kmf_set_attr_at_index(attrlist, cur_num,
KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE));
cur_num++;
} else {
kmf_set_attr_at_index(attrlist, index,
KMF_KEY_HANDLE_ATTR, key, sizeof (KMF_KEY_HANDLE));
}
index = kmf_find_attr(KMF_CERT_DATA_ATTR, attrlist, cur_num);
if (index == -1) {
kmf_set_attr_at_index(attrlist, cur_num,
KMF_CERT_DATA_ATTR, cert, sizeof (KMF_DATA));
cur_num++;
} else {
kmf_set_attr_at_index(attrlist, index,
KMF_CERT_DATA_ATTR, cert, sizeof (KMF_DATA));
}
*new_attrlist = attrlist;
*new_num = cur_num;
return (KMF_OK);
}
static KMF_OID *
get_default_signoid(KMF_KEY_HANDLE *key)
{
KMF_OID *oid;
switch (key->keyalg) {
case KMF_RSA:
oid = (KMF_OID *)&KMFOID_SHA256WithRSA;
break;
case KMF_DSA:
if (key->kstype == KMF_KEYSTORE_NSS)
oid = (KMF_OID *)&KMFOID_X9CM_DSAWithSHA1;
else
oid = (KMF_OID *)&KMFOID_SHA256WithDSA;
break;
case KMF_ECDSA:
oid = (KMF_OID *)&KMFOID_SHA256WithECDSA;
break;
default:
oid = NULL;
break;
}
return (oid);
}
static KMF_RETURN
check_for_basic_constraint(KMF_DATA *cert)
{
KMF_RETURN rv = KMF_OK;
KMF_X509EXT_KEY_USAGE keyUsage;
KMF_X509_CERTIFICATE *x509cert = NULL;
rv = kmf_get_cert_ku((const KMF_DATA *)cert, &keyUsage);
if (rv == KMF_OK) {
KMF_X509EXT_BASICCONSTRAINTS basicConstraint;
KMF_BOOL critical;
if (keyUsage.KeyUsageBits & KMF_keyCertSign)
rv = kmf_get_cert_basic_constraint(
(const KMF_DATA *)cert,
&critical, &basicConstraint);
if (rv != KMF_ERR_EXTENSION_NOT_FOUND)
return (rv);
basicConstraint.cA = TRUE;
basicConstraint.pathLenConstraintPresent = FALSE;
rv = DerDecodeSignedCertificate(cert, &x509cert);
if (rv != KMF_OK)
return (rv);
rv = kmf_set_cert_basic_constraint(x509cert,
TRUE, &basicConstraint);
if (rv != KMF_OK) {
kmf_free_signed_cert(x509cert);
free(x509cert);
return (rv);
}
kmf_free_data(cert);
rv = kmf_encode_cert_record(x509cert, cert);
kmf_free_signed_cert(x509cert);
free(x509cert);
}
if (rv == KMF_ERR_EXTENSION_NOT_FOUND)
rv = KMF_OK;
return (rv);
}
KMF_RETURN
kmf_sign_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret;
int new_numattr = numattr + 1;
KMF_ATTRIBUTE *new_attrlist = NULL;
KMF_DATA *signer_cert = NULL;
KMF_DATA *tbs_cert = NULL;
KMF_DATA *signed_cert = NULL;
KMF_DATA unsignedCert = { 0, NULL };
KMF_KEY_HANDLE sign_key, *sign_key_ptr;
int freethekey = 0;
KMF_POLICY_RECORD *policy;
KMF_OID *oid = NULL;
KMF_X509_CERTIFICATE *x509cert;
KMF_X509_TBS_CERT *decodedTbsCert = NULL;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
signer_cert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
numattr);
sign_key_ptr = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist,
numattr);
if (signer_cert == NULL && sign_key_ptr == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (signer_cert != NULL && sign_key_ptr != NULL)
return (KMF_ERR_BAD_PARAMETER);
oid = kmf_get_attr_ptr(KMF_OID_ATTR, attrlist, numattr);
if (oid == NULL) {
KMF_ALGORITHM_INDEX AlgId;
ret = kmf_get_attr(KMF_ALGORITHM_INDEX_ATTR, attrlist, numattr,
&AlgId, NULL);
if (ret == KMF_OK)
oid = x509_algid_to_algoid(AlgId);
}
if (signer_cert != NULL) {
policy = handle->policy;
ret = check_key_usage(handle, signer_cert, KMF_KU_SIGN_CERT);
if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
ret = KMF_OK;
if (ret != KMF_OK)
return (ret);
ret = setup_findprikey_attrlist(attrlist, numattr,
&new_attrlist, &new_numattr, &sign_key, signer_cert);
if (ret != KMF_OK)
goto out;
ret = kmf_find_prikey_by_cert(handle, new_numattr,
new_attrlist);
if (ret != KMF_OK) {
goto out;
}
sign_key_ptr = &sign_key;
freethekey = 1;
}
tbs_cert = kmf_get_attr_ptr(KMF_TBS_CERT_DATA_ATTR, attrlist,
numattr);
if (tbs_cert == NULL) {
x509cert = kmf_get_attr_ptr(KMF_X509_CERTIFICATE_ATTR, attrlist,
numattr);
if (x509cert == NULL) {
ret = KMF_ERR_BAD_PARAMETER;
goto out;
}
ret = kmf_encode_cert_record(x509cert, &unsignedCert);
if (ret != KMF_OK)
goto out;
tbs_cert = &unsignedCert;
}
ret = check_for_basic_constraint(tbs_cert);
if (ret)
goto out;
if (oid == NULL) {
oid = get_default_signoid(sign_key_ptr);
}
signed_cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
numattr);
if (signed_cert == NULL) {
ret = KMF_ERR_BAD_PARAMETER;
goto out;
}
ret = sign_cert(handle, tbs_cert, sign_key_ptr, oid, signed_cert);
out:
if (new_attrlist)
(void) free(new_attrlist);
if (freethekey)
kmf_free_kmf_key(handle, &sign_key);
kmf_free_data(&unsignedCert);
if (decodedTbsCert != NULL) {
kmf_free_tbs_cert(decodedTbsCert);
free(decodedTbsCert);
}
return (ret);
}
KMF_RETURN
kmf_sign_data(KMF_HANDLE_T handle, int numattr,
KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret = KMF_OK;
KMF_ATTRIBUTE *new_attrlist = NULL;
int new_numattr = numattr;
KMF_DATA *signer_cert = NULL;
KMF_DATA *tbs_data = NULL;
KMF_DATA *output = NULL;
KMF_KEY_HANDLE sign_key, *sign_key_ptr;
KMF_ALGORITHM_INDEX AlgId = KMF_ALGID_NONE;
KMF_DATA signature = { 0, NULL };
KMF_OID *oid;
KMF_POLICY_RECORD *policy;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
{KMF_OUT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
signer_cert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
numattr);
sign_key_ptr = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist,
numattr);
if (signer_cert == NULL && sign_key_ptr == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (signer_cert != NULL) {
ret = check_key_usage(handle, signer_cert, KMF_KU_SIGN_DATA);
policy = handle->policy;
if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
ret = KMF_OK;
if (ret != KMF_OK)
return (ret);
ret = setup_findprikey_attrlist(attrlist, numattr,
&new_attrlist, &new_numattr, &sign_key, signer_cert);
if (ret != KMF_OK) {
goto cleanup;
}
ret = kmf_find_prikey_by_cert(handle, new_numattr,
new_attrlist);
if (ret != KMF_OK) {
goto cleanup;
}
sign_key_ptr = &sign_key;
}
tbs_data = kmf_get_attr_ptr(KMF_DATA_ATTR, attrlist, numattr);
if (tbs_data == NULL) {
ret = KMF_ERR_BAD_PARAMETER;
goto cleanup;
}
output = kmf_get_attr_ptr(KMF_OUT_DATA_ATTR, attrlist, numattr);
if (output == NULL) {
ret = KMF_ERR_BAD_PARAMETER;
goto cleanup;
}
oid = kmf_get_attr_ptr(KMF_OID_ATTR, attrlist, numattr);
if (oid == NULL) {
ret = kmf_get_attr(KMF_ALGORITHM_INDEX_ATTR, attrlist,
numattr, &AlgId, NULL);
if (ret != KMF_OK)
oid = get_default_signoid(sign_key_ptr);
else
oid = x509_algid_to_algoid(AlgId);
}
if (sign_key_ptr->keyp == NULL) {
ret = KMF_ERR_BAD_PARAMETER;
goto cleanup;
}
plugin = FindPlugin(handle, sign_key_ptr->kstype);
if (plugin == NULL || plugin->funclist->SignData == NULL) {
ret = KMF_ERR_PLUGIN_NOTFOUND;
goto cleanup;
}
ret = plugin->funclist->SignData(handle, sign_key_ptr, oid, tbs_data,
output);
if (ret != KMF_OK)
goto cleanup;
if (plugin->type == KMF_KEYSTORE_NSS &&
(IsEqualOid(oid, (KMF_OID *)&KMFOID_X9CM_DSAWithSHA1) ||
IsEqualOid(oid, (KMF_OID *)&KMFOID_SHA256WithDSA))) {
ret = DerDecodeDSASignature(output, &signature);
if (ret != KMF_OK)
goto cleanup;
output->Length = signature.Length;
(void) memcpy(output->Data, signature.Data, signature.Length);
}
cleanup:
if (new_attrlist != NULL)
free(new_attrlist);
if (signature.Data)
free(signature.Data);
if (signer_cert != NULL && sign_key_ptr != NULL)
kmf_free_kmf_key(handle, sign_key_ptr);
return (ret);
}
KMF_RETURN
kmf_verify_data(KMF_HANDLE_T handle,
int num_args,
KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret = KMF_OK;
KMF_PLUGIN *plugin;
KMF_KEYSTORE_TYPE kstype;
uint32_t len;
KMF_DATA derkey = { 0, NULL };
KMF_KEY_HANDLE *KMFKey;
KMF_ALGORITHM_INDEX sigAlg = KMF_ALGID_NONE;
KMF_DATA *indata;
KMF_DATA *insig;
KMF_DATA *signer_cert;
KMF_X509_SPKI spki;
KMF_POLICY_RECORD *policy;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_DATA_ATTR, FALSE, sizeof (KMF_DATA),
sizeof (KMF_DATA)},
{KMF_IN_SIGN_ATTR, FALSE, sizeof (KMF_DATA),
sizeof (KMF_DATA)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, num_args, attrlist);
if (ret != KMF_OK)
return (ret);
len = sizeof (kstype);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, num_args,
&kstype, &len);
if (ret != KMF_OK)
return (ret);
KMFKey = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, num_args);
signer_cert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
num_args);
if (KMFKey == NULL && signer_cert == NULL) {
return (KMF_ERR_BAD_PARAMETER);
}
len = sizeof (sigAlg);
ret = kmf_get_attr(KMF_ALGORITHM_INDEX_ATTR, attrlist, num_args,
&sigAlg, &len);
if (ret != KMF_OK && signer_cert == NULL)
return (ret);
indata = kmf_get_attr_ptr(KMF_DATA_ATTR, attrlist, num_args);
if (indata == NULL)
return (KMF_ERR_BAD_PARAMETER);
insig = kmf_get_attr_ptr(KMF_IN_SIGN_ATTR, attrlist, num_args);
if (insig == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (signer_cert != NULL) {
KMF_X509_CERTIFICATE *SignerCert = NULL;
policy = handle->policy;
ret = check_key_usage(handle, signer_cert, KMF_KU_SIGN_DATA);
if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
ret = KMF_OK;
if (ret != KMF_OK)
return (ret);
ret = DerDecodeSignedCertificate(signer_cert, &SignerCert);
if (ret != KMF_OK)
return (ret);
if (sigAlg == KMF_ALGID_NONE)
sigAlg = x509_algoid_to_algid(CERT_ALG_OID(SignerCert));
if (sigAlg == KMF_ALGID_NONE) {
kmf_free_signed_cert(SignerCert);
free(SignerCert);
return (KMF_ERR_BAD_ALGORITHM);
}
ret = PKCS_VerifyData(handle, sigAlg,
&SignerCert->certificate.subjectPublicKeyInfo,
indata, insig);
kmf_free_signed_cert(SignerCert);
free(SignerCert);
} else {
plugin = FindPlugin(handle, kstype);
if (plugin != NULL &&
plugin->funclist->EncodePubkeyData != NULL) {
ret = plugin->funclist->EncodePubkeyData(handle,
KMFKey, &derkey);
} else {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
ret = DerDecodeSPKI(&derkey, &spki);
if (ret == KMF_OK)
ret = PKCS_VerifyData(handle, sigAlg, &spki,
indata, insig);
if (derkey.Data != NULL)
free(derkey.Data);
kmf_free_algoid(&spki.algorithm);
kmf_free_data(&spki.subjectPublicKey);
}
return (ret);
}
KMF_RETURN
kmf_verify_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret;
KMF_DATA derkey = { 0, NULL };
KMF_PLUGIN *plugin;
KMF_KEY_HANDLE *KMFKey;
KMF_DATA *CertToBeVerified;
KMF_DATA *SignerCert;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
CLEAR_ERROR(handle, ret);
if (ret != KMF_OK)
return (ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
KMFKey = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
SignerCert = kmf_get_attr_ptr(KMF_SIGNER_CERT_DATA_ATTR, attrlist,
numattr);
if (KMFKey == NULL && SignerCert == NULL)
return (KMF_ERR_BAD_PARAMETER);
CertToBeVerified = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
numattr);
if (CertToBeVerified == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (SignerCert != NULL) {
ret = verify_cert_with_cert(handle, CertToBeVerified,
SignerCert);
} else {
plugin = FindPlugin(handle, KMFKey->kstype);
if (plugin != NULL && plugin->funclist->EncodePubkeyData !=
NULL) {
ret = plugin->funclist->EncodePubkeyData(handle,
KMFKey, &derkey);
} else {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
if (ret == KMF_OK && derkey.Length > 0) {
ret = verify_cert_with_key(handle, &derkey,
CertToBeVerified);
if (derkey.Data != NULL)
free(derkey.Data);
}
}
return (ret);
}
KMF_RETURN
kmf_encrypt(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret;
KMF_X509_CERTIFICATE *x509cert = NULL;
KMF_X509_SPKI *pubkey;
KMF_OID *alg;
KMF_ALGORITHM_INDEX algid;
KMF_DATA *cert;
KMF_DATA *plaintext;
KMF_DATA *ciphertext;
KMF_POLICY_RECORD *policy;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
sizeof (KMF_DATA)},
{KMF_PLAINTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
sizeof (KMF_DATA)},
{KMF_CIPHERTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
sizeof (KMF_DATA)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
CLEAR_ERROR(handle, ret);
if (ret != KMF_OK)
return (ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
numattr);
plaintext = kmf_get_attr_ptr(KMF_PLAINTEXT_DATA_ATTR, attrlist,
numattr);
ciphertext = kmf_get_attr_ptr(KMF_CIPHERTEXT_DATA_ATTR, attrlist,
numattr);
if (cert == NULL || plaintext == NULL || ciphertext == NULL)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA);
if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
ret = KMF_OK;
if (ret != KMF_OK)
return (ret);
if ((ret = DerDecodeSignedCertificate(cert, &x509cert)) != KMF_OK)
return (ret);
pubkey = &x509cert->certificate.subjectPublicKeyInfo;
alg = &pubkey->algorithm.algorithm;
algid = x509_algoid_to_algid(alg);
if (algid == KMF_ALGID_DSA ||
algid == KMF_ALGID_SHA1WithDSA ||
algid == KMF_ALGID_SHA256WithDSA ||
algid == KMF_ALGID_SHA1WithECDSA ||
algid == KMF_ALGID_SHA256WithECDSA ||
algid == KMF_ALGID_SHA384WithECDSA ||
algid == KMF_ALGID_SHA512WithECDSA ||
algid == KMF_ALGID_NONE) {
kmf_free_signed_cert(x509cert);
free(x509cert);
return (KMF_ERR_BAD_ALGORITHM);
}
ret = PKCS_EncryptData(handle, algid, pubkey, plaintext, ciphertext);
kmf_free_signed_cert(x509cert);
free(x509cert);
return (ret);
}
KMF_RETURN
kmf_decrypt(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret;
KMF_X509_CERTIFICATE *x509cert = NULL;
KMF_X509_SPKI *spki_ptr;
KMF_PLUGIN *plugin;
KMF_ALGORITHM_INDEX AlgorithmId;
KMF_ATTRIBUTE *new_attrlist = NULL;
int new_numattr;
KMF_DATA *cert = NULL;
KMF_DATA *ciphertext = NULL;
KMF_DATA *plaintext = NULL;
KMF_KEY_HANDLE prikey;
KMF_POLICY_RECORD *policy;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
{KMF_PLAINTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
sizeof (KMF_DATA)},
{KMF_CIPHERTEXT_DATA_ATTR, FALSE, sizeof (KMF_DATA),
sizeof (KMF_DATA)},
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist,
numattr);
if (cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
ret = check_key_usage(handle, cert, KMF_KU_ENCRYPT_DATA);
if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
ret = KMF_OK;
if (ret != KMF_OK)
return (ret);
ciphertext = kmf_get_attr_ptr(KMF_CIPHERTEXT_DATA_ATTR, attrlist,
numattr);
if (ciphertext == NULL)
return (KMF_ERR_BAD_PARAMETER);
plaintext = kmf_get_attr_ptr(KMF_PLAINTEXT_DATA_ATTR, attrlist,
numattr);
if (plaintext == NULL)
return (KMF_ERR_BAD_PARAMETER);
ret = setup_findprikey_attrlist(attrlist, numattr, &new_attrlist,
&new_numattr, &prikey, cert);
if (ret != KMF_OK)
goto cleanup;
ret = kmf_find_prikey_by_cert(handle, new_numattr, new_attrlist);
if (ret != KMF_OK)
goto cleanup;
ret = DerDecodeSignedCertificate(cert, &x509cert);
if (ret != KMF_OK)
goto cleanup;
spki_ptr = &x509cert->certificate.subjectPublicKeyInfo;
AlgorithmId = x509_algoid_to_algid((KMF_OID *)
&spki_ptr->algorithm.algorithm);
if (AlgorithmId == KMF_ALGID_DSA ||
AlgorithmId == KMF_ALGID_ECDSA) {
ret = KMF_ERR_BAD_ALGORITHM;
goto cleanup;
}
plugin = FindPlugin(handle, prikey.kstype);
if (plugin != NULL && plugin->funclist->DecryptData != NULL) {
ret = plugin->funclist->DecryptData(handle,
&prikey, &spki_ptr->algorithm.algorithm,
ciphertext, plaintext);
} else {
ret = KMF_ERR_PLUGIN_NOTFOUND;
}
cleanup:
if (new_attrlist != NULL)
free(new_attrlist);
kmf_free_kmf_key(handle, &prikey);
kmf_free_signed_cert(x509cert);
free(x509cert);
return (ret);
}
KMF_RETURN
kmf_store_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret = KMF_OK;
KMF_KEYSTORE_TYPE kstype;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, NULL);
if (ret != KMF_OK)
return (ret);
plugin = FindPlugin(handle, kstype);
if (plugin == NULL || plugin->funclist->StoreCert == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
return (plugin->funclist->StoreCert(handle, numattr, attrlist));
}
KMF_RETURN
kmf_import_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret = KMF_OK;
KMF_KEYSTORE_TYPE kstype;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_CERT_FILENAME_ATTR, TRUE, 1, 0},
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs, 0, NULL,
numattr, attrlist);
if (ret != KMF_OK)
return (ret);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, NULL);
if (ret != KMF_OK)
return (ret);
plugin = FindPlugin(handle, kstype);
if (plugin == NULL || plugin->funclist->ImportCert == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
return (plugin->funclist->ImportCert(handle, numattr, attrlist));
}
KMF_RETURN
kmf_delete_cert_from_keystore(KMF_HANDLE_T handle, int numattr,
KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret = KMF_OK;
KMF_KEYSTORE_TYPE kstype;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, NULL);
if (ret != KMF_OK)
return (ret);
plugin = FindPlugin(handle, kstype);
if (plugin == NULL || plugin->funclist->DeleteCert == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
return (plugin->funclist->DeleteCert(handle, numattr, attrlist));
}
static KMF_RETURN
cert_get_crl(KMF_HANDLE_T handle, const KMF_DATA *cert, char *proxy,
char *filename, char **retn_uri, KMF_ENCODE_FORMAT *format)
{
KMF_RETURN ret = KMF_OK;
KMF_X509EXT_CRLDISTPOINTS crl_dps;
boolean_t done = B_FALSE;
char uri[1024];
char *proxyname = NULL;
char *proxy_port_s = NULL;
int proxy_port = 0;
int i, j;
char *path = NULL;
if (handle == NULL || cert == NULL || filename == NULL ||
retn_uri == NULL || format == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (proxy != NULL) {
proxyname = strtok(proxy, ":");
proxy_port_s = strtok(NULL, "\0");
if (proxy_port_s != NULL) {
proxy_port = strtol(proxy_port_s, NULL, 0);
} else {
proxy_port = 8080;
}
}
ret = kmf_get_cert_crl_dist_pts((const KMF_DATA *)cert,
&crl_dps);
if (ret != KMF_OK)
goto out;
for (i = 0; i < crl_dps.number; i++) {
KMF_CRL_DIST_POINT *dp = &(crl_dps.dplist[i]);
KMF_GENERALNAMES *fullname = &(dp->name.full_name);
KMF_DATA *data;
if (done)
break;
for (j = 0; j < fullname->number; j++) {
data = &(fullname->namelist[j].name);
(void) memcpy(uri, data->Data, data->Length);
uri[data->Length] = '\0';
ret = kmf_download_crl(handle, uri, proxyname,
proxy_port, 30, filename, format);
if (ret == KMF_OK) {
done = B_TRUE;
path = malloc(data->Length + 1);
if (path == NULL) {
ret = KMF_ERR_MEMORY;
goto out;
}
(void) strncpy(path, uri, data->Length);
*retn_uri = path;
break;
}
}
}
out:
kmf_free_crl_dist_pts(&crl_dps);
return (ret);
}
static KMF_RETURN
check_crl_validity(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE kstype,
char *crlfilename, KMF_DATA *issuer_cert)
{
KMF_RETURN ret = KMF_OK;
KMF_POLICY_RECORD *policy;
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
if (kstype == KMF_KEYSTORE_NSS)
return (KMF_OK);
if (!policy->validation_info.crl_info.ignore_crl_sign) {
ret = kmf_verify_crl_file(handle, crlfilename,
issuer_cert);
if (ret != KMF_OK)
return (ret);
}
if (!policy->validation_info.crl_info.ignore_crl_date) {
ret = kmf_check_crl_date(handle, crlfilename);
if (ret != KMF_OK)
return (ret);
}
return (ret);
}
static KMF_RETURN
cert_crl_check(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
KMF_DATA *user_cert, KMF_DATA *issuer_cert)
{
KMF_POLICY_RECORD *policy;
KMF_RETURN ret = KMF_OK;
KMF_ATTRIBUTE attrlist[16];
int numattr = 0;
int fd;
boolean_t crlchk;
char user_certfile[MAXPATHLEN];
char crlfile_tmp[MAXPATHLEN];
char *basefilename = NULL;
char *dir = NULL;
char *crlfilename = NULL;
char *proxy = NULL;
char *uri = NULL;
KMF_ENCODE_FORMAT format;
if (handle == NULL || kstype == NULL || user_cert == NULL ||
issuer_cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (!is_valid_keystore_type(*kstype))
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
basefilename = policy->validation_info.crl_info.basefilename;
dir = policy->validation_info.crl_info.directory;
if (policy->validation_info.crl_info.get_crl_uri) {
if (basefilename == NULL)
basefilename = basename(uri);
crlfilename = get_fullpath(dir == NULL ? "./" : dir,
basefilename);
if (crlfilename == NULL) {
ret = KMF_ERR_BAD_CRLFILE;
goto cleanup;
}
if ((fd = open(crlfilename, O_RDONLY)) != -1) {
(void) close(fd);
if ((ret = check_crl_validity(handle, *kstype,
crlfilename, issuer_cert)) == KMF_OK) {
goto checkcrl;
}
}
(void) strlcpy(crlfile_tmp, CRLFILE_TEMPNAME,
sizeof (crlfile_tmp));
if (mkstemp(crlfile_tmp) == -1) {
ret = KMF_ERR_INTERNAL;
goto cleanup;
}
proxy = policy->validation_info.crl_info.proxy;
ret = cert_get_crl(handle, user_cert, proxy, crlfile_tmp,
&uri, &format);
if (ret != KMF_OK) {
(void) unlink(crlfile_tmp);
goto cleanup;
}
if ((ret = check_crl_validity(handle, *kstype, crlfile_tmp,
issuer_cert)) != KMF_OK)
return (ret);
if (*kstype == KMF_KEYSTORE_NSS) {
numattr = 0;
kmf_set_attr_at_index(attrlist, numattr,
KMF_KEYSTORE_TYPE_ATTR, kstype, sizeof (kstype));
numattr++;
kmf_set_attr_at_index(attrlist, numattr,
KMF_CRL_FILENAME_ATTR, crlfile_tmp,
strlen(crlfile_tmp));
numattr++;
crlchk = B_FALSE;
kmf_set_attr_at_index(attrlist, numattr,
KMF_CRL_CHECK_ATTR, &crlchk, sizeof (boolean_t));
numattr++;
ret = kmf_import_crl(handle, numattr, attrlist);
(void) unlink(crlfile_tmp);
if (ret != KMF_OK)
goto cleanup;
} else {
if (rename(crlfile_tmp, crlfilename) == -1) {
(void) unlink(crlfile_tmp);
ret = KMF_ERR_WRITE_FILE;
goto cleanup;
}
}
} else {
if (*kstype != KMF_KEYSTORE_NSS) {
if (basefilename == NULL) {
ret = KMF_ERR_BAD_PARAMETER;
goto cleanup;
}
crlfilename = get_fullpath(dir == NULL ? "./" : dir,
basefilename);
if (crlfilename == NULL) {
ret = KMF_ERR_BAD_CRLFILE;
goto cleanup;
}
if ((ret = check_crl_validity(handle, *kstype,
crlfilename, issuer_cert)) != KMF_OK)
return (ret);
}
}
checkcrl:
numattr = 0;
kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
kstype, sizeof (kstype));
numattr++;
switch (*kstype) {
case KMF_KEYSTORE_NSS:
kmf_set_attr_at_index(attrlist, numattr,
KMF_CERT_DATA_ATTR, user_cert, sizeof (KMF_DATA));
numattr++;
break;
case KMF_KEYSTORE_PK11TOKEN:
case KMF_KEYSTORE_OPENSSL:
(void) strlcpy(user_certfile, CERTFILE_TEMPNAME,
sizeof (user_certfile));
if (mkstemp(user_certfile) == -1) {
ret = KMF_ERR_INTERNAL;
goto cleanup;
}
ret = kmf_create_cert_file(user_cert, KMF_FORMAT_ASN1,
user_certfile);
if (ret != KMF_OK) {
goto cleanup;
}
kmf_set_attr_at_index(attrlist, numattr,
KMF_CERT_FILENAME_ATTR,
user_certfile, strlen(user_certfile));
numattr++;
kmf_set_attr_at_index(attrlist, numattr,
KMF_CRL_FILENAME_ATTR,
crlfilename, strlen(crlfilename));
numattr++;
break;
default:
ret = KMF_ERR_PLUGIN_NOTFOUND;
goto cleanup;
}
ret = kmf_find_cert_in_crl(handle, numattr, attrlist);
if (ret == KMF_ERR_NOT_REVOKED) {
ret = KMF_OK;
}
cleanup:
(void) unlink(user_certfile);
if (crlfilename != NULL)
free(crlfilename);
if (uri != NULL)
free(uri);
return (ret);
}
static KMF_RETURN
cert_ocsp_check(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
KMF_DATA *user_cert, KMF_DATA *issuer_cert, KMF_DATA *response,
char *slotlabel, char *dirpath)
{
KMF_RETURN ret = KMF_OK;
KMF_POLICY_RECORD *policy;
KMF_DATA *new_response = NULL;
boolean_t ignore_response_sign = B_FALSE;
uint32_t ltime = 0;
KMF_DATA *signer_cert = NULL;
KMF_BIGINT sernum = { NULL, 0 };
int response_status;
int reason;
int cert_status;
KMF_ATTRIBUTE attrlist[32];
int numattr;
if (handle == NULL || kstype == NULL || user_cert == NULL ||
issuer_cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
if (policy->VAL_OCSP_BASIC.response_lifetime != NULL &&
(str2lifetime(policy->VAL_OCSP_BASIC.response_lifetime, <ime)
< 0))
return (KMF_ERR_OCSP_RESPONSE_LIFETIME);
ignore_response_sign = policy->VAL_OCSP_BASIC.ignore_response_sign;
if (ignore_response_sign == B_FALSE &&
policy->VAL_OCSP.has_resp_cert == B_TRUE) {
char *signer_name;
KMF_X509_DER_CERT signer_retrcert;
uchar_t *bytes = NULL;
size_t bytelen;
uint32_t num = 0;
KMF_ATTRIBUTE fc_attrlist[16];
int fc_numattr = 0;
char *dir = "./";
if (policy->VAL_OCSP_RESP_CERT.name == NULL ||
policy->VAL_OCSP_RESP_CERT.serial == NULL)
return (KMF_ERR_POLICY_NOT_FOUND);
signer_cert = malloc(sizeof (KMF_DATA));
if (signer_cert == NULL) {
ret = KMF_ERR_MEMORY;
goto out;
}
(void) memset(signer_cert, 0, sizeof (KMF_DATA));
signer_name = policy->VAL_OCSP_RESP_CERT.name;
ret = kmf_hexstr_to_bytes(
(uchar_t *)policy->VAL_OCSP_RESP_CERT.serial,
&bytes, &bytelen);
if (ret != KMF_OK || bytes == NULL) {
ret = KMF_ERR_OCSP_POLICY;
goto out;
}
sernum.val = bytes;
sernum.len = bytelen;
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_KEYSTORE_TYPE_ATTR, kstype,
sizeof (KMF_KEYSTORE_TYPE));
fc_numattr++;
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_SUBJECT_NAME_ATTR, signer_name, strlen(signer_name));
fc_numattr++;
kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_BIGINT_ATTR,
&sernum, sizeof (KMF_BIGINT));
fc_numattr++;
if (*kstype == KMF_KEYSTORE_NSS && slotlabel != NULL) {
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_TOKEN_LABEL_ATTR, slotlabel,
strlen(slotlabel));
fc_numattr++;
}
if (*kstype == KMF_KEYSTORE_OPENSSL) {
if (dirpath == NULL) {
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_DIRPATH_ATTR, dir, strlen(dir));
fc_numattr++;
} else {
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_DIRPATH_ATTR, dirpath,
strlen(dirpath));
fc_numattr++;
}
}
num = 0;
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_COUNT_ATTR, &num, sizeof (uint32_t));
fc_numattr++;
ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
if (ret != KMF_OK || num != 1) {
if (num == 0)
ret = KMF_ERR_CERT_NOT_FOUND;
if (num > 0)
ret = KMF_ERR_CERT_MULTIPLE_FOUND;
goto out;
}
(void) memset(&signer_retrcert, 0, sizeof (KMF_X509_DER_CERT));
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_X509_DER_CERT_ATTR, &signer_retrcert,
sizeof (KMF_X509_DER_CERT));
fc_numattr++;
ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
if (ret == KMF_OK) {
signer_cert->Length =
signer_retrcert.certificate.Length;
signer_cert->Data = signer_retrcert.certificate.Data;
} else {
goto out;
}
}
if (response == NULL) {
new_response = (KMF_DATA *) malloc(sizeof (KMF_DATA));
if (new_response == NULL) {
ret = KMF_ERR_MEMORY;
goto out;
}
new_response->Data = NULL;
new_response->Length = 0;
ret = kmf_get_ocsp_for_cert(handle, user_cert, issuer_cert,
new_response);
if (ret != KMF_OK)
goto out;
}
numattr = 0;
kmf_set_attr_at_index(attrlist, numattr, KMF_ISSUER_CERT_DATA_ATTR,
issuer_cert, sizeof (KMF_DATA));
numattr++;
kmf_set_attr_at_index(attrlist, numattr, KMF_USER_CERT_DATA_ATTR,
user_cert, sizeof (KMF_DATA));
numattr++;
if (signer_cert != NULL) {
kmf_set_attr_at_index(attrlist, numattr,
KMF_SIGNER_CERT_DATA_ATTR, user_cert, sizeof (KMF_DATA));
numattr++;
}
kmf_set_attr_at_index(attrlist, numattr, KMF_OCSP_RESPONSE_DATA_ATTR,
response == NULL ? new_response : response, sizeof (KMF_DATA));
numattr++;
kmf_set_attr_at_index(attrlist, numattr, KMF_RESPONSE_LIFETIME_ATTR,
<ime, sizeof (uint32_t));
numattr++;
kmf_set_attr_at_index(attrlist, numattr,
KMF_IGNORE_RESPONSE_SIGN_ATTR, &ignore_response_sign,
sizeof (boolean_t));
numattr++;
kmf_set_attr_at_index(attrlist, numattr,
KMF_OCSP_RESPONSE_STATUS_ATTR, &response_status, sizeof (int));
numattr++;
kmf_set_attr_at_index(attrlist, numattr,
KMF_OCSP_RESPONSE_REASON_ATTR, &reason, sizeof (int));
numattr++;
kmf_set_attr_at_index(attrlist, numattr,
KMF_OCSP_RESPONSE_CERT_STATUS_ATTR, &cert_status, sizeof (int));
numattr++;
ret = kmf_get_ocsp_status_for_cert(handle, numattr, attrlist);
if (ret == KMF_OK) {
switch (cert_status) {
case OCSP_GOOD:
break;
case OCSP_UNKNOWN:
ret = KMF_ERR_OCSP_UNKNOWN_CERT;
break;
case OCSP_REVOKED:
ret = KMF_ERR_OCSP_REVOKED;
break;
}
}
out:
if (new_response) {
kmf_free_data(new_response);
free(new_response);
}
if (signer_cert) {
kmf_free_data(signer_cert);
free(signer_cert);
}
if (sernum.val != NULL)
free(sernum.val);
return (ret);
}
static KMF_RETURN
cert_ku_check(KMF_HANDLE_T handle, KMF_DATA *cert)
{
KMF_POLICY_RECORD *policy;
KMF_X509EXT_KEY_USAGE keyusage;
KMF_RETURN ret = KMF_OK;
KMF_X509EXT_BASICCONSTRAINTS constraint;
KMF_BOOL critical = B_FALSE;
if (handle == NULL || cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
(void) memset(&keyusage, 0, sizeof (keyusage));
ret = kmf_get_cert_ku(cert, &keyusage);
if (ret == KMF_ERR_EXTENSION_NOT_FOUND) {
if (policy->ku_bits) {
return (KMF_ERR_KEYUSAGE);
} else {
return (KMF_OK);
}
}
if (ret != KMF_OK) {
return (ret);
}
if ((keyusage.KeyUsageBits & KMF_keyCertSign)) {
(void) memset(&constraint, 0, sizeof (constraint));
ret = kmf_get_cert_basic_constraint(cert,
&critical, &constraint);
if (ret != KMF_OK) {
return (ret);
}
if (!constraint.cA || !critical)
return (KMF_ERR_KEYUSAGE);
}
if ((policy->ku_bits & keyusage.KeyUsageBits) == policy->ku_bits) {
return (KMF_OK);
} else {
return (KMF_ERR_KEYUSAGE);
}
}
static KMF_RETURN
cert_eku_check(KMF_HANDLE_T handle, KMF_DATA *cert)
{
KMF_POLICY_RECORD *policy;
KMF_RETURN ret = KMF_OK;
KMF_X509EXT_EKU eku;
uint16_t cert_eku = 0, policy_eku = 0;
int i;
if (handle == NULL || cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
if (policy->eku_set.eku_count == 0)
return (KMF_OK);
ret = kmf_get_cert_eku(cert, &eku);
if ((ret != KMF_ERR_EXTENSION_NOT_FOUND) && (ret != KMF_OK)) {
return (ret);
}
if (ret == KMF_ERR_EXTENSION_NOT_FOUND) {
cert_eku = 0;
} else {
for (i = 0; i < eku.nEKUs; i++) {
if (IsEqualOid(&eku.keyPurposeIdList[i],
(KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) {
cert_eku |= KMF_EKU_SERVERAUTH;
} else if (IsEqualOid(&eku.keyPurposeIdList[i],
(KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) {
cert_eku |= KMF_EKU_CLIENTAUTH;
} else if (IsEqualOid(&eku.keyPurposeIdList[i],
(KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) {
cert_eku |= KMF_EKU_CODESIGNING;
} else if (IsEqualOid(&eku.keyPurposeIdList[i],
(KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) {
cert_eku |= KMF_EKU_EMAIL;
} else if (IsEqualOid(&eku.keyPurposeIdList[i],
(KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) {
cert_eku |= KMF_EKU_TIMESTAMP;
} else if (IsEqualOid(&eku.keyPurposeIdList[i],
(KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) {
cert_eku |= KMF_EKU_OCSPSIGNING;
} else if (!policy->ignore_unknown_ekus) {
return (KMF_ERR_KEYUSAGE);
}
}
}
for (i = 0; i < policy->eku_set.eku_count; i++) {
if (IsEqualOid(&policy->eku_set.ekulist[i],
(KMF_OID *)&KMFOID_PKIX_KP_ServerAuth)) {
policy_eku |= KMF_EKU_SERVERAUTH;
} else if (IsEqualOid(&policy->eku_set.ekulist[i],
(KMF_OID *)&KMFOID_PKIX_KP_ClientAuth)) {
policy_eku |= KMF_EKU_CLIENTAUTH;
} else if (IsEqualOid(&policy->eku_set.ekulist[i],
(KMF_OID *)&KMFOID_PKIX_KP_CodeSigning)) {
policy_eku |= KMF_EKU_CODESIGNING;
} else if (IsEqualOid(&policy->eku_set.ekulist[i],
(KMF_OID *)&KMFOID_PKIX_KP_EmailProtection)) {
policy_eku |= KMF_EKU_EMAIL;
} else if (IsEqualOid(&policy->eku_set.ekulist[i],
(KMF_OID *)&KMFOID_PKIX_KP_TimeStamping)) {
policy_eku |= KMF_EKU_TIMESTAMP;
} else if (IsEqualOid(&policy->eku_set.ekulist[i],
(KMF_OID *)&KMFOID_PKIX_KP_OCSPSigning)) {
policy_eku |= KMF_EKU_OCSPSIGNING;
} else if (!policy->ignore_unknown_ekus) {
return (KMF_ERR_KEYUSAGE);
}
}
if ((policy_eku & cert_eku) == policy_eku) {
return (KMF_OK);
} else {
return (KMF_ERR_KEYUSAGE);
}
}
static KMF_RETURN
find_issuer_cert(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
char *user_issuer, KMF_DATA *issuer_cert,
char *slotlabel, char *dirpath)
{
KMF_RETURN ret = KMF_OK;
KMF_X509_DER_CERT *certlist = NULL;
uint32_t i, num = 0;
time_t t_notbefore;
time_t t_notafter;
time_t latest;
KMF_DATA tmp_cert = { 0, NULL };
KMF_ATTRIBUTE fc_attrlist[16];
int fc_numattr = 0;
char *dir = "./";
if (handle == NULL || kstype == NULL || user_issuer == NULL ||
issuer_cert == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (!is_valid_keystore_type(*kstype))
return (KMF_ERR_BAD_PARAMETER);
kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_KEYSTORE_TYPE_ATTR,
kstype, sizeof (KMF_KEYSTORE_TYPE));
fc_numattr++;
kmf_set_attr_at_index(fc_attrlist, fc_numattr, KMF_SUBJECT_NAME_ATTR,
user_issuer, strlen(user_issuer));
fc_numattr++;
if (*kstype == KMF_KEYSTORE_NSS && slotlabel != NULL) {
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_TOKEN_LABEL_ATTR, slotlabel, strlen(slotlabel));
fc_numattr++;
}
if (*kstype == KMF_KEYSTORE_OPENSSL) {
if (dirpath == NULL) {
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_DIRPATH_ATTR, dir, strlen(dir));
fc_numattr++;
} else {
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_DIRPATH_ATTR, dirpath, strlen(dirpath));
fc_numattr++;
}
}
num = 0;
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_COUNT_ATTR, &num, sizeof (uint32_t));
fc_numattr++;
ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
if (ret == KMF_OK && num > 0) {
certlist = (KMF_X509_DER_CERT *)malloc(num *
sizeof (KMF_X509_DER_CERT));
if (certlist == NULL) {
ret = KMF_ERR_MEMORY;
goto out;
}
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_X509_DER_CERT_ATTR, certlist,
sizeof (KMF_X509_DER_CERT));
fc_numattr++;
ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
if (ret != KMF_OK) {
free(certlist);
certlist = NULL;
goto out;
}
} else {
goto out;
}
if (num == 1) {
tmp_cert.Length = certlist[0].certificate.Length;
tmp_cert.Data = certlist[0].certificate.Data;
} else {
latest = 0;
for (i = 0; i < num; i++) {
ret = kmf_get_cert_validity(&certlist[i].certificate,
&t_notbefore, &t_notafter);
if (ret != KMF_OK) {
ret = KMF_ERR_VALIDITY_PERIOD;
goto out;
}
if (t_notbefore > latest) {
tmp_cert.Length =
certlist[i].certificate.Length;
tmp_cert.Data =
certlist[i].certificate.Data;
latest = t_notbefore;
}
}
}
issuer_cert->Length = tmp_cert.Length;
issuer_cert->Data = malloc(tmp_cert.Length);
if (issuer_cert->Data == NULL) {
ret = KMF_ERR_MEMORY;
goto out;
}
(void) memcpy(issuer_cert->Data, tmp_cert.Data,
tmp_cert.Length);
out:
if (certlist != NULL) {
for (i = 0; i < num; i++)
kmf_free_kmf_cert(handle, &certlist[i]);
free(certlist);
}
return (ret);
}
static KMF_RETURN
find_ta_cert(KMF_HANDLE_T handle, KMF_KEYSTORE_TYPE *kstype,
KMF_DATA *ta_cert, KMF_X509_NAME *user_issuerDN,
char *slotlabel, char *dirpath)
{
KMF_POLICY_RECORD *policy;
KMF_RETURN ret = KMF_OK;
uint32_t num = 0;
char *ta_name;
KMF_BIGINT serial = { NULL, 0 };
uchar_t *bytes = NULL;
size_t bytelen;
KMF_X509_DER_CERT ta_retrCert;
char *ta_subject = NULL;
KMF_X509_NAME ta_subjectDN;
KMF_ATTRIBUTE fc_attrlist[16];
int fc_numattr = 0;
char *dir = "./";
if (handle == NULL || kstype == NULL || ta_cert == NULL ||
user_issuerDN == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (!is_valid_keystore_type(*kstype))
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
ta_name = policy->ta_name;
ret = kmf_hexstr_to_bytes((uchar_t *)policy->ta_serial,
&bytes, &bytelen);
if (ret != KMF_OK || bytes == NULL) {
ret = KMF_ERR_TA_POLICY;
goto out;
}
serial.val = bytes;
serial.len = bytelen;
kmf_set_attr_at_index(fc_attrlist,
fc_numattr++, KMF_BIGINT_ATTR,
&serial, sizeof (KMF_BIGINT));
kmf_set_attr_at_index(fc_attrlist,
fc_numattr++, KMF_SUBJECT_NAME_ATTR,
ta_name, strlen(ta_name));
kmf_set_attr_at_index(fc_attrlist, fc_numattr++, KMF_KEYSTORE_TYPE_ATTR,
kstype, sizeof (KMF_KEYSTORE_TYPE));
if (*kstype == KMF_KEYSTORE_NSS && slotlabel != NULL) {
kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
KMF_TOKEN_LABEL_ATTR, slotlabel, strlen(slotlabel));
}
if (*kstype == KMF_KEYSTORE_OPENSSL) {
if (dirpath == NULL) {
kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
KMF_DIRPATH_ATTR, dir, strlen(dir));
} else {
kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
KMF_DIRPATH_ATTR, dirpath, strlen(dirpath));
}
}
num = 0;
kmf_set_attr_at_index(fc_attrlist, fc_numattr++,
KMF_COUNT_ATTR, &num, sizeof (uint32_t));
ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
if (ret != KMF_OK || num != 1) {
if (num == 0)
ret = KMF_ERR_CERT_NOT_FOUND;
if (num > 1)
ret = KMF_ERR_CERT_MULTIPLE_FOUND;
goto out;
}
kmf_set_attr_at_index(fc_attrlist, fc_numattr,
KMF_X509_DER_CERT_ATTR, &ta_retrCert, sizeof (KMF_X509_DER_CERT));
fc_numattr++;
ret = kmf_find_cert(handle, fc_numattr, fc_attrlist);
if (ret == KMF_OK) {
ta_cert->Length = ta_retrCert.certificate.Length;
ta_cert->Data = malloc(ta_retrCert.certificate.Length);
if (ta_cert->Data == NULL) {
ret = KMF_ERR_MEMORY;
goto out;
}
(void) memcpy(ta_cert->Data, ta_retrCert.certificate.Data,
ta_retrCert.certificate.Length);
} else {
goto out;
}
(void) memset(&ta_subjectDN, 0, sizeof (ta_subjectDN));
ret = kmf_get_cert_subject_str(handle, ta_cert, &ta_subject);
if (ret != KMF_OK)
goto out;
ret = kmf_dn_parser(ta_subject, &ta_subjectDN);
if (ret != KMF_OK)
goto out;
if (kmf_compare_rdns(user_issuerDN, &ta_subjectDN) != 0)
ret = KMF_ERR_CERT_NOT_FOUND;
kmf_free_dn(&ta_subjectDN);
if (ret == KMF_OK) {
ret = check_key_usage(handle, ta_cert, KMF_KU_SIGN_CERT);
if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
ret = KMF_OK;
}
out:
if (ta_retrCert.certificate.Data)
kmf_free_kmf_cert(handle, &ta_retrCert);
if ((ret != KMF_OK))
kmf_free_data(ta_cert);
if (ta_subject != NULL)
free(ta_subject);
if (serial.val != NULL)
free(serial.val);
return (ret);
}
KMF_RETURN
kmf_validate_cert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN ret = KMF_OK;
KMF_KEYSTORE_TYPE *kstype = NULL;
KMF_DATA *pcert = NULL;
int *result = NULL;
char *slotlabel = NULL;
char *dirpath = NULL;
KMF_DATA *ocsp_response = NULL;
KMF_DATA ta_cert = { 0, NULL };
KMF_DATA issuer_cert = { 0, NULL };
char *user_issuer = NULL, *user_subject = NULL;
KMF_X509_NAME user_issuerDN, user_subjectDN;
boolean_t self_signed = B_FALSE;
KMF_POLICY_RECORD *policy;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_CERT_DATA_ATTR, FALSE, sizeof (KMF_DATA), sizeof (KMF_DATA)},
{KMF_VALIDATE_RESULT_ATTR, FALSE, 1, sizeof (int)}
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs,
0, NULL, numattr, attrlist);
if (ret != KMF_OK)
return (ret);
policy = handle->policy;
kstype = kmf_get_attr_ptr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr);
pcert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
result = kmf_get_attr_ptr(KMF_VALIDATE_RESULT_ATTR, attrlist, numattr);
if (kstype == NULL || pcert == NULL || result == NULL)
return (KMF_ERR_BAD_PARAMETER);
slotlabel = kmf_get_attr_ptr(KMF_TOKEN_LABEL_ATTR, attrlist, numattr);
dirpath = kmf_get_attr_ptr(KMF_DIRPATH_ATTR, attrlist, numattr);
ocsp_response = kmf_get_attr_ptr(KMF_OCSP_RESPONSE_DATA_ATTR, attrlist,
numattr);
*result = KMF_CERT_VALIDATE_OK;
if ((ret = kmf_get_cert_issuer_str(handle, pcert,
&user_issuer)) != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_USER;
} else if ((ret = kmf_dn_parser(user_issuer, &user_issuerDN)) !=
KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_USER;
}
if ((ret = kmf_get_cert_subject_str(handle, pcert,
&user_subject)) != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_USER;
} else if ((ret = kmf_dn_parser(user_subject, &user_subjectDN)) !=
KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_USER;
}
if ((*result & KMF_CERT_VALIDATE_ERR_USER) == 0 &&
(kmf_compare_rdns(&user_issuerDN, &user_subjectDN)) == 0) {
self_signed = B_TRUE;
}
kmf_free_dn(&user_subjectDN);
ret = cert_ku_check(handle, pcert);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_KEYUSAGE;
}
ret = cert_eku_check(handle, pcert);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_EXT_KEYUSAGE;
}
if (!policy->ignore_date) {
ret = kmf_check_cert_date(handle, pcert);
if (ret != KMF_OK)
*result |= KMF_CERT_VALIDATE_ERR_TIME;
}
if (policy->ignore_trust_anchor) {
goto check_revocation;
}
if (self_signed) {
ret = verify_cert_with_cert(handle, pcert, pcert);
if (ret != KMF_OK)
*result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
} else if (user_issuer != NULL) {
if (policy->ta_name != NULL &&
strcasecmp(policy->ta_name, "search") == 0) {
ret = find_issuer_cert(handle, kstype, user_issuer,
&issuer_cert, slotlabel, dirpath);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_TA;
} else {
ta_cert = issuer_cert;
}
} else {
ret = find_ta_cert(handle, kstype, &ta_cert,
&user_issuerDN, slotlabel, dirpath);
}
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_TA;
}
if ((*result & KMF_CERT_VALIDATE_ERR_TA) == 0) {
ret = verify_cert_with_cert(handle, pcert,
&ta_cert);
if (ret != KMF_OK)
*result |= KMF_CERT_VALIDATE_ERR_SIGNATURE;
}
} else {
*result |= KMF_CERT_VALIDATE_ERR_TA;
}
check_revocation:
if (self_signed) {
goto out;
}
if (!(policy->revocation & KMF_REVOCATION_METHOD_CRL) &&
!(policy->revocation & KMF_REVOCATION_METHOD_OCSP)) {
goto out;
}
if (issuer_cert.Length == 0 &&
policy->revocation & KMF_REVOCATION_METHOD_CRL ||
policy->revocation & KMF_REVOCATION_METHOD_OCSP) {
ret = find_issuer_cert(handle, kstype, user_issuer,
&issuer_cert, slotlabel, dirpath);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_ISSUER;
}
}
if (policy->revocation & KMF_REVOCATION_METHOD_CRL &&
(*result & KMF_CERT_VALIDATE_ERR_ISSUER) == 0) {
ret = cert_crl_check(handle, kstype, pcert, &issuer_cert);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_CRL;
}
}
if (policy->revocation & KMF_REVOCATION_METHOD_OCSP &&
(*result & KMF_CERT_VALIDATE_ERR_ISSUER) == 0) {
ret = cert_ocsp_check(handle, kstype, pcert, &issuer_cert,
ocsp_response, slotlabel, dirpath);
if (ret != KMF_OK) {
*result |= KMF_CERT_VALIDATE_ERR_OCSP;
}
}
out:
if (user_issuer) {
kmf_free_dn(&user_issuerDN);
free(user_issuer);
}
if (user_subject)
free(user_subject);
if (issuer_cert.Data &&
issuer_cert.Data != ta_cert.Data)
kmf_free_data(&issuer_cert);
kmf_free_data(&ta_cert);
if (*result != 0)
ret = KMF_ERR_CERT_VALIDATION;
return (ret);
}
KMF_RETURN
kmf_create_cert_file(const KMF_DATA *certdata, KMF_ENCODE_FORMAT format,
char *certfile)
{
KMF_RETURN rv = KMF_OK;
int fd = -1;
KMF_DATA pemdata = { 0, NULL };
if (certdata == NULL || certfile == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (format != KMF_FORMAT_PEM && format != KMF_FORMAT_ASN1)
return (KMF_ERR_BAD_PARAMETER);
if (format == KMF_FORMAT_PEM) {
int len;
rv = kmf_der_to_pem(KMF_CERT,
certdata->Data, certdata->Length,
&pemdata.Data, &len);
if (rv != KMF_OK)
goto cleanup;
pemdata.Length = (size_t)len;
}
if ((fd = open(certfile, O_CREAT | O_RDWR | O_TRUNC, 0644)) == -1) {
rv = KMF_ERR_OPEN_FILE;
goto cleanup;
}
if (format == KMF_FORMAT_PEM) {
if (write(fd, pemdata.Data, pemdata.Length) !=
pemdata.Length) {
rv = KMF_ERR_WRITE_FILE;
}
} else {
if (write(fd, certdata->Data, certdata->Length) !=
certdata->Length) {
rv = KMF_ERR_WRITE_FILE;
}
}
cleanup:
if (fd != -1)
(void) close(fd);
kmf_free_data(&pemdata);
return (rv);
}
KMF_RETURN
kmf_is_cert_data(KMF_DATA *data, KMF_ENCODE_FORMAT *fmt)
{
KMF_RETURN rv = KMF_OK;
KMF_X509_CERTIFICATE *x509 = NULL;
KMF_DATA oldpem = { 0, NULL };
uchar_t *d = NULL;
int len = 0;
if (data == NULL || fmt == NULL)
return (KMF_ERR_BAD_PARAMETER);
rv = kmf_get_data_format(data, fmt);
if (rv != KMF_OK)
return (rv);
switch (*fmt) {
case KMF_FORMAT_ASN1:
rv = DerDecodeSignedCertificate(data, &x509);
break;
case KMF_FORMAT_PEM:
rv = kmf_pem_to_der(data->Data, data->Length,
&d, &len);
if (rv != KMF_OK)
return (rv);
oldpem.Data = d;
oldpem.Length = len;
rv = DerDecodeSignedCertificate(&oldpem, &x509);
kmf_free_data(&oldpem);
break;
case KMF_FORMAT_PKCS12:
case KMF_FORMAT_UNDEF:
default:
return (KMF_ERR_ENCODING);
}
if (x509 != NULL) {
kmf_free_signed_cert(x509);
free(x509);
}
return (rv);
}
KMF_RETURN
kmf_is_cert_file(KMF_HANDLE_T handle, char *filename,
KMF_ENCODE_FORMAT *pformat)
{
KMF_RETURN ret;
KMF_DATA filedata;
CLEAR_ERROR(handle, ret);
if (ret != KMF_OK)
return (ret);
if (filename == NULL || pformat == NULL)
return (KMF_ERR_BAD_PARAMETER);
ret = kmf_read_input_file(handle, filename, &filedata);
if (ret != KMF_OK)
return (ret);
ret = kmf_is_cert_data(&filedata, pformat);
if (ret == KMF_ERR_BAD_CERT_FORMAT)
ret = KMF_ERR_BAD_CERTFILE;
kmf_free_data(&filedata);
return (ret);
}
KMF_RETURN
kmf_check_cert_date(KMF_HANDLE_T handle, const KMF_DATA *cert)
{
KMF_RETURN rv;
struct tm *gmt;
time_t t_now;
time_t t_notbefore;
time_t t_notafter;
KMF_POLICY_RECORD *policy;
uint32_t adj;
CLEAR_ERROR(handle, rv);
if (rv != KMF_OK)
return (rv);
if (cert == NULL || cert->Data == NULL || cert->Length == 0)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
rv = kmf_get_cert_validity(cert, &t_notbefore, &t_notafter);
if (rv != KMF_OK)
return (rv);
t_now = time(NULL);
gmt = gmtime(&t_now);
t_now = mktime(gmt);
if (policy->validity_adjusttime != NULL) {
if (str2lifetime(policy->validity_adjusttime, &adj) < 0)
return (KMF_ERR_VALIDITY_PERIOD);
} else {
adj = 0;
}
t_notafter += adj;
t_notbefore -= adj;
if (t_now <= t_notafter && t_now >= t_notbefore) {
rv = KMF_OK;
} else {
rv = KMF_ERR_VALIDITY_PERIOD;
}
return (rv);
}
KMF_RETURN
kmf_export_pk12(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_PLUGIN *plugin;
KMF_RETURN ret = KMF_OK;
KMF_KEYSTORE_TYPE kstype;
KMF_ATTRIBUTE_TESTER required_attrs[] = {
{KMF_KEYSTORE_TYPE_ATTR, FALSE, 1, sizeof (KMF_KEYSTORE_TYPE)},
{KMF_OUTPUT_FILENAME_ATTR, TRUE, 1, 0},
};
int num_req_attrs = sizeof (required_attrs) /
sizeof (KMF_ATTRIBUTE_TESTER);
if (handle == NULL)
return (KMF_ERR_BAD_PARAMETER);
CLEAR_ERROR(handle, ret);
ret = test_attributes(num_req_attrs, required_attrs, 0, NULL,
numattr, attrlist);
if (ret != KMF_OK)
return (ret);
ret = kmf_get_attr(KMF_KEYSTORE_TYPE_ATTR, attrlist, numattr,
&kstype, NULL);
if (ret != KMF_OK)
return (ret);
plugin = FindPlugin(handle, kstype);
if (plugin == NULL || plugin->funclist->ExportPK12 == NULL)
return (KMF_ERR_PLUGIN_NOTFOUND);
return (plugin->funclist->ExportPK12(handle, numattr, attrlist));
}
KMF_RETURN
kmf_build_pk12(KMF_HANDLE_T handle, int numcerts,
KMF_X509_DER_CERT *certlist, int numkeys, KMF_KEY_HANDLE *keylist,
KMF_CREDENTIAL *p12cred, char *filename)
{
KMF_RETURN rv;
KMF_PLUGIN *plugin;
KMF_RETURN (*buildpk12)(KMF_HANDLE *, int, KMF_X509_DER_CERT *,
int, KMF_KEY_HANDLE *, KMF_CREDENTIAL *, char *);
CLEAR_ERROR(handle, rv);
if (rv != KMF_OK)
return (rv);
if (filename == NULL || p12cred == NULL ||
(certlist == NULL && keylist == NULL))
return (KMF_ERR_BAD_PARAMETER);
plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
if (plugin == NULL || plugin->dldesc == NULL) {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
buildpk12 = (KMF_RETURN(*)())dlsym(plugin->dldesc,
"openssl_build_pk12");
if (buildpk12 == NULL) {
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
rv = buildpk12(handle, numcerts, certlist, numkeys, keylist, p12cred,
filename);
return (rv);
}
KMF_RETURN
kmf_import_objects(KMF_HANDLE_T handle, char *filename,
KMF_CREDENTIAL *cred,
KMF_X509_DER_CERT **certs, int *ncerts,
KMF_RAW_KEY_DATA **rawkeys, int *nkeys)
{
KMF_RETURN rv;
KMF_PLUGIN *plugin;
KMF_RETURN (*import_objects)(KMF_HANDLE *, char *, KMF_CREDENTIAL *,
KMF_X509_DER_CERT **, int *, KMF_RAW_KEY_DATA **, int *);
CLEAR_ERROR(handle, rv);
if (rv != KMF_OK)
return (rv);
if (filename == NULL || cred == NULL || certs == NULL ||
ncerts == NULL ||rawkeys == NULL || nkeys == NULL)
return (KMF_ERR_BAD_PARAMETER);
plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
if (plugin == NULL || plugin->dldesc == NULL) {
return (KMF_ERR_PLUGIN_NOTFOUND);
}
import_objects = (KMF_RETURN(*)())dlsym(plugin->dldesc,
"openssl_import_objects");
if (import_objects == NULL) {
return (KMF_ERR_FUNCTION_NOT_FOUND);
}
rv = import_objects(handle, filename, cred, certs, ncerts,
rawkeys, nkeys);
return (rv);
}
KMF_BOOL
IsEqualOid(KMF_OID *Oid1, KMF_OID *Oid2)
{
return ((Oid1->Length == Oid2->Length) &&
!memcmp(Oid1->Data, Oid2->Data, Oid1->Length));
}
static KMF_RETURN
set_algoid(KMF_X509_ALGORITHM_IDENTIFIER *destid,
KMF_OID *newoid)
{
if (destid == NULL || newoid == NULL)
return (KMF_ERR_BAD_PARAMETER);
destid->algorithm.Length = newoid->Length;
destid->algorithm.Data = malloc(destid->algorithm.Length);
if (destid->algorithm.Data == NULL)
return (KMF_ERR_MEMORY);
(void) memcpy(destid->algorithm.Data, newoid->Data,
destid->algorithm.Length);
return (KMF_OK);
}
KMF_RETURN
copy_algoid(KMF_X509_ALGORITHM_IDENTIFIER *destid,
KMF_X509_ALGORITHM_IDENTIFIER *srcid)
{
KMF_RETURN ret = KMF_OK;
if (!destid || !srcid)
return (KMF_ERR_BAD_PARAMETER);
destid->algorithm.Length = srcid->algorithm.Length;
destid->algorithm.Data = malloc(destid->algorithm.Length);
if (destid->algorithm.Data == NULL)
return (KMF_ERR_MEMORY);
(void) memcpy(destid->algorithm.Data, srcid->algorithm.Data,
destid->algorithm.Length);
destid->parameters.Length = srcid->parameters.Length;
if (destid->parameters.Length > 0) {
destid->parameters.Data = malloc(destid->parameters.Length);
if (destid->parameters.Data == NULL)
return (KMF_ERR_MEMORY);
(void) memcpy(destid->parameters.Data, srcid->parameters.Data,
destid->parameters.Length);
} else {
destid->parameters.Data = NULL;
}
return (ret);
}
static KMF_RETURN
sign_cert(KMF_HANDLE_T handle,
const KMF_DATA *SubjectCert,
KMF_KEY_HANDLE *Signkey,
KMF_OID *signature_oid,
KMF_DATA *SignedCert)
{
KMF_X509_CERTIFICATE *subj_cert = NULL;
KMF_DATA data_to_sign = { 0, NULL };
KMF_DATA signed_data = { 0, NULL };
KMF_RETURN ret = KMF_OK;
KMF_ALGORITHM_INDEX algid;
int i = 0;
KMF_ATTRIBUTE attrlist[8];
if (!SignedCert)
return (KMF_ERR_BAD_PARAMETER);
SignedCert->Length = 0;
SignedCert->Data = NULL;
if (!SubjectCert)
return (KMF_ERR_BAD_PARAMETER);
if (!SubjectCert->Data || !SubjectCert->Length)
return (KMF_ERR_BAD_PARAMETER);
ret = ExtractX509CertParts((KMF_DATA *)SubjectCert,
&data_to_sign, NULL);
if (ret != KMF_OK) {
goto cleanup;
}
signed_data.Length = data_to_sign.Length*2;
signed_data.Data = calloc(1, signed_data.Length);
if (!signed_data.Data) {
ret = KMF_ERR_MEMORY;
goto cleanup;
}
ret = DerDecodeSignedCertificate(SubjectCert, &subj_cert);
if (ret != KMF_OK) {
goto cleanup;
}
if (!IsEqualOid(&subj_cert->signature.algorithmIdentifier.algorithm,
signature_oid)) {
kmf_free_algoid(&subj_cert->signature.algorithmIdentifier);
ret = set_algoid(&subj_cert->signature.algorithmIdentifier,
signature_oid);
if (ret != KMF_OK)
goto cleanup;
ret = set_algoid(&subj_cert->certificate.signature,
signature_oid);
if (ret)
goto cleanup;
kmf_free_data(&data_to_sign);
ret = DerEncodeTbsCertificate(&subj_cert->certificate,
&data_to_sign);
if (ret != KMF_OK)
goto cleanup;
}
kmf_set_attr_at_index(attrlist, i, KMF_KEYSTORE_TYPE_ATTR,
&Signkey->kstype, sizeof (KMF_KEYSTORE_TYPE));
i++;
kmf_set_attr_at_index(attrlist, i, KMF_KEY_HANDLE_ATTR,
Signkey, sizeof (KMF_KEY_HANDLE));
i++;
kmf_set_attr_at_index(attrlist, i, KMF_DATA_ATTR,
&data_to_sign, sizeof (KMF_DATA));
i++;
kmf_set_attr_at_index(attrlist, i, KMF_OUT_DATA_ATTR,
&signed_data, sizeof (KMF_DATA));
i++;
kmf_set_attr_at_index(attrlist, i, KMF_OID_ATTR,
signature_oid, sizeof (KMF_OID));
i++;
ret = kmf_sign_data(handle, i, attrlist);
if (ret != KMF_OK)
goto cleanup;
algid = x509_algoid_to_algid(signature_oid);
if (algid == KMF_ALGID_SHA1WithECDSA ||
algid == KMF_ALGID_SHA256WithECDSA ||
algid == KMF_ALGID_SHA384WithECDSA ||
algid == KMF_ALGID_SHA512WithECDSA) {
KMF_DATA signature;
ret = DerEncodeECDSASignature(&signed_data, &signature);
kmf_free_data(&signed_data);
if (ret != KMF_OK)
goto cleanup;
subj_cert->signature.encrypted = signature;
} else if (algid == KMF_ALGID_SHA1WithDSA ||
algid == KMF_ALGID_SHA256WithDSA) {
KMF_DATA signature;
ret = DerEncodeDSASignature(&signed_data, &signature);
kmf_free_data(&signed_data);
if (ret != KMF_OK)
goto cleanup;
subj_cert->signature.encrypted = signature;
} else {
ret = copy_data(&subj_cert->signature.encrypted, &signed_data);
kmf_free_data(&signed_data);
if (ret != KMF_OK)
goto cleanup;
}
ret = DerEncodeSignedCertificate(subj_cert, SignedCert);
cleanup:
if (ret != KMF_OK)
kmf_free_data(SignedCert);
kmf_free_data(&data_to_sign);
if (subj_cert != NULL) {
kmf_free_signed_cert(subj_cert);
free(subj_cert);
}
return (ret);
}
static KMF_RETURN
verify_cert_with_key(KMF_HANDLE_T handle,
KMF_DATA *derkey,
const KMF_DATA *CertToBeVerified)
{
KMF_RETURN ret = KMF_OK;
KMF_X509_CERTIFICATE *signed_cert = NULL;
KMF_X509_SPKI spki;
KMF_DATA data_to_verify = { 0, NULL };
KMF_DATA signed_data = { 0, NULL };
KMF_DATA signature = { 0, NULL };
KMF_ALGORITHM_INDEX algid;
if (handle == NULL || CertToBeVerified == NULL ||
derkey == NULL || derkey->Data == NULL)
return (KMF_ERR_BAD_PARAMETER);
(void) memset(&spki, 0, sizeof (KMF_X509_SPKI));
ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerified,
&data_to_verify, &signed_data);
if (ret != KMF_OK)
goto cleanup;
ret = DerDecodeSPKI(derkey, &spki);
if (ret != KMF_OK)
goto cleanup;
ret = DerDecodeSignedCertificate(CertToBeVerified, &signed_cert);
if (ret != KMF_OK)
return (ret);
algid = x509_algoid_to_algid(CERT_SIG_OID(signed_cert));
if (algid == KMF_ALGID_NONE)
return (KMF_ERR_BAD_ALGORITHM);
if (algid == KMF_ALGID_SHA1WithDSA ||
algid == KMF_ALGID_SHA256WithDSA) {
ret = DerDecodeDSASignature(&signed_data, &signature);
if (ret != KMF_OK)
goto cleanup;
} else if (algid == KMF_ALGID_SHA1WithECDSA ||
algid == KMF_ALGID_SHA256WithECDSA ||
algid == KMF_ALGID_SHA384WithECDSA ||
algid == KMF_ALGID_SHA512WithECDSA) {
ret = DerDecodeECDSASignature(&signed_data, &signature);
if (ret != KMF_OK)
goto cleanup;
} else {
signature.Data = signed_data.Data;
signature.Length = signed_data.Length;
}
ret = PKCS_VerifyData(handle, algid, &spki,
&data_to_verify, &signature);
cleanup:
if (data_to_verify.Data != NULL)
free(data_to_verify.Data);
if (signed_data.Data != NULL)
free(signed_data.Data);
if (signed_cert) {
kmf_free_signed_cert(signed_cert);
free(signed_cert);
}
if (algid == KMF_ALGID_SHA1WithDSA ||
algid == KMF_ALGID_SHA256WithDSA ||
algid == KMF_ALGID_SHA1WithECDSA ||
algid == KMF_ALGID_SHA256WithECDSA ||
algid == KMF_ALGID_SHA384WithECDSA ||
algid == KMF_ALGID_SHA512WithECDSA) {
free(signature.Data);
}
kmf_free_algoid(&spki.algorithm);
kmf_free_data(&spki.subjectPublicKey);
return (ret);
}
static KMF_RETURN
verify_cert_with_cert(KMF_HANDLE_T handle,
const KMF_DATA *CertToBeVerifiedData,
const KMF_DATA *SignerCertData)
{
KMF_RETURN ret = KMF_OK;
KMF_X509_CERTIFICATE *SignerCert = NULL;
KMF_X509_CERTIFICATE *ToBeVerifiedCert = NULL;
KMF_DATA data_to_verify = { 0, NULL };
KMF_DATA signed_data = { 0, NULL };
KMF_DATA signature;
KMF_ALGORITHM_INDEX algid;
KMF_POLICY_RECORD *policy;
if (handle == NULL ||
!CertToBeVerifiedData ||
!CertToBeVerifiedData->Data ||
!CertToBeVerifiedData->Length)
return (KMF_ERR_BAD_PARAMETER);
if (!SignerCertData ||
!SignerCertData->Data ||
!SignerCertData->Length)
return (KMF_ERR_BAD_PARAMETER);
policy = handle->policy;
ret = check_key_usage(handle, SignerCertData, KMF_KU_SIGN_CERT);
if (ret == KMF_ERR_EXTENSION_NOT_FOUND && policy->ku_bits == 0)
ret = KMF_OK;
if (ret != KMF_OK)
return (ret);
ret = ExtractX509CertParts((KMF_DATA *)CertToBeVerifiedData,
&data_to_verify, &signed_data);
if (ret != KMF_OK)
goto cleanup;
ret = DerDecodeSignedCertificate(CertToBeVerifiedData,
&ToBeVerifiedCert);
if (ret != KMF_OK)
goto cleanup;
algid = x509_algoid_to_algid(CERT_SIG_OID(ToBeVerifiedCert));
if (algid == KMF_ALGID_SHA1WithDSA ||
algid == KMF_ALGID_SHA256WithDSA) {
ret = DerDecodeDSASignature(&signed_data, &signature);
if (ret != KMF_OK)
goto cleanup;
} else if (algid == KMF_ALGID_SHA1WithECDSA ||
algid == KMF_ALGID_SHA256WithECDSA ||
algid == KMF_ALGID_SHA384WithECDSA ||
algid == KMF_ALGID_SHA512WithECDSA) {
ret = DerDecodeECDSASignature(&signed_data, &signature);
if (ret != KMF_OK)
goto cleanup;
} else {
signature.Data = signed_data.Data;
signature.Length = signed_data.Length;
}
ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert);
if (ret != KMF_OK)
goto cleanup;
ret = PKCS_VerifyData(handle, algid,
&SignerCert->certificate.subjectPublicKeyInfo,
&data_to_verify, &signature);
cleanup:
kmf_free_data(&data_to_verify);
kmf_free_data(&signed_data);
if (SignerCert) {
kmf_free_signed_cert(SignerCert);
free(SignerCert);
}
if (ToBeVerifiedCert) {
kmf_free_signed_cert(ToBeVerifiedCert);
free(ToBeVerifiedCert);
}
if (algid == KMF_ALGID_SHA1WithDSA ||
algid == KMF_ALGID_SHA256WithDSA ||
algid == KMF_ALGID_SHA1WithECDSA ||
algid == KMF_ALGID_SHA256WithECDSA ||
algid == KMF_ALGID_SHA384WithECDSA ||
algid == KMF_ALGID_SHA512WithECDSA) {
free(signature.Data);
}
return (ret);
}