blob: bab6957c45fa225a137bba823974452f8b151fea [file] [log] [blame]
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* PKCS11 token KMF Plugin
*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdio.h> /* debugging only */
#include <errno.h>
#include <values.h>
#include <kmfapiP.h>
#include <ber_der.h>
#include <fcntl.h>
#include <sha1.h>
#include <bignum.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>
#define DEV_RANDOM "/dev/random"
#define SETATTR(t, n, atype, value, size) \
t[n].type = atype; \
t[n].pValue = (CK_BYTE *)value; \
t[n].ulValueLen = (CK_ULONG)size;
#define SET_ERROR(h, c) h->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; \
h->lasterr.errcode = c;
typedef struct _objlist {
CK_OBJECT_HANDLE handle;
struct _objlist *next;
} OBJLIST;
static KMF_RETURN
search_certs(KMF_HANDLE_T, char *, char *, char *, KMF_BIGINT *,
boolean_t, KMF_CERT_VALIDITY, OBJLIST **, uint32_t *);
static CK_RV
getObjectLabel(KMF_HANDLE_T, CK_OBJECT_HANDLE, char **);
static KMF_RETURN
keyObj2RawKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_KEY_DATA **);
static KMF_RETURN
create_generic_secret_key(KMF_HANDLE_T,
int, KMF_ATTRIBUTE *, CK_OBJECT_HANDLE *);
KMF_RETURN
KMFPK11_ConfigureKeystore(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_FindCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
void
KMFPK11_FreeKMFCert(KMF_HANDLE_T,
KMF_X509_DER_CERT *kmf_cert);
KMF_RETURN
KMFPK11_StoreCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_ImportCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_DeleteCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_CreateKeypair(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_StoreKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_DeleteKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_EncodePubKeyData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_DATA *);
KMF_RETURN
KMFPK11_SignData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
KMF_DATA *, KMF_DATA *);
KMF_RETURN
KMFPK11_GetErrorString(KMF_HANDLE_T, char **);
KMF_RETURN
KMFPK11_FindPrikeyByCert(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_DecryptData(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_OID *,
KMF_DATA *, KMF_DATA *);
KMF_RETURN
KMFPK11_FindKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_CreateSymKey(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *);
KMF_RETURN
KMFPK11_SetTokenPin(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
KMF_RETURN
KMFPK11_ExportPK12(KMF_HANDLE_T, int, KMF_ATTRIBUTE *);
static
KMF_PLUGIN_FUNCLIST pk11token_plugin_table =
{
1, /* Version */
KMFPK11_ConfigureKeystore,
KMFPK11_FindCert,
KMFPK11_FreeKMFCert,
KMFPK11_StoreCert,
KMFPK11_ImportCert,
NULL, /* ImportCRL */
KMFPK11_DeleteCert,
NULL, /* DeleteCRL */
KMFPK11_CreateKeypair,
KMFPK11_FindKey,
KMFPK11_EncodePubKeyData,
KMFPK11_SignData,
KMFPK11_DeleteKey,
NULL, /* ListCRL */
NULL, /* FindCRL */
NULL, /* FindCertInCRL */
KMFPK11_GetErrorString,
KMFPK11_FindPrikeyByCert,
KMFPK11_DecryptData,
KMFPK11_ExportPK12,
KMFPK11_CreateSymKey,
KMFPK11_GetSymKeyValue,
KMFPK11_SetTokenPin,
KMFPK11_StoreKey,
NULL /* Finalize */
};
KMF_PLUGIN_FUNCLIST *
KMF_Plugin_Initialize()
{
return (&pk11token_plugin_table);
}
KMF_RETURN
KMFPK11_ConfigureKeystore(KMF_HANDLE_T handle,
int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN rv = KMF_OK;
char *label;
boolean_t readonly = B_TRUE;
label = kmf_get_attr_ptr(KMF_TOKEN_LABEL_ATTR, attrlist, numattr);
if (label == NULL) {
return (KMF_ERR_BAD_PARAMETER);
}
/* "readonly" is optional. Default is TRUE */
(void) kmf_get_attr(KMF_READONLY_ATTR, attrlist, numattr,
(void *)&readonly, NULL);
rv = kmf_select_token(handle, label, readonly);
return (rv);
}
static KMF_RETURN
pk11_authenticate(KMF_HANDLE_T handle,
KMF_CREDENTIAL *cred)
{
CK_RV ck_rv = CKR_OK;
CK_SESSION_HANDLE hSession = (CK_SESSION_HANDLE)handle->pk11handle;
if (hSession == NULL)
return (KMF_ERR_NO_TOKEN_SELECTED);
if (cred == NULL || cred->cred == NULL) {
return (KMF_ERR_BAD_PARAMETER);
}
if ((ck_rv = C_Login(hSession, CKU_USER, (uchar_t *)cred->cred,
cred->credlen)) != CKR_OK) {
if (ck_rv != CKR_USER_ALREADY_LOGGED_IN) {
handle->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
handle->lasterr.errcode = ck_rv;
return (KMF_ERR_AUTH_FAILED);
}
}
return (KMF_OK);
}
static KMF_RETURN
PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
KMF_X509_DER_CERT *kmfcert)
{
KMF_RETURN rv = 0;
CK_RV ckrv = CKR_OK;
CK_CERTIFICATE_TYPE cktype;
CK_OBJECT_CLASS class;
CK_ULONG subject_len, value_len, issuer_len, serno_len, id_len;
CK_BYTE *subject = NULL, *value = NULL;
char *label = NULL;
CK_ATTRIBUTE templ[10];
(void) memset(templ, 0, 10 * sizeof (CK_ATTRIBUTE));
SETATTR(templ, 0, CKA_CLASS, &class, sizeof (class));
/* Is this a certificate object ? */
ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 1);
if (ckrv != CKR_OK || class != CKO_CERTIFICATE) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL);
}
SETATTR(templ, 0, CKA_CERTIFICATE_TYPE, &cktype, sizeof (cktype));
ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 1);
if (ckrv != CKR_OK || cktype != CKC_X_509) {
SET_ERROR(kmfh, ckrv);
return (ckrv);
} else {
int i = 0;
/* What attributes are available and how big are they? */
subject_len = issuer_len = serno_len = id_len = value_len = 0;
SETATTR(templ, i, CKA_SUBJECT, NULL, subject_len);
i++;
SETATTR(templ, i, CKA_ISSUER, NULL, issuer_len);
i++;
SETATTR(templ, i, CKA_SERIAL_NUMBER, NULL, serno_len);
i++;
SETATTR(templ, i, CKA_ID, NULL, id_len);
i++;
SETATTR(templ, i, CKA_VALUE, NULL, value_len);
i++;
/*
* Query the object with NULL values in the pValue spot
* so we know how much space to allocate for each field.
*/
ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, i);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL); /* TODO - Error messages ? */
}
subject_len = templ[0].ulValueLen;
issuer_len = templ[1].ulValueLen;
serno_len = templ[2].ulValueLen;
id_len = templ[3].ulValueLen;
value_len = templ[4].ulValueLen;
/*
* For PKCS#11 CKC_X_509 certificate objects,
* the following attributes must be defined.
* CKA_SUBJECT, CKA_ID, CKA_ISSUER, CKA_SERIAL_NUMBER,
* CKA_VALUE.
*/
if (subject_len == 0 || issuer_len == 0 ||
serno_len == 0 || value_len == 0) {
return (KMF_ERR_INTERNAL);
}
/* Only fetch the value field if we are saving the data */
if (kmfcert != NULL) {
int i = 0;
value = malloc(value_len);
if (value == NULL) {
rv = KMF_ERR_MEMORY;
goto errout;
}
SETATTR(templ, i, CKA_VALUE, value, value_len);
i++;
/* re-query the object with room for the value attr */
ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj,
templ, i);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto errout;
}
kmfcert->certificate.Data = value;
kmfcert->certificate.Length = value_len;
kmfcert->kmf_private.flags |= KMF_FLAG_CERT_SIGNED;
kmfcert->kmf_private.keystore_type =
KMF_KEYSTORE_PK11TOKEN;
ckrv = getObjectLabel(kmfh, hObj, &label);
if (ckrv == CKR_OK && label != NULL) {
kmfcert->kmf_private.label = (char *)label;
}
rv = KMF_OK;
}
}
errout:
if (rv != KMF_OK) {
if (subject)
free(subject);
if (value)
free(value);
if (kmfcert) {
kmfcert->certificate.Data = NULL;
kmfcert->certificate.Length = 0;
}
}
return (rv);
}
static void
free_objlist(OBJLIST *head)
{
OBJLIST *temp = head;
while (temp != NULL) {
head = head->next;
free(temp);
temp = head;
}
}
/*
* The caller should make sure that the templ->pValue is NULL since
* it will be overwritten below.
*/
static KMF_RETURN
get_attr(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj,
CK_ATTRIBUTE *templ)
{
CK_RV rv;
rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1);
if (rv != CKR_OK) {
SET_ERROR(kmfh, rv);
return (KMF_ERR_INTERNAL);
}
if (templ->ulValueLen > 0) {
templ->pValue = malloc(templ->ulValueLen);
if (templ->pValue == NULL)
return (KMF_ERR_MEMORY);
rv = C_GetAttributeValue(kmfh->pk11handle, obj, templ, 1);
if (rv != CKR_OK) {
SET_ERROR(kmfh, rv);
return (KMF_ERR_INTERNAL);
}
}
return (KMF_OK);
}
/*
* Match a certificate with an issuer and/or subject name.
* This is tricky because we cannot reliably compare DER encodings
* because RDNs may have their AV-pairs in different orders even
* if the values are the same. You must compare individual
* AV pairs for the RDNs.
*
* RETURN: 0 for a match, non-zero for a non-match.
*/
static KMF_RETURN
matchcert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj,
KMF_X509_NAME *issuer, KMF_X509_NAME *subject)
{
KMF_RETURN rv = KMF_OK;
CK_ATTRIBUTE certattr;
KMF_DATA name;
KMF_X509_NAME dn;
if (issuer->numberOfRDNs > 0) {
certattr.type = CKA_ISSUER;
certattr.pValue = NULL;
certattr.ulValueLen = 0;
rv = get_attr(kmfh, obj, &certattr);
if (rv == KMF_OK) {
name.Data = certattr.pValue;
name.Length = certattr.ulValueLen;
rv = DerDecodeName(&name, &dn);
if (rv == KMF_OK) {
rv = kmf_compare_rdns(issuer, &dn);
kmf_free_dn(&dn);
}
free(certattr.pValue);
}
if (rv != KMF_OK)
return (rv);
}
if (subject->numberOfRDNs > 0) {
certattr.type = CKA_SUBJECT;
certattr.pValue = NULL;
certattr.ulValueLen = 0;
rv = get_attr(kmfh, obj, &certattr);
if (rv == KMF_OK) {
name.Data = certattr.pValue;
name.Length = certattr.ulValueLen;
rv = DerDecodeName(&name, &dn);
if (rv == KMF_OK) {
rv = kmf_compare_rdns(subject, &dn);
kmf_free_dn(&dn);
}
free(certattr.pValue);
}
}
return (rv);
}
/*
* delete "curr" node from the "newlist".
*/
static void
pk11_delete_obj_from_list(OBJLIST **newlist,
OBJLIST **prev, OBJLIST **curr)
{
if (*curr == *newlist) {
/* first node in the list */
*newlist = (*curr)->next;
*prev = (*curr)->next;
free(*curr);
*curr = *newlist;
} else {
(*prev)->next = (*curr)->next;
free(*curr);
*curr = (*prev)->next;
}
}
/*
* search_certs
*
* Because this code is shared by the FindCert and
* DeleteCert functions, put it in a separate routine
* to save some work and make code easier to debug and
* read.
*/
static KMF_RETURN
search_certs(KMF_HANDLE_T handle,
char *label, char *issuer, char *subject, KMF_BIGINT *serial,
boolean_t private, KMF_CERT_VALIDITY validity,
OBJLIST **objlist, uint32_t *numobj)
{
KMF_RETURN rv = KMF_OK;
CK_RV ckrv = CKR_OK;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
CK_ATTRIBUTE templ[10];
CK_BBOOL true = TRUE;
CK_OBJECT_CLASS oclass = CKO_CERTIFICATE;
CK_CERTIFICATE_TYPE ctype = CKC_X_509;
KMF_X509_NAME subjectDN, issuerDN;
int i;
OBJLIST *newlist, *tail;
CK_ULONG num = 0;
uint32_t num_ok_certs = 0; /* number of non-expired or expired certs */
(void) memset(&templ, 0, 10 * sizeof (CK_ATTRIBUTE));
(void) memset(&issuerDN, 0, sizeof (KMF_X509_NAME));
(void) memset(&subjectDN, 0, sizeof (KMF_X509_NAME));
i = 0;
SETATTR(templ, i, CKA_TOKEN, &true, sizeof (true)); i++;
SETATTR(templ, i, CKA_CLASS, &oclass, sizeof (oclass)); i++;
SETATTR(templ, i, CKA_CERTIFICATE_TYPE, &ctype, sizeof (ctype)); i++;
if (label != NULL && strlen(label)) {
SETATTR(templ, i, CKA_LABEL, label, strlen(label));
i++;
}
if (private) {
SETATTR(templ, i, CKA_PRIVATE, &true, sizeof (true)); i++;
}
if (issuer != NULL && strlen(issuer)) {
if ((rv = kmf_dn_parser(issuer, &issuerDN)) != KMF_OK)
return (rv);
}
if (subject != NULL && strlen(subject)) {
if ((rv = kmf_dn_parser(subject, &subjectDN)) != KMF_OK)
return (rv);
}
if (serial != NULL && serial->val != NULL && serial->len > 0) {
SETATTR(templ, i, CKA_SERIAL_NUMBER, serial->val, serial->len);
i++;
}
(*numobj) = 0;
*objlist = NULL;
newlist = NULL;
ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, i);
if (ckrv != CKR_OK)
goto cleanup;
tail = newlist = NULL;
while (ckrv == CKR_OK) {
CK_OBJECT_HANDLE tObj;
ckrv = C_FindObjects(kmfh->pk11handle, &tObj, 1, &num);
if (ckrv != CKR_OK || num == 0)
break;
/*
* 'matchcert' returns 0 if subject/issuer match
*
* If no match, move on to the next one
*/
if (matchcert(kmfh, tObj, &issuerDN, &subjectDN))
continue;
if (newlist == NULL) {
newlist = malloc(sizeof (OBJLIST));
if (newlist == NULL) {
rv = KMF_ERR_MEMORY;
break;
}
newlist->handle = tObj;
newlist->next = NULL;
tail = newlist;
} else {
tail->next = malloc(sizeof (OBJLIST));
if (tail->next != NULL) {
tail = tail->next;
} else {
rv = KMF_ERR_MEMORY;
break;
}
tail->handle = tObj;
tail->next = NULL;
}
(*numobj)++;
}
ckrv = C_FindObjectsFinal(kmfh->pk11handle);
cleanup:
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
if (newlist != NULL) {
free_objlist(newlist);
*numobj = 0;
newlist = NULL;
}
} else {
if (validity == KMF_ALL_CERTS) {
*objlist = newlist;
} else {
OBJLIST *node, *prev;
KMF_X509_DER_CERT tmp_kmf_cert;
uint32_t i = 0;
node = prev = newlist;
/*
* Now check to see if any found certificate is expired
* or valid.
*/
while (node != NULL && i < (*numobj)) {
(void) memset(&tmp_kmf_cert, 0,
sizeof (KMF_X509_DER_CERT));
rv = PK11Cert2KMFCert(kmfh, node->handle,
&tmp_kmf_cert);
if (rv != KMF_OK) {
goto cleanup1;
}
rv = kmf_check_cert_date(handle,
&tmp_kmf_cert.certificate);
if (validity == KMF_NONEXPIRED_CERTS) {
if (rv == KMF_OK) {
num_ok_certs++;
prev = node;
node = node->next;
} else if (rv ==
KMF_ERR_VALIDITY_PERIOD) {
/*
* expired - remove it from list
*/
pk11_delete_obj_from_list(
&newlist, &prev, &node);
} else {
goto cleanup1;
}
}
if (validity == KMF_EXPIRED_CERTS) {
if (rv == KMF_ERR_VALIDITY_PERIOD) {
num_ok_certs++;
prev = node;
node = node->next;
rv = KMF_OK;
} else if (rv == KMF_OK) {
/*
* valid - remove it from list
*/
pk11_delete_obj_from_list(
&newlist, &prev, &node);
} else {
goto cleanup1;
}
}
i++;
kmf_free_kmf_cert(handle, &tmp_kmf_cert);
}
*numobj = num_ok_certs;
*objlist = newlist;
}
}
cleanup1:
if (rv != KMF_OK && newlist != NULL) {
free_objlist(newlist);
*numobj = 0;
*objlist = NULL;
}
if (issuer != NULL)
kmf_free_dn(&issuerDN);
if (subject != NULL)
kmf_free_dn(&subjectDN);
return (rv);
}
/*
* The caller may pass a NULL value for kmf_cert below and the function will
* just return the number of certs found (in num_certs).
*/
KMF_RETURN
KMFPK11_FindCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN rv = 0;
uint32_t want_certs;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
OBJLIST *objlist = NULL;
uint32_t *num_certs;
KMF_X509_DER_CERT *kmf_cert = NULL;
char *certlabel = NULL;
char *issuer = NULL;
char *subject = NULL;
KMF_BIGINT *serial = NULL;
KMF_CERT_VALIDITY validity;
KMF_CREDENTIAL *cred = NULL;
boolean_t private;
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
num_certs = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr);
if (num_certs == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (*num_certs > 0)
want_certs = *num_certs;
else
want_certs = MAXINT; /* count them all */
*num_certs = 0;
/* Get the optional returned certificate list */
kmf_cert = kmf_get_attr_ptr(KMF_X509_DER_CERT_ATTR, attrlist,
numattr);
/* Get optional search criteria attributes */
certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
issuer = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr);
subject = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr);
serial = kmf_get_attr_ptr(KMF_BIGINT_ATTR, attrlist, numattr);
rv = kmf_get_attr(KMF_CERT_VALIDITY_ATTR, attrlist, numattr,
&validity, NULL);
if (rv != KMF_OK) {
validity = KMF_ALL_CERTS;
rv = KMF_OK;
}
rv = kmf_get_attr(KMF_PRIVATE_BOOL_ATTR, attrlist, numattr,
(void *)&private, NULL);
if (rv != KMF_OK) {
private = B_FALSE;
rv = KMF_OK;
}
cred = kmf_get_attr_ptr(KMF_CREDENTIAL_ATTR, attrlist, numattr);
if (cred != NULL) {
rv = pk11_authenticate(handle, cred);
if (rv != KMF_OK)
return (rv);
}
/* Start searching */
rv = search_certs(handle, certlabel, issuer, subject, serial, private,
validity, &objlist, num_certs);
if (rv == KMF_OK && objlist != NULL && kmf_cert != NULL) {
OBJLIST *node = objlist;
int i = 0;
while (node != NULL && i < want_certs) {
rv = PK11Cert2KMFCert(kmfh, node->handle,
&kmf_cert[i]);
i++;
node = node->next;
}
}
if (objlist != NULL)
free_objlist(objlist);
if (*num_certs == 0)
rv = KMF_ERR_CERT_NOT_FOUND;
return (rv);
}
/*ARGSUSED*/
void
KMFPK11_FreeKMFCert(KMF_HANDLE_T handle, KMF_X509_DER_CERT *kmf_cert)
{
if (kmf_cert != NULL && kmf_cert->certificate.Data != NULL) {
free(kmf_cert->certificate.Data);
kmf_cert->certificate.Data = NULL;
kmf_cert->certificate.Length = 0;
if (kmf_cert->kmf_private.label != NULL) {
free(kmf_cert->kmf_private.label);
kmf_cert->kmf_private.label = NULL;
}
}
}
KMF_RETURN
KMFPK11_EncodePubKeyData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *pKey,
KMF_DATA *eData)
{
KMF_RETURN ret = KMF_OK;
CK_RV rv;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY;
CK_KEY_TYPE ckKeyType;
KMF_DATA Modulus, Exponent, Prime, Subprime, Base, Value;
KMF_OID *Algorithm;
BerElement *asn1 = NULL;
BerValue *PubKeyParams = NULL, *EncodedKey = NULL;
KMF_X509_SPKI spki;
CK_BYTE ec_params[256], ec_point[256];
CK_ATTRIBUTE rsaTemplate[4];
CK_ATTRIBUTE dsaTemplate[6];
CK_ATTRIBUTE ecdsaTemplate[6];
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
if (pKey == NULL || pKey->keyp == CK_INVALID_HANDLE)
return (KMF_ERR_BAD_PARAMETER);
(void) memset(&Modulus, 0, sizeof (Modulus));
(void) memset(&Exponent, 0, sizeof (Exponent));
(void) memset(&Prime, 0, sizeof (Prime));
(void) memset(&Subprime, 0, sizeof (Subprime));
(void) memset(&Base, 0, sizeof (Base));
(void) memset(&Value, 0, sizeof (Value));
switch (pKey->keyalg) {
case KMF_RSA:
SETATTR(rsaTemplate, 0, CKA_CLASS, &ckObjClass,
sizeof (ckObjClass));
SETATTR(rsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType,
sizeof (ckKeyType));
SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data,
Modulus.Length);
SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT,
Exponent.Data, Exponent.Length);
/* Get the length of the fields */
rv = C_GetAttributeValue(kmfh->pk11handle,
(CK_OBJECT_HANDLE)pKey->keyp, rsaTemplate, 4);
if (rv != CKR_OK) {
SET_ERROR(kmfh, rv);
return (KMF_ERR_BAD_PARAMETER);
}
Modulus.Length = rsaTemplate[2].ulValueLen;
Modulus.Data = malloc(Modulus.Length);
if (Modulus.Data == NULL)
return (KMF_ERR_MEMORY);
Exponent.Length = rsaTemplate[3].ulValueLen;
Exponent.Data = malloc(Exponent.Length);
if (Exponent.Data == NULL) {
free(Modulus.Data);
return (KMF_ERR_MEMORY);
}
SETATTR(rsaTemplate, 2, CKA_MODULUS, Modulus.Data,
Modulus.Length);
SETATTR(rsaTemplate, 3, CKA_PUBLIC_EXPONENT,
Exponent.Data, Exponent.Length);
/* Now get the values */
rv = C_GetAttributeValue(kmfh->pk11handle,
(CK_OBJECT_HANDLE)pKey->keyp, rsaTemplate, 4);
if (rv != CKR_OK) {
SET_ERROR(kmfh, rv);
free(Modulus.Data);
free(Exponent.Data);
return (KMF_ERR_BAD_PARAMETER);
}
/*
* This is the KEY algorithm, not the
* signature algorithm.
*/
Algorithm = x509_algid_to_algoid(KMF_ALGID_RSA);
if (Algorithm != NULL) {
/* Encode the RSA Key Data */
if ((asn1 = kmfder_alloc()) == NULL) {
free(Modulus.Data);
free(Exponent.Data);
return (KMF_ERR_MEMORY);
}
if (kmfber_printf(asn1, "{II}", Modulus.Data,
Modulus.Length, Exponent.Data,
Exponent.Length) == -1) {
kmfber_free(asn1, 1);
free(Modulus.Data);
free(Exponent.Data);
return (KMF_ERR_ENCODING);
}
if (kmfber_flatten(asn1, &EncodedKey) == -1) {
kmfber_free(asn1, 1);
free(Modulus.Data);
free(Exponent.Data);
return (KMF_ERR_ENCODING);
}
kmfber_free(asn1, 1);
}
free(Exponent.Data);
free(Modulus.Data);
break;
case KMF_DSA:
SETATTR(dsaTemplate, 0, CKA_CLASS, &ckObjClass,
sizeof (ckObjClass));
SETATTR(dsaTemplate, 1, CKA_KEY_TYPE, &ckKeyType,
sizeof (ckKeyType));
SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data,
Prime.Length);
SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data,
Subprime.Length);
SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data,
Base.Length);
SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data,
Value.Length);
/* Get the length of the fields */
rv = C_GetAttributeValue(kmfh->pk11handle,
(CK_OBJECT_HANDLE)pKey->keyp, dsaTemplate, 6);
if (rv != CKR_OK) {
SET_ERROR(kmfh, rv);
return (KMF_ERR_BAD_PARAMETER);
}
Prime.Length = dsaTemplate[2].ulValueLen;
Prime.Data = malloc(Prime.Length);
if (Prime.Data == NULL) {
return (KMF_ERR_MEMORY);
}
Subprime.Length = dsaTemplate[3].ulValueLen;
Subprime.Data = malloc(Subprime.Length);
if (Subprime.Data == NULL) {
free(Prime.Data);
return (KMF_ERR_MEMORY);
}
Base.Length = dsaTemplate[4].ulValueLen;
Base.Data = malloc(Base.Length);
if (Base.Data == NULL) {
free(Prime.Data);
free(Subprime.Data);
return (KMF_ERR_MEMORY);
}
Value.Length = dsaTemplate[5].ulValueLen;
Value.Data = malloc(Value.Length);
if (Value.Data == NULL) {
free(Prime.Data);
free(Subprime.Data);
free(Base.Data);
return (KMF_ERR_MEMORY);
}
SETATTR(dsaTemplate, 2, CKA_PRIME, Prime.Data,
Prime.Length);
SETATTR(dsaTemplate, 3, CKA_SUBPRIME, Subprime.Data,
Subprime.Length);
SETATTR(dsaTemplate, 4, CKA_BASE, Base.Data,
Base.Length);
SETATTR(dsaTemplate, 5, CKA_VALUE, Value.Data,
Value.Length);
/* Now get the values */
rv = C_GetAttributeValue(kmfh->pk11handle,
(CK_OBJECT_HANDLE)pKey->keyp, dsaTemplate, 6);
if (rv != CKR_OK) {
free(Prime.Data);
free(Subprime.Data);
free(Base.Data);
free(Value.Data);
SET_ERROR(kmfh, rv);
return (KMF_ERR_BAD_PARAMETER);
}
/*
* This is the KEY algorithm, not the
* signature algorithm.
*/
Algorithm = x509_algid_to_algoid(KMF_ALGID_DSA);
/* Encode the DSA Algorithm Parameters */
if ((asn1 = kmfder_alloc()) == NULL) {
free(Prime.Data);
free(Subprime.Data);
free(Base.Data);
free(Value.Data);
return (KMF_ERR_MEMORY);
}
if (kmfber_printf(asn1, "{III}", Prime.Data,
Prime.Length, Subprime.Data, Subprime.Length,
Base.Data, Base.Length) == -1) {
kmfber_free(asn1, 1);
free(Prime.Data);
free(Subprime.Data);
free(Base.Data);
free(Value.Data);
return (KMF_ERR_ENCODING);
}
if (kmfber_flatten(asn1, &PubKeyParams) == -1) {
kmfber_free(asn1, 1);
free(Prime.Data);
free(Subprime.Data);
free(Base.Data);
free(Value.Data);
return (KMF_ERR_ENCODING);
}
kmfber_free(asn1, 1);
free(Prime.Data);
free(Subprime.Data);
free(Base.Data);
/* Encode the DSA Key Value */
if ((asn1 = kmfder_alloc()) == NULL) {
free(Value.Data);
return (KMF_ERR_MEMORY);
}
if (kmfber_printf(asn1, "I",
Value.Data, Value.Length) == -1) {
kmfber_free(asn1, 1);
free(Value.Data);
return (KMF_ERR_ENCODING);
}
if (kmfber_flatten(asn1, &EncodedKey) == -1) {
kmfber_free(asn1, 1);
free(Value.Data);
return (KMF_ERR_ENCODING);
}
kmfber_free(asn1, 1);
free(Value.Data);
break;
case KMF_ECDSA:
/* The EC_PARAMS are the PubKey algorithm parameters */
PubKeyParams = calloc(1, sizeof (BerValue));
if (PubKeyParams == NULL)
return (KMF_ERR_MEMORY);
EncodedKey = calloc(1, sizeof (BerValue));
if (EncodedKey == NULL) {
free(PubKeyParams);
return (KMF_ERR_MEMORY);
}
SETATTR(ecdsaTemplate, 0, CKA_EC_PARAMS,
&ec_params, sizeof (ec_params));
SETATTR(ecdsaTemplate, 1, CKA_EC_POINT,
&ec_point, sizeof (ec_point));
/* Get the length of the fields */
rv = C_GetAttributeValue(kmfh->pk11handle,
(CK_OBJECT_HANDLE)pKey->keyp,
ecdsaTemplate, 2);
if (rv != CKR_OK) {
SET_ERROR(kmfh, rv);
return (KMF_ERR_BAD_PARAMETER);
}
/* The params are to be used as algorithm parameters */
PubKeyParams->bv_val = (char *)ec_params;
PubKeyParams->bv_len = ecdsaTemplate[0].ulValueLen;
/*
* The EC_POINT is to be used as the subject pub key.
*/
EncodedKey->bv_val = (char *)ec_point;
EncodedKey->bv_len = ecdsaTemplate[1].ulValueLen;
/* Use the EC_PUBLIC_KEY OID */
Algorithm = (KMF_OID *)&KMFOID_EC_PUBLIC_KEY;
break;
default:
return (KMF_ERR_BAD_PARAMETER);
}
/* Now, build an SPKI structure for the final encoding step */
spki.algorithm.algorithm = *Algorithm;
if (PubKeyParams != NULL) {
spki.algorithm.parameters.Data =
(uchar_t *)PubKeyParams->bv_val;
spki.algorithm.parameters.Length = PubKeyParams->bv_len;
} else {
spki.algorithm.parameters.Data = NULL;
spki.algorithm.parameters.Length = 0;
}
if (EncodedKey != NULL) {
spki.subjectPublicKey.Data = (uchar_t *)EncodedKey->bv_val;
spki.subjectPublicKey.Length = EncodedKey->bv_len;
} else {
spki.subjectPublicKey.Data = NULL;
spki.subjectPublicKey.Length = 0;
}
/* Finally, encode the entire SPKI record */
ret = DerEncodeSPKI(&spki, eData);
cleanup:
if (EncodedKey) {
if (pKey->keyalg != KMF_ECDSA)
free(EncodedKey->bv_val);
free(EncodedKey);
}
if (PubKeyParams) {
if (pKey->keyalg != KMF_ECDSA)
free(PubKeyParams->bv_val);
free(PubKeyParams);
}
return (ret);
}
static KMF_RETURN
CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert)
{
KMF_RETURN rv = 0;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
KMF_X509_CERTIFICATE *signed_cert_ptr = NULL;
KMF_DATA data;
KMF_DATA Id;
CK_RV ckrv;
CK_ULONG subject_len, issuer_len, serno_len;
CK_BYTE *subject, *issuer, *serial, nullserno;
CK_BBOOL true = TRUE;
CK_CERTIFICATE_TYPE certtype = CKC_X_509;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE x509templ[11];
CK_OBJECT_HANDLE hCert = NULL;
int i;
if (kmfh == NULL)
return (KMF_ERR_INTERNAL); /* should not happen */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_INTERNAL); /* should not happen */
if (pcert == NULL || pcert->Data == NULL || pcert->Length == 0)
return (KMF_ERR_INTERNAL); /* should not happen */
/*
* The data *must* be a DER encoded X.509 certificate.
* Convert it to a CSSM cert and then parse the fields so
* the PKCS#11 attributes can be filled in correctly.
*/
rv = DerDecodeSignedCertificate((const KMF_DATA *)pcert,
&signed_cert_ptr);
if (rv != KMF_OK) {
return (KMF_ERR_ENCODING);
}
/*
* Encode fields into PKCS#11 attributes.
*/
/* Get the subject name */
rv = DerEncodeName(&signed_cert_ptr->certificate.subject, &data);
if (rv == KMF_OK) {
subject = data.Data;
subject_len = data.Length;
} else {
rv = KMF_ERR_ENCODING;
goto cleanup;
}
/* Encode the issuer */
rv = DerEncodeName(&signed_cert_ptr->certificate.issuer, &data);
if (rv == KMF_OK) {
issuer = data.Data;
issuer_len = data.Length;
} else {
rv = KMF_ERR_ENCODING;
goto cleanup;
}
/* Encode serial number */
if (signed_cert_ptr->certificate.serialNumber.len > 0 &&
signed_cert_ptr->certificate.serialNumber.val != NULL) {
serial = signed_cert_ptr->certificate.serialNumber.val;
serno_len = signed_cert_ptr->certificate.serialNumber.len;
} else {
/*
* RFC3280 says to gracefully handle certs with serial numbers
* of 0.
*/
nullserno = '\0';
serial = &nullserno;
serno_len = 1;
}
/* Generate an ID from the SPKI data */
rv = GetIDFromSPKI(&signed_cert_ptr->certificate.subjectPublicKeyInfo,
&Id);
if (rv != KMF_OK) {
goto cleanup;
}
i = 0;
SETATTR(x509templ, i, CKA_CLASS, &certClass, sizeof (certClass)); i++;
SETATTR(x509templ, i, CKA_CERTIFICATE_TYPE, &certtype,
sizeof (certtype));
i++;
SETATTR(x509templ, i, CKA_TOKEN, &true, sizeof (true)); i++;
SETATTR(x509templ, i, CKA_SUBJECT, subject, subject_len); i++;
SETATTR(x509templ, i, CKA_ISSUER, issuer, issuer_len); i++;
SETATTR(x509templ, i, CKA_SERIAL_NUMBER, serial, serno_len); i++;
SETATTR(x509templ, i, CKA_VALUE, pcert->Data, pcert->Length); i++;
SETATTR(x509templ, i, CKA_ID, Id.Data, Id.Length); i++;
if (label != NULL && strlen(label)) {
SETATTR(x509templ, i, CKA_LABEL, label, strlen(label)); i++;
}
/*
* The cert object handle is actually "leaked" here. If the app
* really wants to clean up the data space, it will have to call
* KMF_DeleteCert and specify the softtoken keystore.
*/
ckrv = C_CreateObject(kmfh->pk11handle, x509templ, i, &hCert);
if (ckrv != CKR_OK) {
/* Report authentication failures to the caller */
if (ckrv == CKR_USER_NOT_LOGGED_IN ||
ckrv == CKR_PIN_INCORRECT ||
ckrv == CKR_PIN_INVALID ||
ckrv == CKR_PIN_EXPIRED ||
ckrv == CKR_PIN_LOCKED ||
ckrv == CKR_SESSION_READ_ONLY)
rv = KMF_ERR_AUTH_FAILED;
else
rv = KMF_ERR_INTERNAL;
SET_ERROR(kmfh, ckrv);
}
free(subject);
free(issuer);
cleanup:
if (Id.Data != NULL)
free(Id.Data);
if (signed_cert_ptr) {
kmf_free_signed_cert(signed_cert_ptr);
free(signed_cert_ptr);
}
return (rv);
}
KMF_RETURN
KMFPK11_StoreCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN rv = 0;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
KMF_DATA *cert = NULL;
KMF_CREDENTIAL *cred = NULL;
char *label = NULL;
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED);
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
if (cert == NULL || cert->Data == NULL || cert->Length == 0)
return (KMF_ERR_BAD_PARAMETER);
/* label attribute is optional */
label = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
cred = kmf_get_attr_ptr(KMF_CREDENTIAL_ATTR, attrlist, numattr);
if (cred != NULL) {
rv = pk11_authenticate(handle, cred);
if (rv != KMF_OK)
return (rv);
}
rv = CreateCertObject(handle, label, cert);
return (rv);
}
KMF_RETURN
KMFPK11_ImportCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN rv = 0;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
char *certfile = NULL;
char *label = NULL;
KMF_ENCODE_FORMAT format;
KMF_CREDENTIAL *cred = NULL;
KMF_DATA cert1 = { 0, NULL };
KMF_DATA cert2 = { 0, NULL };
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED);
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
/*
* Get the input cert filename attribute, check if it is a valid
* certificate and auto-detect the file format of it.
*/
certfile = kmf_get_attr_ptr(KMF_CERT_FILENAME_ATTR, attrlist, numattr);
if (certfile == NULL)
return (KMF_ERR_BAD_PARAMETER);
rv = kmf_is_cert_file(handle, certfile, &format);
if (rv != KMF_OK)
return (rv);
/* Read in the CERT file */
rv = kmf_read_input_file(handle, certfile, &cert1);
if (rv != KMF_OK) {
return (rv);
}
/* The label attribute is optional */
label = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
/*
* If the input certificate is in PEM format, we need to convert
* it to DER first.
*/
if (format == KMF_FORMAT_PEM) {
int derlen;
rv = kmf_pem_to_der(cert1.Data, cert1.Length,
&cert2.Data, &derlen);
if (rv != KMF_OK) {
goto out;
}
cert2.Length = (size_t)derlen;
}
cred = kmf_get_attr_ptr(KMF_CREDENTIAL_ATTR, attrlist, numattr);
if (cred != NULL) {
rv = pk11_authenticate(handle, cred);
if (rv != KMF_OK)
return (rv);
}
rv = CreateCertObject(handle, label,
format == KMF_FORMAT_ASN1 ? &cert1 : &cert2);
out:
if (cert1.Data != NULL) {
free(cert1.Data);
}
if (cert2.Data != NULL) {
free(cert2.Data);
}
return (rv);
}
KMF_RETURN
KMFPK11_DeleteCert(KMF_HANDLE_T handle, int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_RETURN rv = 0;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
OBJLIST *objlist;
uint32_t numObjects = 0;
char *certlabel = NULL;
char *issuer = NULL;
char *subject = NULL;
KMF_BIGINT *serial = NULL;
KMF_CERT_VALIDITY validity;
boolean_t private;
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
/* Get the search criteria attributes. They are all optional. */
certlabel = kmf_get_attr_ptr(KMF_CERT_LABEL_ATTR, attrlist, numattr);
issuer = kmf_get_attr_ptr(KMF_ISSUER_NAME_ATTR, attrlist, numattr);
subject = kmf_get_attr_ptr(KMF_SUBJECT_NAME_ATTR, attrlist, numattr);
serial = kmf_get_attr_ptr(KMF_BIGINT_ATTR, attrlist, numattr);
rv = kmf_get_attr(KMF_CERT_VALIDITY_ATTR, attrlist, numattr,
&validity, NULL);
if (rv != KMF_OK) {
validity = KMF_ALL_CERTS;
rv = KMF_OK;
}
rv = kmf_get_attr(KMF_PRIVATE_BOOL_ATTR, attrlist, numattr,
(void *)&private, NULL);
if (rv != KMF_OK) {
private = B_FALSE;
rv = KMF_OK;
}
/*
* Start searching for certificates that match the criteria and
* delete them.
*/
objlist = NULL;
rv = search_certs(handle, certlabel, issuer, subject, serial,
private, validity, &objlist, &numObjects);
if (rv == KMF_OK && objlist != NULL) {
OBJLIST *node = objlist;
while (node != NULL) {
CK_RV ckrv;
ckrv = C_DestroyObject(kmfh->pk11handle, node->handle);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
break;
}
node = node->next;
}
free_objlist(objlist);
}
if (rv == KMF_OK && numObjects == 0)
rv = KMF_ERR_CERT_NOT_FOUND;
out:
return (rv);
}
static CK_RV
gendsa_keypair(KMF_HANDLE *kmfh, boolean_t storekey,
CK_OBJECT_HANDLE *pubKey,
CK_OBJECT_HANDLE *priKey)
{
CK_RV ckrv = CKR_OK;
CK_SESSION_HANDLE hSession = kmfh->pk11handle;
static CK_ULONG dsaKeyType = CKK_DSA;
static CK_BBOOL true = TRUE;
static CK_BBOOL false = FALSE;
static CK_OBJECT_CLASS priClass = CKO_PRIVATE_KEY;
static CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
static CK_BYTE ckDsaPrime[128] = {
0xb2, 0x6b, 0xc3, 0xfb, 0xe3, 0x26, 0xf4, 0xc2,
0xcf, 0xdd, 0xf9, 0xae, 0x3e, 0x39, 0x7f, 0x9c,
0xa7, 0x73, 0xc3, 0x00, 0xa3, 0x50, 0x67, 0xc3,
0xab, 0x49, 0x2c, 0xea, 0x59, 0x10, 0xa4, 0xbc,
0x09, 0x94, 0xa9, 0x05, 0x3b, 0x0d, 0x35, 0x3c,
0x55, 0x52, 0x47, 0xf0, 0xe3, 0x72, 0x5b, 0xe8,
0x72, 0xa0, 0x71, 0x1c, 0x23, 0x4f, 0x6d, 0xe8,
0xac, 0xe5, 0x21, 0x1b, 0xc0, 0xd8, 0x42, 0xd3,
0x87, 0xae, 0x83, 0x5e, 0x52, 0x7e, 0x46, 0x09,
0xb5, 0xc7, 0x3d, 0xd6, 0x00, 0xf5, 0xf2, 0x9c,
0x84, 0x30, 0x81, 0x7e, 0x7b, 0x30, 0x5b, 0xd5,
0xab, 0xd0, 0x2f, 0x21, 0xb3, 0xd8, 0xed, 0xdb,
0x97, 0x77, 0xe4, 0x7e, 0x6c, 0xcc, 0xb9, 0x6b,
0xdd, 0xaa, 0x96, 0x04, 0xe7, 0xd4, 0x55, 0x11,
0x53, 0xab, 0xba, 0x95, 0x9a, 0xa2, 0x8c, 0x27,
0xd9, 0xcf, 0xad, 0xf3, 0xcf, 0x3a, 0x0c, 0x4b};
static CK_BYTE ckDsaSubPrime[20] = {
0xa4, 0x5f, 0x2a, 0x27, 0x09, 0x49, 0xb6, 0xfe,
0x73, 0xeb, 0x95, 0x7d, 0x00, 0xf3, 0x42, 0xfc,
0x78, 0x47, 0xb0, 0xd5};
static CK_BYTE ckDsaBase[128] = {
0x5c, 0x57, 0x16, 0x49, 0xef, 0xc8, 0xfb, 0x4b,
0xee, 0x07, 0x45, 0x3b, 0x6a, 0x1d, 0xf3, 0xe5,
0xeb, 0xee, 0xad, 0x11, 0x13, 0xe3, 0x52, 0xe3,
0x0d, 0xc0, 0x21, 0x25, 0xfa, 0xf0, 0x93, 0x1c,
0x53, 0x4d, 0xdc, 0x0d, 0x76, 0xd2, 0xfe, 0xc2,
0xd7, 0x72, 0x64, 0x69, 0x53, 0x3d, 0x33, 0xbd,
0xe1, 0x34, 0xf2, 0x5a, 0x67, 0x83, 0xe0, 0xd3,
0x1c, 0xd6, 0x41, 0x4d, 0x16, 0xe8, 0x6c, 0x5a,
0x07, 0x95, 0x21, 0x9a, 0xa3, 0xc4, 0xb9, 0x05,
0x9d, 0x11, 0xcb, 0xc8, 0xc4, 0x9d, 0x00, 0x1a,
0xf4, 0x85, 0x2a, 0xa9, 0x20, 0x3c, 0xba, 0x67,
0xe5, 0xed, 0x31, 0xb2, 0x11, 0xfb, 0x1f, 0x73,
0xec, 0x61, 0x29, 0xad, 0xc7, 0x68, 0xb2, 0x3f,
0x38, 0xea, 0xd9, 0x87, 0x83, 0x9e, 0x7e, 0x19,
0x18, 0xdd, 0xc2, 0xc3, 0x5b, 0x16, 0x6d, 0xce,
0xcf, 0x88, 0x91, 0x07, 0xe0, 0x2b, 0xa8, 0x54 };
static CK_ATTRIBUTE ckDsaPubKeyTemplate[] = {
{ CKA_CLASS, &pubClass, sizeof (pubClass) },
{ CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType) },
{ CKA_TOKEN, &true, sizeof (true)},
{ CKA_PRIVATE, &false, sizeof (false)},
{ CKA_PRIME, &ckDsaPrime, sizeof (ckDsaPrime) },
{ CKA_SUBPRIME, &ckDsaSubPrime, sizeof (ckDsaSubPrime)},
{ CKA_BASE, &ckDsaBase, sizeof (ckDsaBase) },
{ CKA_VERIFY, &true, sizeof (true) },
};
#define NUMBER_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \
sizeof (CK_ATTRIBUTE))
#define MAX_DSA_PUB_TEMPLATES (sizeof (ckDsaPubKeyTemplate) / \
sizeof (CK_ATTRIBUTE))
static CK_ATTRIBUTE ckDsaPriKeyTemplate[] = {
{CKA_CLASS, &priClass, sizeof (priClass)},
{CKA_KEY_TYPE, &dsaKeyType, sizeof (dsaKeyType)},
{CKA_TOKEN, &true, sizeof (true)},
{CKA_PRIVATE, &true, sizeof (true)},
{CKA_SIGN, &true, sizeof (true)},
};
#define NUMBER_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \
sizeof (CK_ATTRIBUTE))
#define MAX_DSA_PRI_TEMPLATES (sizeof (ckDsaPriKeyTemplate) / \
sizeof (CK_ATTRIBUTE))
CK_MECHANISM keyGenMech = {CKM_DSA_KEY_PAIR_GEN, NULL, 0};
SETATTR(ckDsaPriKeyTemplate, 2, CKA_TOKEN,
(storekey ? &true : &false), sizeof (CK_BBOOL));
ckrv = C_GenerateKeyPair(hSession, &keyGenMech,
ckDsaPubKeyTemplate,
(sizeof (ckDsaPubKeyTemplate)/sizeof (CK_ATTRIBUTE)),
ckDsaPriKeyTemplate,
(sizeof (ckDsaPriKeyTemplate)/sizeof (CK_ATTRIBUTE)),
pubKey, priKey);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_KEYGEN_FAILED);
}
return (ckrv);
}
static CK_RV
genrsa_keypair(KMF_HANDLE *kmfh, CK_ULONG modulusBits,
boolean_t storekey, KMF_BIGINT *rsaexp,
CK_OBJECT_HANDLE *pubKey,
CK_OBJECT_HANDLE *priKey)
{
CK_RV ckrv = CKR_OK;
CK_SESSION_HANDLE hSession = kmfh->pk11handle;
CK_ATTRIBUTE rsaPubKeyTemplate[16];
CK_ATTRIBUTE rsaPriKeyTemplate[16];
CK_MECHANISM keyGenMech = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0};
int numpubattr = 0, numpriattr = 0;
static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01};
static CK_BBOOL true = TRUE;
static CK_BBOOL false = FALSE;
SETATTR(rsaPubKeyTemplate, numpubattr, CKA_TOKEN,
(storekey ? &true : &false), sizeof (CK_BBOOL));
numpubattr++;
SETATTR(rsaPubKeyTemplate, numpubattr, CKA_MODULUS_BITS,
&modulusBits, sizeof (modulusBits));
numpubattr++;
if (rsaexp != NULL && (rsaexp->len > 0 && rsaexp->val != NULL)) {
SETATTR(rsaPubKeyTemplate, numpubattr,
CKA_PUBLIC_EXPONENT,
rsaexp->val, rsaexp->len);
numpubattr++;
} else {
SETATTR(rsaPubKeyTemplate, numpubattr,
CKA_PUBLIC_EXPONENT, &PubExpo, sizeof (PubExpo));
numpubattr++;
}
SETATTR(rsaPubKeyTemplate, numpubattr, CKA_ENCRYPT,
&true, sizeof (true));
numpubattr++;
SETATTR(rsaPubKeyTemplate, numpubattr, CKA_VERIFY,
&true, sizeof (true));
numpubattr++;
SETATTR(rsaPubKeyTemplate, numpubattr, CKA_WRAP,
&true, sizeof (true));
numpubattr++;
SETATTR(rsaPriKeyTemplate, numpriattr, CKA_TOKEN,
(storekey ? &true : &false), sizeof (CK_BBOOL));
numpriattr++;
SETATTR(rsaPriKeyTemplate, numpriattr, CKA_PRIVATE, &true,
sizeof (true));
numpriattr++;
SETATTR(rsaPriKeyTemplate, numpriattr, CKA_DECRYPT, &true,
sizeof (true));
numpriattr++;
SETATTR(rsaPriKeyTemplate, numpriattr, CKA_SIGN, &true,
sizeof (true));
numpriattr++;
SETATTR(rsaPriKeyTemplate, numpriattr, CKA_UNWRAP, &true,
sizeof (true));
numpriattr++;
ckrv = C_GenerateKeyPair(hSession, &keyGenMech,
rsaPubKeyTemplate, numpubattr,
rsaPriKeyTemplate, numpriattr,
pubKey, priKey);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (ckrv);
}
return (ckrv);
}
static CK_RV
genecc_keypair(KMF_HANDLE *kmfh,
boolean_t ontoken,
KMF_OID *curveoid,
CK_OBJECT_HANDLE *pubKey,
CK_OBJECT_HANDLE *priKey)
{
CK_RV ckrv;
CK_SESSION_HANDLE hSession = kmfh->pk11handle;
CK_MECHANISM keyGenMech = {CKM_EC_KEY_PAIR_GEN, NULL, 0};
const ulong_t publicKey = CKO_PUBLIC_KEY;
const ulong_t privateKey = CKO_PRIVATE_KEY;
const ulong_t keytype = CKK_EC;
static CK_BBOOL true = TRUE;
static CK_BBOOL false = FALSE;
CK_ATTRIBUTE public_template[6];
CK_ATTRIBUTE private_template[6];
int numpubattr, numpriattr;
numpubattr = 0;
SETATTR(public_template, numpubattr, CKA_CLASS,
&publicKey, sizeof (publicKey));
numpubattr++;
SETATTR(public_template, numpubattr, CKA_KEY_TYPE,
&keytype, sizeof (keytype));
numpubattr++;
SETATTR(public_template, numpubattr, CKA_EC_PARAMS,
curveoid->Data, curveoid->Length);
numpubattr++;
SETATTR(public_template, numpubattr, CKA_TOKEN,
ontoken ? &true : &false, sizeof (true));
numpubattr++;
SETATTR(public_template, numpubattr, CKA_VERIFY,
&true, sizeof (true));
numpubattr++;
SETATTR(public_template, numpubattr, CKA_PRIVATE,
&false, sizeof (false));
numpubattr++;
numpriattr = 0;
SETATTR(private_template, numpriattr, CKA_CLASS,
&privateKey, sizeof (privateKey));
numpriattr++;
SETATTR(private_template, numpriattr, CKA_KEY_TYPE,
&keytype, sizeof (keytype));
numpriattr++;
SETATTR(private_template, numpriattr, CKA_TOKEN,
ontoken ? &true : &false, sizeof (true));
numpriattr++;
SETATTR(private_template, numpriattr, CKA_PRIVATE,
&true, sizeof (true));
numpriattr++;
SETATTR(private_template, numpriattr, CKA_SIGN,
&true, sizeof (true));
numpriattr++;
SETATTR(private_template, numpriattr, CKA_DERIVE,
&true, sizeof (true));
numpriattr++;
ckrv = C_GenerateKeyPair(hSession, &keyGenMech,
public_template, numpubattr,
private_template, numpriattr,
pubKey, priKey);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (ckrv);
}
return (ckrv);
}
KMF_RETURN
KMFPK11_CreateKeypair(KMF_HANDLE_T handle,
int numattr,
KMF_ATTRIBUTE *attlist)
{
KMF_RETURN rv = KMF_OK;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
KMF_DATA IDInput, IDOutput;
KMF_CREDENTIAL *cred;
KMF_KEY_ALG keytype = KMF_RSA;
KMF_KEY_HANDLE *pubkey, *privkey;
CK_RV ckrv = 0;
CK_SESSION_HANDLE hSession = kmfh->pk11handle;
CK_ATTRIBUTE labelattr[1];
CK_ATTRIBUTE idattr[1];
CK_OBJECT_HANDLE pubKey, priKey;
char IDHashData[SHA1_HASH_LENGTH];
static CK_ULONG modulusBits = 1024;
uint32_t modulusBits_size = sizeof (CK_ULONG);
SHA1_CTX ctx;
boolean_t storekey = TRUE;
char *keylabel = NULL;
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
/* "storekey" is optional. Default is TRUE */
(void) kmf_get_attr(KMF_STOREKEY_BOOL_ATTR, attlist, numattr,
&storekey, NULL);
cred = kmf_get_attr_ptr(KMF_CREDENTIAL_ATTR, attlist, numattr);
if (cred == NULL)
return (KMF_ERR_BAD_PARAMETER);
rv = pk11_authenticate(handle, cred);
if (rv != KMF_OK)
return (rv);
/* keytype is optional. KMF_RSA is default */
(void) kmf_get_attr(KMF_KEYALG_ATTR, attlist, numattr,
(void *)&keytype, NULL);
pubkey = kmf_get_attr_ptr(KMF_PUBKEY_HANDLE_ATTR, attlist, numattr);
if (pubkey == NULL)
return (KMF_ERR_BAD_PARAMETER);
privkey = kmf_get_attr_ptr(KMF_PRIVKEY_HANDLE_ATTR, attlist, numattr);
if (privkey == NULL)
return (KMF_ERR_BAD_PARAMETER);
(void) memset(pubkey, 0, sizeof (KMF_KEY_HANDLE));
(void) memset(privkey, 0, sizeof (KMF_KEY_HANDLE));
if (keytype == KMF_RSA) {
CK_BYTE *modulus = NULL;
CK_ULONG modulusLength = 0;
KMF_BIGINT *rsaexp = NULL;
CK_ATTRIBUTE modattr[1];
rv = kmf_get_attr(KMF_KEYLENGTH_ATTR, attlist, numattr,
&modulusBits, &modulusBits_size);
if (rv == KMF_ERR_ATTR_NOT_FOUND)
/* Default modulusBits = 1024 */
rv = KMF_OK;
if (rv != KMF_OK)
return (KMF_ERR_BAD_PARAMETER);
rsaexp = kmf_get_attr_ptr(KMF_RSAEXP_ATTR, attlist, numattr);
/* Generate the RSA keypair */
ckrv = genrsa_keypair(kmfh, modulusBits, storekey,
rsaexp, &pubKey, &priKey);
if (ckrv != CKR_OK)
return (KMF_ERR_BAD_PARAMETER);
privkey->kstype = KMF_KEYSTORE_PK11TOKEN;
privkey->keyalg = KMF_RSA;
privkey->keyclass = KMF_ASYM_PRI;
privkey->keyp = (void *)priKey;
pubkey->kstype = KMF_KEYSTORE_PK11TOKEN;
pubkey->keyalg = KMF_RSA;
pubkey->keyclass = KMF_ASYM_PUB;
pubkey->keyp = (void *)pubKey;
SETATTR(modattr, 0, CKA_MODULUS, NULL, modulusLength);
/* Get the Modulus field to use as input for creating the ID */
ckrv = C_GetAttributeValue(kmfh->pk11handle,
(CK_OBJECT_HANDLE)pubKey, modattr, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_BAD_PARAMETER);
}
modulusLength = modattr[0].ulValueLen;
modulus = malloc(modulusLength);
if (modulus == NULL)
return (KMF_ERR_MEMORY);
modattr[0].pValue = modulus;
ckrv = C_GetAttributeValue(kmfh->pk11handle,
(CK_OBJECT_HANDLE)pubKey, modattr, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
free(modulus);
return (KMF_ERR_BAD_PARAMETER);
}
IDInput.Data = modulus;
IDInput.Length = modulusLength;
} else if (keytype == KMF_DSA) {
CK_BYTE *keyvalue;
CK_ULONG valueLen;
CK_ATTRIBUTE valattr[1];
/* Generate the DSA keypair */
ckrv = gendsa_keypair(kmfh, storekey, &pubKey, &priKey);
if (ckrv != CKR_OK)
return (KMF_ERR_BAD_PARAMETER);
privkey->kstype = KMF_KEYSTORE_PK11TOKEN;
privkey->keyalg = KMF_DSA;
privkey->keyclass = KMF_ASYM_PRI;
privkey->keyp = (void *)priKey;
pubkey->kstype = KMF_KEYSTORE_PK11TOKEN;
pubkey->keyalg = KMF_DSA;
pubkey->keyclass = KMF_ASYM_PUB;
pubkey->keyp = (void *)pubKey;
/* Get the Public Value to use as input for creating the ID */
SETATTR(valattr, 0, CKA_VALUE, NULL, &valueLen);
ckrv = C_GetAttributeValue(hSession,
(CK_OBJECT_HANDLE)pubKey, valattr, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_BAD_PARAMETER);
}
valueLen = valattr[0].ulValueLen;
keyvalue = malloc(valueLen);
if (keyvalue == NULL)
return (KMF_ERR_MEMORY);
valattr[0].pValue = keyvalue;
ckrv = C_GetAttributeValue(hSession,
(CK_OBJECT_HANDLE)pubKey, valattr, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
free(keyvalue);
return (KMF_ERR_BAD_PARAMETER);
}
IDInput.Data = keyvalue;
IDInput.Length = valueLen;
} else if (keytype == KMF_ECDSA) {
CK_BYTE *keyvalue;
CK_ULONG valueLen;
CK_ATTRIBUTE valattr[1];
KMF_OID *eccoid = kmf_get_attr_ptr(KMF_ECC_CURVE_OID_ATTR,
attlist, numattr);
if (eccoid == NULL)
return (KMF_ERR_BAD_PARAMETER);
ckrv = genecc_keypair(kmfh, storekey, eccoid,
&pubKey, &priKey);
if (ckrv != CKR_OK)
return (KMF_ERR_BAD_PARAMETER);
privkey->kstype = KMF_KEYSTORE_PK11TOKEN;
privkey->keyalg = KMF_ECDSA;
privkey->keyclass = KMF_ASYM_PRI;
privkey->keyp = (void *)priKey;
pubkey->kstype = KMF_KEYSTORE_PK11TOKEN;
pubkey->keyalg = KMF_ECDSA;
pubkey->keyclass = KMF_ASYM_PUB;
pubkey->keyp = (void *)pubKey;
/* Get the EC_POINT to use as input for creating the ID */
SETATTR(valattr, 0, CKA_EC_POINT, NULL, &valueLen);
ckrv = C_GetAttributeValue(hSession,
(CK_OBJECT_HANDLE)pubKey, valattr, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_BAD_PARAMETER);
}
valueLen = valattr[0].ulValueLen;
keyvalue = malloc(valueLen);
if (keyvalue == NULL)
return (KMF_ERR_MEMORY);
valattr[0].pValue = keyvalue;
ckrv = C_GetAttributeValue(hSession,
(CK_OBJECT_HANDLE)pubKey, valattr, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
free(keyvalue);
return (KMF_ERR_BAD_PARAMETER);
}
IDInput.Data = keyvalue;
IDInput.Length = valueLen;
} else {
return (KMF_ERR_BAD_PARAMETER);
}
keylabel = kmf_get_attr_ptr(KMF_KEYLABEL_ATTR, attlist, numattr);
if (keylabel != NULL && strlen(keylabel)) {
SETATTR(labelattr, 0, CKA_LABEL, keylabel, strlen(keylabel));
/* Set the CKA_LABEL if one was indicated */
if ((ckrv = C_SetAttributeValue(hSession, pubKey,
labelattr, 1)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto cleanup;
}
pubkey->keylabel = (char *)strdup(keylabel);
if (pubkey->keylabel == NULL) {
rv = KMF_ERR_MEMORY;
goto cleanup;
}
if ((ckrv = C_SetAttributeValue(hSession, priKey,
labelattr, 1)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto cleanup;
}
privkey->keylabel = (char *)strdup(keylabel);
if (privkey->keylabel == NULL) {
rv = KMF_ERR_MEMORY;
goto cleanup;
}
} else {
rv = KMF_OK;
}
/* Now, assign a CKA_ID value so it can be searched */
/* ID_Input was assigned above in the RSA or DSA keygen section */
IDOutput.Data = (uchar_t *)IDHashData;
IDOutput.Length = sizeof (IDHashData);
SHA1Init(&ctx);
SHA1Update(&ctx, IDInput.Data, IDInput.Length);
SHA1Final(IDOutput.Data, &ctx);
IDOutput.Length = SHA1_DIGEST_LENGTH;
free(IDInput.Data);
if (rv != CKR_OK) {
goto cleanup;
}
SETATTR(idattr, 0, CKA_ID, IDOutput.Data, IDOutput.Length);
if ((ckrv = C_SetAttributeValue(hSession, pubKey,
idattr, 1)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto cleanup;
}
if ((ckrv = C_SetAttributeValue(hSession, priKey,
idattr, 1)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto cleanup;
}
cleanup:
if (rv != KMF_OK) {
if (pubKey != CK_INVALID_HANDLE)
(void) C_DestroyObject(hSession, pubKey);
if (priKey != CK_INVALID_HANDLE)
(void) C_DestroyObject(hSession, priKey);
if (privkey->keylabel)
free(privkey->keylabel);
if (pubkey->keylabel)
free(pubkey->keylabel);
}
return (rv);
}
KMF_RETURN
KMFPK11_DeleteKey(KMF_HANDLE_T handle,
int numattr, KMF_ATTRIBUTE *attrlist)
{
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
CK_RV ckrv = CKR_OK;
KMF_RETURN rv = KMF_OK;
KMF_KEY_HANDLE *key;
KMF_CREDENTIAL cred;
boolean_t destroy = B_TRUE;
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
if (key == NULL || key->keyp == NULL)
return (KMF_ERR_BAD_PARAMETER);
if (key->keyclass != KMF_ASYM_PUB &&
key->keyclass != KMF_ASYM_PRI &&
key->keyclass != KMF_SYMMETRIC)
return (KMF_ERR_BAD_KEY_CLASS);
/* "destroy" is optional. Default is TRUE */
(void) kmf_get_attr(KMF_DESTROY_BOOL_ATTR, attrlist, numattr,
(void *)&destroy, NULL);
if (destroy) {
rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
(void *)&cred, NULL);
if (rv != KMF_OK)
return (KMF_ERR_BAD_PARAMETER);
rv = pk11_authenticate(handle, &cred);
if (rv != KMF_OK) {
return (rv);
}
}
if (!key->israw && destroy)
ckrv = C_DestroyObject(kmfh->pk11handle,
(CK_OBJECT_HANDLE)key->keyp);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
/* Report authentication failures to the caller */
if (ckrv == CKR_PIN_EXPIRED || ckrv == CKR_SESSION_READ_ONLY)
rv = KMF_ERR_AUTH_FAILED;
else
rv = KMF_ERR_INTERNAL;
}
return (rv);
}
KMF_RETURN
KMFPK11_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *keyp,
KMF_OID *algOID,
KMF_DATA *tobesigned,
KMF_DATA *output)
{
KMF_RETURN rv = KMF_OK;
CK_RV ckrv;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
CK_SESSION_HANDLE hSession = kmfh->pk11handle;
CK_MECHANISM mechanism;
CK_MECHANISM_TYPE mechtype, hashmech;
CK_KEY_TYPE keytype;
KMF_ALGORITHM_INDEX AlgId;
KMF_DATA hashData = { 0, NULL };
uchar_t digest[1024];
CK_ATTRIBUTE subprime = { CKA_SUBPRIME, NULL, 0 };
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
if (keyp == NULL || algOID == NULL ||
tobesigned == NULL || output == NULL)
return (KMF_ERR_BAD_PARAMETER);
/* These functions are available to the plugin from libkmf */
AlgId = x509_algoid_to_algid(algOID);
if (AlgId == KMF_ALGID_NONE)
return (KMF_ERR_BAD_PARAMETER);
/* Get the PKCS11 signing key type and mechtype */
if (get_pk11_data(AlgId, &keytype, &mechtype, &hashmech, 0))
return (KMF_ERR_BAD_PARAMETER);
(void) memset(digest, 0, sizeof (digest));
hashData.Data = digest;
hashData.Length = sizeof (digest);
rv = PKCS_DigestData(handle, hSession, hashmech, tobesigned, &hashData,
(mechtype == CKM_RSA_PKCS));
if (rv)
return (rv);
if (mechtype == CKM_DSA && hashmech == CKM_SHA256) {
/*
* FIPS 186-3 says that when signing with DSA
* the hash must be truncated to the size of the
* subprime.
*/
ckrv = C_GetAttributeValue(hSession,
(CK_OBJECT_HANDLE)keyp->keyp,
&subprime, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL);
}
hashData.Length = subprime.ulValueLen;
}
/* the mechtype from the 'get_pk11_info' refers to the signing */
mechanism.mechanism = mechtype;
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;
ckrv = C_SignInit(hSession, &mechanism, (CK_OBJECT_HANDLE)keyp->keyp);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL);
}
ckrv = C_Sign(hSession, hashData.Data, hashData.Length,
output->Data, (CK_ULONG *)&output->Length);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL);
}
return (KMF_OK);
}
KMF_RETURN
KMFPK11_GetErrorString(KMF_HANDLE_T handle, char **msgstr)
{
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
*msgstr = NULL;
if (kmfh->lasterr.errcode != 0) {
char *e = pkcs11_strerror(kmfh->lasterr.errcode);
if (e == NULL || (*msgstr = (char *)strdup(e)) == NULL) {
return (KMF_ERR_MEMORY);
}
}
return (KMF_OK);
}
static CK_RV
getObjectKeytype(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj,
CK_ULONG *keytype)
{
CK_RV rv = CKR_OK;
CK_ATTRIBUTE templ;
CK_ULONG len = sizeof (CK_ULONG);
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
templ.type = CKA_KEY_TYPE;
templ.pValue = keytype;
templ.ulValueLen = len;
rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1);
return (rv);
}
static CK_RV
getObjectLabel(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj,
char **outlabel)
{
CK_RV rv = CKR_OK;
CK_ATTRIBUTE templ;
char Label[BUFSIZ];
CK_ULONG len = sizeof (Label);
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
(void) memset(Label, 0, len);
templ.type = CKA_LABEL;
templ.pValue = Label;
templ.ulValueLen = len;
rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1);
if (rv == CKR_OK) {
*outlabel = (char *)strdup(Label);
} else {
*outlabel = NULL;
}
return (rv);
}
static CK_RV
getObjectKeyclass(KMF_HANDLE_T handle, CK_OBJECT_HANDLE obj,
KMF_KEY_CLASS *keyclass)
{
CK_RV rv = CKR_OK;
CK_ATTRIBUTE templ;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
CK_OBJECT_CLASS class;
templ.type = CKA_CLASS;
templ.pValue = &class;
templ.ulValueLen = sizeof (CK_OBJECT_CLASS);
rv = C_GetAttributeValue(kmfh->pk11handle, obj, &templ, 1);
if (rv == CKR_OK) {
if (class == CKO_PUBLIC_KEY) {
*keyclass = KMF_ASYM_PUB;
} else if (class == CKO_PRIVATE_KEY) {
*keyclass = KMF_ASYM_PRI;
} else if (class == CKO_SECRET_KEY) {
*keyclass = KMF_SYMMETRIC;
}
} else {
*keyclass = KMF_KEYCLASS_NONE;
}
return (rv);
}
KMF_RETURN
KMFPK11_FindPrikeyByCert(KMF_HANDLE_T handle, int numattr,
KMF_ATTRIBUTE *attrlist)
{
KMF_X509_SPKI *pubkey;
KMF_X509_CERTIFICATE *SignerCert = NULL;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
KMF_RETURN rv = KMF_OK;
CK_RV ckrv = CKR_OK;
CK_ATTRIBUTE templ[4];
CK_OBJECT_HANDLE pri_obj = CK_INVALID_HANDLE;
CK_ULONG obj_count;
CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
CK_BBOOL true = TRUE;
KMF_DATA Id = { 0, NULL };
KMF_KEY_HANDLE *key = NULL;
KMF_DATA *cert = NULL;
KMF_CREDENTIAL cred;
KMF_ENCODE_FORMAT format = KMF_FORMAT_UNDEF;
CK_ULONG keytype;
/* Get the key handle */
key = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
if (key == NULL)
return (KMF_ERR_BAD_PARAMETER);
/* Get the optional encoded format */
(void) kmf_get_attr(KMF_ENCODE_FORMAT_ATTR, attrlist, numattr,
(void *)&format, NULL);
/* Decode the signer cert so we can get the SPKI data */
cert = kmf_get_attr_ptr(KMF_CERT_DATA_ATTR, attrlist, numattr);
if (cert == NULL || cert->Data == NULL)
return (KMF_ERR_BAD_PARAMETER);
if ((rv = DerDecodeSignedCertificate(cert,
&SignerCert)) != KMF_OK)
return (rv);
/* Get the public key info from the signer certificate */
pubkey = &SignerCert->certificate.subjectPublicKeyInfo;
/* Generate an ID from the SPKI data */
rv = GetIDFromSPKI(pubkey, &Id);
if (rv != KMF_OK) {
goto errout;
}
/* Get the credential and login */
rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr,
(void *)&cred, NULL);
if (rv != KMF_OK)
return (KMF_ERR_BAD_PARAMETER);
rv = pk11_authenticate(handle, &cred);
if (rv != KMF_OK) {
return (rv);
}
/* Start searching */
SETATTR(templ, 0, CKA_CLASS, &objClass, sizeof (objClass));
SETATTR(templ, 1, CKA_TOKEN, &true, sizeof (true));
SETATTR(templ, 2, CKA_PRIVATE, &true, sizeof (true));
SETATTR(templ, 3, CKA_ID, Id.Data, Id.Length);
if ((ckrv = C_FindObjectsInit(kmfh->pk11handle, templ, 4)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto errout;
}
if ((ckrv = C_FindObjects(kmfh->pk11handle, &pri_obj, 1,
&obj_count)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto errout;
}
if (obj_count == 0) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_KEY_NOT_FOUND;
goto errout;
}
key->kstype = KMF_KEYSTORE_PK11TOKEN;
key->keyclass = KMF_ASYM_PRI;
key->keyp = (void *)pri_obj;
key->israw = FALSE;
(void) C_FindObjectsFinal(kmfh->pk11handle);
ckrv = getObjectLabel(handle, (CK_OBJECT_HANDLE)key->keyp,
&key->keylabel);
if (ckrv != CKR_OK) {
SET_ERROR(handle, ckrv);
rv = KMF_ERR_INTERNAL;
} else {
rv = KMF_OK;
}
/*
* The key->keyalg value is needed if we need to convert the key
* to raw key. However, the key->keyalg value will not be set if
* this function is not called thru the kmf_find_prikey_by_cert()
* framework function. To be safe, we will get the keytype from
* the key object and set key->keyalg value here.
*/
ckrv = getObjectKeytype(handle, (CK_OBJECT_HANDLE)key->keyp,
&keytype);
if (ckrv != CKR_OK) {
SET_ERROR(handle, ckrv);
rv = KMF_ERR_INTERNAL;
} else {
rv = KMF_OK;
}
if (keytype == CKK_RSA)
key->keyalg = KMF_RSA;
else if (keytype == CKK_DSA)
key->keyalg = KMF_DSA;
else if (keytype == CKK_EC)
key->keyalg = KMF_ECDSA;
else {
/* For asymmetric keys, we only support RSA and DSA */
rv = KMF_ERR_KEY_NOT_FOUND;
goto errout;
}
if (rv == KMF_OK && format == KMF_FORMAT_RAWKEY) {
KMF_RAW_KEY_DATA *rkey = NULL;
rv = keyObj2RawKey(handle, key, &rkey);
if (rv == KMF_OK) {
key->keyp = rkey;
key->israw = TRUE;
}
}
errout:
if (Id.Data != NULL)
free(Id.Data);
if (SignerCert != NULL) {
kmf_free_signed_cert(SignerCert);
free(SignerCert);
}
return (rv);
}
KMF_RETURN
KMFPK11_DecryptData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key,
KMF_OID *algOID, KMF_DATA *ciphertext,
KMF_DATA *output)
{
CK_RV ckrv;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
CK_SESSION_HANDLE hSession = kmfh->pk11handle;
CK_MECHANISM mechanism;
CK_MECHANISM_TYPE mechtype;
CK_KEY_TYPE keytype;
KMF_ALGORITHM_INDEX AlgId;
CK_ULONG out_len = 0, block_len = 0, total_decrypted = 0;
uint8_t *in_data, *out_data;
int i, blocks;
CK_ATTRIBUTE ckTemplate[1];
if (kmfh == NULL)
return (KMF_ERR_UNINITIALIZED); /* Plugin Not Initialized */
if (kmfh->pk11handle == CK_INVALID_HANDLE)
return (KMF_ERR_NO_TOKEN_SELECTED);
if (key == NULL || algOID == NULL ||
ciphertext == NULL || output == NULL)
return (KMF_ERR_BAD_PARAMETER);
AlgId = x509_algoid_to_algid(algOID);
if (AlgId == KMF_ALGID_NONE)
return (KMF_ERR_BAD_PARAMETER);
/* Map the Algorithm ID to a PKCS#11 mechanism */
if (get_pk11_data(AlgId, &keytype, &mechtype, NULL, 0))
return (KMF_ERR_BAD_PARAMETER);
mechanism.mechanism = mechtype;
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;
SETATTR(ckTemplate, 0, CKA_MODULUS, (CK_BYTE *)NULL,
sizeof (CK_ULONG));
/* Get the modulus length */
ckrv = C_GetAttributeValue(hSession,
(CK_OBJECT_HANDLE)key->keyp, ckTemplate, 1);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL);
}
block_len = ckTemplate[0].ulValueLen;
/* Compute the number of times to do single-part decryption */
blocks = ciphertext->Length/block_len;
out_data = output->Data;
in_data = ciphertext->Data;
out_len = block_len - 11;
for (i = 0; i < blocks; i++) {
ckrv = C_DecryptInit(hSession, &mechanism,
(CK_OBJECT_HANDLE)key->keyp);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL);
}
ckrv = C_Decrypt(hSession, in_data, block_len,
out_data, (CK_ULONG *)&out_len);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL);
}
out_data += out_len;
total_decrypted += out_len;
in_data += block_len;
}
output->Length = total_decrypted;
return (KMF_OK);
}
static void
attr2bigint(CK_ATTRIBUTE_PTR attr, KMF_BIGINT *big)
{
big->val = attr->pValue;
big->len = attr->ulValueLen;
}
static KMF_RETURN
get_bigint_attr(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj,
CK_ATTRIBUTE_TYPE attrtype, KMF_BIGINT *bigint)
{
CK_RV ckrv;
CK_ATTRIBUTE attr;
attr.type = attrtype;
attr.pValue = NULL;
attr.ulValueLen = 0;
if ((ckrv = C_GetAttributeValue(sess, obj,
&attr, 1)) != CKR_OK) {
/* Mask this error so the caller can continue */
if (ckrv == CKR_ATTRIBUTE_TYPE_INVALID)
return (KMF_OK);
else
return (KMF_ERR_INTERNAL);
}
if (attr.ulValueLen > 0 && bigint != NULL) {
attr.pValue = malloc(attr.ulValueLen);
if (attr.pValue == NULL)
return (KMF_ERR_MEMORY);
if ((ckrv = C_GetAttributeValue(sess, obj,
&attr, 1)) != CKR_OK)
if (ckrv != CKR_OK) {
free(attr.pValue);
return (KMF_ERR_INTERNAL);
}
bigint->val = attr.pValue;
bigint->len = attr.ulValueLen;
}
return (KMF_OK);
}
static KMF_RETURN
get_raw_rsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_RSA_KEY *rawrsa)
{
KMF_RETURN rv = KMF_OK;
CK_RV ckrv;
CK_SESSION_HANDLE sess = kmfh->pk11handle;
CK_ATTRIBUTE rsa_pri_attrs[2] = {
{ CKA_MODULUS, NULL, 0 },
{ CKA_PUBLIC_EXPONENT, NULL, 0 }
};
CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
int i;
if (rawrsa == NULL)
return (KMF_ERR_BAD_PARAMETER);
(void) memset(rawrsa, 0, sizeof (KMF_RAW_RSA_KEY));
if ((ckrv = C_GetAttributeValue(sess, obj,
rsa_pri_attrs, count)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
/* Tell the caller know why the key data cannot be retrieved. */
if (ckrv == CKR_ATTRIBUTE_SENSITIVE)
return (KMF_ERR_SENSITIVE_KEY);
else if (ckrv == CKR_KEY_UNEXTRACTABLE)
return (KMF_ERR_UNEXTRACTABLE_KEY);
else
return (KMF_ERR_INTERNAL);
}
/* Allocate memory for each attribute. */
for (i = 0; i < count; i++) {
if (rsa_pri_attrs[i].ulValueLen == (CK_ULONG)-1 ||
rsa_pri_attrs[i].ulValueLen == 0) {
rsa_pri_attrs[i].ulValueLen = 0;
continue;
}
if ((rsa_pri_attrs[i].pValue =
malloc(rsa_pri_attrs[i].ulValueLen)) == NULL) {
rv = KMF_ERR_MEMORY;
goto end;
}
}
/* Now that we have space, really get the attributes */
if ((ckrv = C_GetAttributeValue(sess, obj,
rsa_pri_attrs, count)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);
rv = KMF_ERR_INTERNAL;
goto end;
}
i = 0;
attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->mod);
attr2bigint(&(rsa_pri_attrs[i++]), &rawrsa->pubexp);
/* Now get the optional parameters */
rv = get_bigint_attr(sess, obj, CKA_PRIVATE_EXPONENT, &rawrsa->priexp);
if (rv != KMF_OK)
goto end;
rv = get_bigint_attr(sess, obj, CKA_PRIME_1, &rawrsa->prime1);
if (rv != KMF_OK)
goto end;
rv = get_bigint_attr(sess, obj, CKA_PRIME_2, &rawrsa->prime2);
if (rv != KMF_OK)
goto end;
rv = get_bigint_attr(sess, obj, CKA_EXPONENT_1, &rawrsa->exp1);
if (rv != KMF_OK)
goto end;
rv = get_bigint_attr(sess, obj, CKA_EXPONENT_2, &rawrsa->exp2);
if (rv != KMF_OK)
goto end;
rv = get_bigint_attr(sess, obj, CKA_COEFFICIENT, &rawrsa->coef);
if (rv != KMF_OK)
goto end;
end:
if (rv != KMF_OK) {
for (i = 0; i < count; i++) {
if (rsa_pri_attrs[i].pValue != NULL)
free(rsa_pri_attrs[i].pValue);
}
if (rawrsa->priexp.val)
free(rawrsa->priexp.val);
if (rawrsa->prime1.val)
free(rawrsa->prime1.val);
if (rawrsa->prime2.val)
free(rawrsa->prime2.val);
if (rawrsa->exp1.val)
free(rawrsa->exp1.val);
if (rawrsa->exp2.val)
free(rawrsa->exp2.val);
if (rawrsa->coef.val)
free(rawrsa->coef.val);
(void) memset(rawrsa, 0, sizeof (KMF_RAW_RSA_KEY));
}
return (rv);
}
#define DSA_PRIME_BUFSIZE CHARLEN2BIGNUMLEN(1024) /* 8192 bits */
#define DSA_PRIVATE_BUFSIZE BIG_CHUNKS_FOR_160BITS /* 160 bits */
/*
* This function calculates the pubkey value from the prime,
* base and private key values of a DSA key.
*/
static KMF_RETURN
compute_dsa_pubvalue(KMF_RAW_DSA_KEY *rawdsa)
{
KMF_RETURN rv = KMF_OK;
BIGNUM p, g, x, y;
BIG_ERR_CODE err;
uchar_t *pubvalue;
uint32_t pubvalue_len;
if ((err = big_init1(&p, DSA_PRIME_BUFSIZE, NULL, 0)) != BIG_OK) {
rv = KMF_ERR_MEMORY;
return (rv);
}
bytestring2bignum(&p, rawdsa->prime.val, rawdsa->prime.len);
if ((err = big_init1(&g, DSA_PRIME_BUFSIZE, NULL, 0)) != BIG_OK) {
rv = KMF_ERR_MEMORY;
goto ret1;
}
bytestring2bignum(&g, rawdsa->base.val, rawdsa->base.len);
if ((err = big_init1(&x, DSA_PRIVATE_BUFSIZE, NULL, 0)) != BIG_OK) {
rv = KMF_ERR_MEMORY;
goto ret2;
}
bytestring2bignum(&x, rawdsa->value.val, rawdsa->value.len);
if ((err = big_init1(&y, DSA_PRIME_BUFSIZE, NULL, 0)) != BIG_OK) {
rv = KMF_ERR_MEMORY;
goto ret3;
}
err = big_modexp(&y, &g, &x, &p, NULL);
if (err != BIG_OK) {
rv = KMF_ERR_INTERNAL;
goto ret3;
}
pubvalue_len = y.len * (int)sizeof (uint32_t);
if ((pubvalue = malloc(pubvalue_len)) == NULL) {
rv = KMF_ERR_MEMORY;
goto ret4;
}
bignum2bytestring(pubvalue, &y, pubvalue_len);
rawdsa->pubvalue.val = pubvalue;
rawdsa->pubvalue.len = pubvalue_len;
ret4:
big_finish(&y);
ret3:
big_finish(&x);
ret2:
big_finish(&g);
ret1:
big_finish(&p);
return (rv);
}
static KMF_RETURN
get_raw_ec(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_EC_KEY *rawec)
{
KMF_RETURN rv = KMF_OK;
CK_RV ckrv;
CK_SESSION_HANDLE sess = kmfh->pk11handle;
CK_ATTRIBUTE ec_attrs[2] = {
{ CKA_EC_PARAMS, NULL, 0},
{ CKA_VALUE, NULL, 0}
};
CK_ULONG count = sizeof (ec_attrs) / sizeof (CK_ATTRIBUTE);
int i;
if ((ckrv = C_GetAttributeValue(sess, obj,
ec_attrs, 2)) != CKR_OK) {
SET_ERROR(kmfh, ckrv);