summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmf
diff options
context:
space:
mode:
authorwyllys <none@none>2007-01-11 18:12:31 -0800
committerwyllys <none@none>2007-01-11 18:12:31 -0800
commit71593db26bb6ef7b739cffe06d53bf990cac112c (patch)
tree00b868c1641a6b333cbb82ec94e8890bbd11c62c /usr/src/lib/libkmf
parent24424a35444c8487648be681d47bee4f57af0ffc (diff)
downloadillumos-joyent-71593db26bb6ef7b739cffe06d53bf990cac112c.tar.gz
6501154 kssladm could use KMF
--HG-- rename : usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/openssl_util.c => usr/src/cmd/cmd-inet/usr.sbin/kssl/kssladm/ksslutil.c
Diffstat (limited to 'usr/src/lib/libkmf')
-rw-r--r--usr/src/lib/libkmf/include/kmfapi.h5
-rw-r--r--usr/src/lib/libkmf/include/kmftypes.h12
-rw-r--r--usr/src/lib/libkmf/libkmf/common/certop.c45
-rw-r--r--usr/src/lib/libkmf/libkmf/common/generalop.c10
-rw-r--r--usr/src/lib/libkmf/libkmf/common/mapfile-vers5
-rw-r--r--usr/src/lib/libkmf/libkmf/common/pk11tokens.c13
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers4
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c348
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c116
9 files changed, 451 insertions, 107 deletions
diff --git a/usr/src/lib/libkmf/include/kmfapi.h b/usr/src/lib/libkmf/include/kmfapi.h
index 64ded2ce6a..c7506ab9e6 100644
--- a/usr/src/lib/libkmf/include/kmfapi.h
+++ b/usr/src/lib/libkmf/include/kmfapi.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*
@@ -269,6 +269,8 @@ extern KMF_RETURN KMF_SetCertBasicConstraintExt(KMF_X509_CERTIFICATE *,
extern KMF_RETURN KMF_ExportPK12(KMF_HANDLE_T, KMF_EXPORTP12_PARAMS *, char *);
extern KMF_RETURN KMF_ImportPK12(KMF_HANDLE_T, char *, KMF_CREDENTIAL *,
KMF_DATA **, int *, KMF_RAW_KEY_DATA **, int *);
+extern KMF_RETURN KMF_ImportKeypair(KMF_HANDLE_T, char *, KMF_CREDENTIAL *,
+ KMF_DATA **, int *, KMF_RAW_KEY_DATA **, int *);
/*
* Get OCSP response operation.
@@ -339,6 +341,7 @@ extern void KMF_FreeCRLDistributionPoints(KMF_X509EXT_CRLDISTPOINTS *);
/* APIs for PKCS#11 token */
extern KMF_RETURN KMF_PK11TokenLookup(KMF_HANDLE_T, char *, CK_SLOT_ID *);
+extern CK_SESSION_HANDLE KMF_GetPK11Handle(KMF_HANDLE_T);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libkmf/include/kmftypes.h b/usr/src/lib/libkmf/include/kmftypes.h
index a5f71d30d9..682b1f453e 100644
--- a/usr/src/lib/libkmf/include/kmftypes.h
+++ b/usr/src/lib/libkmf/include/kmftypes.h
@@ -23,7 +23,7 @@
*
* Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -110,8 +110,10 @@ typedef enum {
KMF_FORMAT_ASN1 = 1, /* DER */
KMF_FORMAT_PEM = 2,
KMF_FORMAT_PKCS12 = 3,
- KMF_FORMAT_RAWKEY = 4 /* For FindKey operation */
+ KMF_FORMAT_RAWKEY = 4, /* For FindKey operation */
+ KMF_FORMAT_PEM_KEYPAIR = 5
} KMF_ENCODE_FORMAT;
+#define KMF_FORMAT_NATIVE KMF_FORMAT_UNDEF
typedef enum {
KMF_ALL_CERTS = 0,
@@ -193,6 +195,7 @@ typedef struct {
boolean_t private; /* for finding CKA_PRIVATE objects */
boolean_t sensitive;
boolean_t not_extractable;
+ boolean_t token; /* true == token object, false == session */
} KMF_PKCS11_PARAMS;
typedef struct {
@@ -599,7 +602,10 @@ typedef enum {
KMF_ERR_UNINITIALIZED_TOKEN = 0x4d,
KMF_ERR_INCOMPLETE_TBS_CERT = 0x4e,
KMF_ERR_MISSING_ERRCODE = 0x4f,
- KMF_KEYSTORE_ALREADY_INITIALIZED = 0x50
+ KMF_KEYSTORE_ALREADY_INITIALIZED = 0x50,
+ KMF_ERR_SENSITIVE_KEY = 0x51,
+ KMF_ERR_UNEXTRACTABLE_KEY = 0x52,
+ KMF_ERR_KEY_MISMATCH = 0x53
} KMF_RETURN;
typedef enum {
diff --git a/usr/src/lib/libkmf/libkmf/common/certop.c b/usr/src/lib/libkmf/libkmf/common/certop.c
index db24590caa..8e7074d0ed 100644
--- a/usr/src/lib/libkmf/libkmf/common/certop.c
+++ b/usr/src/lib/libkmf/libkmf/common/certop.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
@@ -2289,6 +2289,49 @@ KMF_ImportPK12(KMF_HANDLE_T handle, char *filename,
return (rv);
}
+KMF_RETURN
+KMF_ImportKeypair(KMF_HANDLE_T handle, char *filename,
+ KMF_CREDENTIAL *cred,
+ KMF_DATA **certs, int *ncerts,
+ KMF_RAW_KEY_DATA **rawkeys, int *nkeys)
+{
+ KMF_RETURN rv;
+ KMF_PLUGIN *plugin;
+ KMF_RETURN (*import_keypair)(KMF_HANDLE *,
+ char *, KMF_CREDENTIAL *,
+ KMF_DATA **, 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);
+
+ /*
+ * Use the Keypair reader from the OpenSSL plugin.
+ */
+ plugin = FindPlugin(handle, KMF_KEYSTORE_OPENSSL);
+ if (plugin == NULL || plugin->dldesc == NULL) {
+ return (KMF_ERR_PLUGIN_NOTFOUND);
+ }
+
+ import_keypair = (KMF_RETURN(*)())dlsym(plugin->dldesc,
+ "openssl_import_keypair");
+ if (import_keypair == NULL) {
+ return (KMF_ERR_FUNCTION_NOT_FOUND);
+ }
+
+ /* Use OpenSSL interfaces to get raw key and cert data */
+ rv = import_keypair(handle, filename, cred, certs, ncerts,
+ rawkeys, nkeys);
+
+ return (rv);
+}
KMF_BOOL
IsEqualOid(KMF_OID *Oid1, KMF_OID *Oid2)
diff --git a/usr/src/lib/libkmf/libkmf/common/generalop.c b/usr/src/lib/libkmf/libkmf/common/generalop.c
index 1617acc119..ad596856b1 100644
--- a/usr/src/lib/libkmf/libkmf/common/generalop.c
+++ b/usr/src/lib/libkmf/libkmf/common/generalop.c
@@ -19,10 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright(c) 1995-2000 Intel Corporation. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -135,7 +134,10 @@ static kmf_error_map kmf_errcodes[] = {
{KMF_ERR_UNINITIALIZED_TOKEN, "KMF_ERR_UNINITIALIZED_TOKEN"},
{KMF_ERR_INCOMPLETE_TBS_CERT, "KMF_ERR_INCOMPLETE_TBS_CERT"},
{KMF_ERR_MISSING_ERRCODE, "KMF_ERR_MISSING_ERRCODE"},
- {KMF_KEYSTORE_ALREADY_INITIALIZED, "KMF_KEYSTORE_ALREADY_INITIALIZED"}
+ {KMF_KEYSTORE_ALREADY_INITIALIZED, "KMF_KEYSTORE_ALREADY_INITIALIZED"},
+ {KMF_ERR_SENSITIVE_KEY, "KMF_ERR_SENSITIVE_KEY"},
+ {KMF_ERR_UNEXTRACTABLE_KEY, "KMF_ERR_UNEXTRACTABLE_KEY"},
+ {KMF_ERR_KEY_MISMATCH, "KMF_ERR_KEY_MISMATCH"}
};
@@ -720,6 +722,8 @@ KMF_GetFileFormat(char *filename, KMF_ENCODE_FORMAT *fmt)
} else {
*fmt = KMF_FORMAT_ASN1;
}
+ } else if (memcmp(buf, "Bag Attr", 8) == 0) {
+ *fmt = KMF_FORMAT_PEM_KEYPAIR;
} else {
/* Cannot determine this file format */
*fmt = 0;
diff --git a/usr/src/lib/libkmf/libkmf/common/mapfile-vers b/usr/src/lib/libkmf/libkmf/common/mapfile-vers
index 6de1bf01f5..044a945d26 100644
--- a/usr/src/lib/libkmf/libkmf/common/mapfile-vers
+++ b/usr/src/lib/libkmf/libkmf/common/mapfile-vers
@@ -18,8 +18,7 @@
#
# CDDL HEADER END
#
-#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -105,12 +104,14 @@ SUNWprivate_1.1 {
KMF_GetKMFErrorString;
KMF_GetOCSPForCert;
KMF_GetOCSPStatusForCert;
+ KMF_GetPK11Handle;
KMF_GetPluginErrorString;
KMF_GetPolicy;
KMF_GetSymKeyValue;
KMF_HexString2Bytes;
KMF_ImportCRL;
KMF_ImportCert;
+ KMF_ImportKeypair;
KMF_ImportPK12;
KMF_Initialize;
KMF_IsCRLFile;
diff --git a/usr/src/lib/libkmf/libkmf/common/pk11tokens.c b/usr/src/lib/libkmf/libkmf/common/pk11tokens.c
index f5e9c62c61..20f8c2db13 100644
--- a/usr/src/lib/libkmf/libkmf/common/pk11tokens.c
+++ b/usr/src/lib/libkmf/libkmf/common/pk11tokens.c
@@ -17,11 +17,10 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- */
-/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
*
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -529,3 +528,9 @@ KMF_SelectToken(KMF_HANDLE_T handle, char *label,
return (kmf_rv);
}
+
+CK_SESSION_HANDLE
+KMF_GetPK11Handle(KMF_HANDLE_T kmfh)
+{
+ return (kmfh->pk11handle);
+}
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers
index cd910effa4..ae025ddd8f 100644
--- a/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers
@@ -18,8 +18,7 @@
#
# CDDL HEADER END
#
-#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -56,6 +55,7 @@ SUNWprivate_1.1 {
OpenSSL_StorePrivateKey;
OpenSSL_VerifyCRLFile;
openssl_read_pkcs12;
+ openssl_import_keypair;
local:
*;
};
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c
index 0f16832dd4..cd8b1815b6 100644
--- a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c
@@ -20,12 +20,13 @@
*
* OpenSSL keystore wrapper
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
+#include <stdlib.h>
#include <kmfapiP.h>
#include <ber_der.h>
#include <oidsalg.h>
@@ -99,6 +100,13 @@ static uchar_t G[] = { 0x00, 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a,
mutex_t init_lock = DEFAULTMUTEX;
static int ssl_initialized = 0;
+static KMF_RETURN
+extract_objects(KMF_HANDLE *, char *, CK_UTF8CHAR *, CK_ULONG,
+ EVP_PKEY **, KMF_DATA **, int *);
+
+static KMF_RETURN
+kmf_load_cert(KMF_HANDLE *, KMF_FINDCERT_PARAMS *, char *, KMF_DATA *);
+
KMF_RETURN
OpenSSL_FindCert(KMF_HANDLE_T,
KMF_FINDCERT_PARAMS *,
@@ -567,6 +575,99 @@ cleanup:
return (rv);
}
+static int
+datacmp(const void *a, const void *b)
+{
+ KMF_DATA *adata = (KMF_DATA *)a;
+ KMF_DATA *bdata = (KMF_DATA *)b;
+ if (adata->Length > bdata->Length)
+ return (-1);
+ if (adata->Length < bdata->Length)
+ return (1);
+ return (0);
+}
+
+static KMF_RETURN
+load_certs(KMF_HANDLE *kmfh, KMF_FINDCERT_PARAMS *params, char *pathname,
+ KMF_DATA **certlist, uint32_t *numcerts)
+{
+ KMF_RETURN rv = KMF_OK;
+ int i;
+ KMF_DATA *certs = NULL;
+ int nc = 0;
+ int hits = 0;
+ KMF_ENCODE_FORMAT format;
+
+ rv = KMF_GetFileFormat(pathname, &format);
+ if (rv != KMF_OK) {
+ if (rv == KMF_ERR_OPEN_FILE)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ return (rv);
+ }
+ if (format == KMF_FORMAT_ASN1) {
+ /* load a single certificate */
+ certs = (KMF_DATA *)malloc(sizeof (KMF_DATA));
+ if (certs == NULL)
+ return (KMF_ERR_MEMORY);
+ certs->Data = NULL;
+ certs->Length = 0;
+ rv = kmf_load_cert(kmfh, params, pathname, certs);
+ if (rv == KMF_OK) {
+ *certlist = certs;
+ *numcerts = 1;
+ }
+ return (rv);
+ } else if (format == KMF_FORMAT_PKCS12) {
+ /* We need a credential to access a PKCS#12 file */
+ rv = KMF_ERR_BAD_CERT_FORMAT;
+ } else if (format == KMF_FORMAT_PEM ||
+ format != KMF_FORMAT_PEM_KEYPAIR) {
+
+ /* This function only works on PEM files */
+ rv = extract_objects(kmfh, pathname,
+ (uchar_t *)NULL, 0, NULL,
+ &certs, &nc);
+ } else {
+ return (KMF_ERR_ENCODING);
+ }
+
+ if (rv != KMF_OK)
+ return (rv);
+
+ for (i = 0; i < nc; i++) {
+ if (params->find_cert_validity == KMF_NONEXPIRED_CERTS) {
+ rv = KMF_CheckCertDate(kmfh, &certs[i]);
+ } else if (params->find_cert_validity == KMF_EXPIRED_CERTS) {
+ rv = KMF_CheckCertDate(kmfh, &certs[i]);
+ if (rv == KMF_OK)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ if (rv == KMF_ERR_VALIDITY_PERIOD)
+ rv = KMF_OK;
+ }
+ if (rv != KMF_OK) {
+ /* Remove this cert from the list by clearing it. */
+ KMF_FreeData(&certs[i]);
+ } else {
+ hits++; /* count valid certs found */
+ }
+ rv = KMF_OK;
+ }
+ if (rv == KMF_OK && hits == 0) {
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ } else if (rv == KMF_OK && hits > 0) {
+ /*
+ * Sort the list of certs by length to put the cleared ones
+ * at the end so they don't get accessed by the caller.
+ */
+ qsort((void *)certs, nc, sizeof (KMF_DATA), datacmp);
+ *certlist = certs;
+
+ /* since we sorted the list, just return the number of hits */
+ *numcerts = hits;
+ }
+ return (rv);
+}
+
static KMF_RETURN
kmf_load_cert(KMF_HANDLE *kmfh,
KMF_FINDCERT_PARAMS *params,
@@ -631,7 +732,8 @@ openssl_load_key(KMF_HANDLE_T handle, const char *file)
if (format == KMF_FORMAT_ASN1)
pkey = d2i_PrivateKey_bio(keyfile, NULL);
- else if (format == KMF_FORMAT_PEM)
+ else if (format == KMF_FORMAT_PEM ||
+ format == KMF_FORMAT_PEM_KEYPAIR)
pkey = PEM_read_bio_PrivateKey(keyfile, NULL, NULL, NULL);
end:
@@ -652,8 +754,8 @@ OpenSSL_FindCert(KMF_HANDLE_T handle,
{
KMF_RETURN rv = KMF_OK;
KMF_HANDLE *kmfh = (KMF_HANDLE *)handle;
- KMF_DATA certdata = {NULL, 0};
char *fullpath;
+ int i;
if (num_certs == NULL || params == NULL)
return (KMF_ERR_BAD_PARAMETER);
@@ -677,6 +779,9 @@ OpenSSL_FindCert(KMF_HANDLE_T handle,
}
while ((dp = readdir(dirp)) != NULL) {
char *fname;
+ KMF_DATA *certlist = NULL;
+ uint32_t numcerts = 0;
+
if (strcmp(dp->d_name, ".") == 0 ||
strcmp(dp->d_name, "..") == 0)
continue;
@@ -684,34 +789,43 @@ OpenSSL_FindCert(KMF_HANDLE_T handle,
fname = get_fullpath(fullpath,
(char *)&dp->d_name);
- rv = kmf_load_cert(kmfh, params, fname,
- &certdata);
+ rv = load_certs(kmfh, params, fname, &certlist,
+ &numcerts);
if (rv != KMF_OK) {
free(fname);
- KMF_FreeData(&certdata);
+ if (certlist != NULL) {
+ for (i = 0; i < numcerts; i++)
+ KMF_FreeData(&certlist[i]);
+ free(certlist);
+ }
continue;
}
/* If load succeeds, add certdata to the list */
if (kmf_cert != NULL) {
- kmf_cert[n].certificate.Data = certdata.Data;
- kmf_cert[n].certificate.Length =
- certdata.Length;
-
- kmf_cert[n].kmf_private.keystore_type =
- KMF_KEYSTORE_OPENSSL;
- kmf_cert[n].kmf_private.flags =
- KMF_FLAG_CERT_VALID;
- kmf_cert[n].kmf_private.label = fname;
-
- certdata.Data = NULL;
- certdata.Length = 0;
+ for (i = 0; i < numcerts; i++) {
+ kmf_cert[n].certificate.Data =
+ certlist[i].Data;
+ kmf_cert[n].certificate.Length =
+ certlist[i].Length;
+
+ kmf_cert[n].kmf_private.keystore_type =
+ KMF_KEYSTORE_OPENSSL;
+ kmf_cert[n].kmf_private.flags =
+ KMF_FLAG_CERT_VALID;
+ kmf_cert[n].kmf_private.label =
+ strdup(fname);
+ n++;
+ }
+ free(certlist);
} else {
- free(fname);
- KMF_FreeData(&certdata);
+ for (i = 0; i < numcerts; i++)
+ KMF_FreeData(&certlist[i]);
+ free(certlist);
+ n += numcerts;
}
- n++;
+ free(fname);
}
(*num_certs) = n;
if (*num_certs == 0)
@@ -721,33 +835,42 @@ OpenSSL_FindCert(KMF_HANDLE_T handle,
exit:
(void) closedir(dirp);
} else {
- /* Just try to load a single certificate */
- rv = kmf_load_cert(kmfh, params, fullpath, &certdata);
+ KMF_DATA *certlist = NULL;
+ uint32_t numcerts = 0;
+
+ rv = load_certs(kmfh, params, fullpath, &certlist, &numcerts);
if (rv != KMF_OK) {
free(fullpath);
- KMF_FreeData(&certdata);
return (rv);
}
- if (kmf_cert != NULL) {
- kmf_cert->certificate.Data = certdata.Data;
- kmf_cert->certificate.Length = certdata.Length;
- kmf_cert->kmf_private.keystore_type =
- KMF_KEYSTORE_OPENSSL;
- kmf_cert->kmf_private.flags = KMF_FLAG_CERT_VALID;
- kmf_cert->kmf_private.label = fullpath;
+ if (kmf_cert != NULL && certlist != NULL) {
+ for (i = 0; i < numcerts; i++) {
+ kmf_cert[i].certificate.Data =
+ certlist[i].Data;
+ kmf_cert[i].certificate.Length =
+ certlist[i].Length;
+ kmf_cert[i].kmf_private.keystore_type =
+ KMF_KEYSTORE_OPENSSL;
+ kmf_cert[i].kmf_private.flags =
+ KMF_FLAG_CERT_VALID;
+ kmf_cert[i].kmf_private.label =
+ strdup(fullpath);
+ }
+ free(certlist);
} else {
- KMF_FreeData(&certdata);
+ if (certlist != NULL) {
+ for (i = 0; i < numcerts; i++)
+ KMF_FreeData(&certlist[i]);
+ free(certlist);
+ }
}
-
- *num_certs = 1;
+ *num_certs = numcerts;
}
- if (kmf_cert == NULL || rv != KMF_OK)
- free(fullpath);
+ free(fullpath);
return (rv);
-
}
void
@@ -3265,6 +3388,107 @@ end:
return (rv);
}
+#define MAX_CHAIN_LENGTH 100
+/*
+ * Helper function to extract keys and certificates from
+ * a single PEM file. Typically the file should contain a
+ * private key and an associated public key wrapped in an x509 cert.
+ * However, the file may be just a list of X509 certs with no keys.
+ */
+static KMF_RETURN
+extract_objects(KMF_HANDLE *kmfh, char *filename, CK_UTF8CHAR *pin,
+ CK_ULONG pinlen, EVP_PKEY **priv_key, KMF_DATA **certs,
+ int *numcerts)
+/* ARGSUSED */
+{
+ KMF_RETURN rv = KMF_OK;
+ FILE *fp;
+ STACK_OF(X509_INFO) *x509_info_stack;
+ int i, ncerts = 0;
+ EVP_PKEY *pkey = NULL;
+ X509_INFO *info;
+ X509 *x;
+ X509_INFO *cert_infos[MAX_CHAIN_LENGTH];
+ KMF_DATA *certlist = NULL;
+
+ if (priv_key)
+ *priv_key = NULL;
+ if (certs)
+ *certs = NULL;
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return (KMF_ERR_OPEN_FILE);
+ }
+ x509_info_stack = PEM_X509_INFO_read(fp, NULL, NULL, pin);
+ if (x509_info_stack == NULL) {
+ (void) fclose(fp);
+ return (KMF_ERR_ENCODING);
+ }
+
+ /*LINTED*/
+ while ((info = sk_X509_INFO_pop(x509_info_stack)) != NULL &&
+ ncerts < MAX_CHAIN_LENGTH) {
+ cert_infos[ncerts] = info;
+ ncerts++;
+ }
+
+ if (ncerts == 0) {
+ (void) fclose(fp);
+ return (KMF_ERR_CERT_NOT_FOUND);
+ }
+
+ if (priv_key != NULL) {
+ rewind(fp);
+ pkey = PEM_read_PrivateKey(fp, NULL, NULL, pin);
+ }
+ (void) fclose(fp);
+
+ x = cert_infos[ncerts - 1]->x509;
+ /*
+ * Make sure the private key matchs the last cert in the file.
+ */
+ if (pkey != NULL && !X509_check_private_key(x, pkey)) {
+ EVP_PKEY_free(pkey);
+ return (KMF_ERR_KEY_MISMATCH);
+ }
+
+ certlist = (KMF_DATA *)malloc(ncerts * sizeof (KMF_DATA));
+ if (certlist == NULL) {
+ if (pkey != NULL)
+ EVP_PKEY_free(pkey);
+ X509_INFO_free(info);
+ return (KMF_ERR_MEMORY);
+ }
+
+ /*
+ * Convert all of the certs to DER format.
+ */
+ for (i = 0; rv == KMF_OK && certs != NULL && i < ncerts; i++) {
+ info = cert_infos[ncerts - 1 - i];
+
+ rv = ssl_cert2KMFDATA(kmfh, info->x509, &certlist[i]);
+
+ if (rv != KMF_OK) {
+ free(certlist);
+ certlist = NULL;
+ ncerts = 0;
+ }
+ X509_INFO_free(info);
+ }
+
+ if (numcerts != NULL)
+ *numcerts = ncerts;
+ if (certs != NULL)
+ *certs = certlist;
+
+ if (priv_key == NULL && pkey != NULL)
+ EVP_PKEY_free(pkey);
+ else if (priv_key != NULL && pkey != NULL)
+ *priv_key = pkey;
+
+ return (rv);
+}
+
/*
* Helper function to decrypt and parse PKCS#12 import file.
*/
@@ -3517,7 +3741,7 @@ convertPK12Objects(
}
/* Also add any included CA certs to the list */
- for (i = 0; i != sk_X509_num(sslcacerts); i++) {
+ for (i = 0; sslcacerts != NULL && i < sk_X509_num(sslcacerts); i++) {
X509 *c;
/*
* sk_X509_value() is macro that embeds a cast to (X509 *).
@@ -3601,6 +3825,54 @@ end:
}
KMF_RETURN
+openssl_import_keypair(KMF_HANDLE *kmfh,
+ char *filename, KMF_CREDENTIAL *cred,
+ KMF_DATA **certlist, int *ncerts,
+ KMF_RAW_KEY_DATA **keylist, int *nkeys)
+{
+ KMF_RETURN rv = KMF_OK;
+ EVP_PKEY *privkey = NULL;
+ KMF_ENCODE_FORMAT format;
+
+ /*
+ * auto-detect the file format, regardless of what
+ * the 'format' parameters in the params say.
+ */
+ rv = KMF_GetFileFormat(filename, &format);
+ if (rv != KMF_OK) {
+ if (rv == KMF_ERR_OPEN_FILE)
+ rv = KMF_ERR_CERT_NOT_FOUND;
+ return (rv);
+ }
+
+ /* This function only works on PEM files */
+ if (format != KMF_FORMAT_PEM &&
+ format != KMF_FORMAT_PEM_KEYPAIR)
+ return (KMF_ERR_ENCODING);
+
+ *certlist = NULL;
+ *keylist = NULL;
+ *ncerts = 0;
+ *nkeys = 0;
+ rv = extract_objects(kmfh, filename,
+ (uchar_t *)cred->cred,
+ (uint32_t)cred->credlen,
+ &privkey, certlist, ncerts);
+
+ /* Reached end of import file? */
+ if (rv == KMF_OK)
+ /* Convert keys and certs to exportable format */
+ rv = convertPK12Objects(kmfh, privkey, NULL, NULL,
+ keylist, nkeys, NULL, NULL);
+
+end:
+ if (privkey)
+ EVP_PKEY_free(privkey);
+
+ return (rv);
+}
+
+KMF_RETURN
OpenSSL_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
KMF_RAW_KEY_DATA *key)
{
diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
index e548c64eb8..cc8a0afc0f 100644
--- a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
+++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c
@@ -21,7 +21,7 @@
/*
* PKCS11 token KMF Plugin
*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -57,6 +57,9 @@ 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 **);
@@ -213,13 +216,12 @@ PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
CK_CERTIFICATE_TYPE cktype;
CK_OBJECT_CLASS class;
- CK_BBOOL cktrusted, token;
CK_ULONG subject_len, value_len, issuer_len, serno_len, id_len;
CK_BYTE *subject = NULL, *value = NULL;
- CK_BYTE *label = NULL;
- CK_ULONG label_len = 0;
+ 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 ? */
@@ -230,30 +232,32 @@ PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
}
SETATTR(templ, 0, CKA_CERTIFICATE_TYPE, &cktype, sizeof (cktype));
- SETATTR(templ, 1, CKA_TOKEN, &token, sizeof (token));
- SETATTR(templ, 2, CKA_TRUSTED, &cktrusted, sizeof (cktrusted));
-
- ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, 3);
+ 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 =
- label_len = 0;
- SETATTR(templ, 0, CKA_SUBJECT, NULL, subject_len);
- SETATTR(templ, 1, CKA_ISSUER, NULL, issuer_len);
- SETATTR(templ, 2, CKA_SERIAL_NUMBER, NULL, serno_len);
- SETATTR(templ, 3, CKA_ID, NULL, id_len);
- SETATTR(templ, 4, CKA_VALUE, NULL, value_len);
- SETATTR(templ, 5, CKA_LABEL, NULL, label_len);
+ 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, 6);
+ ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj, templ, i);
if (ckrv != CKR_OK) {
SET_ERROR(kmfh, ckrv);
return (KMF_ERR_INTERNAL); /* TODO - Error messages ? */
@@ -264,7 +268,6 @@ PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
serno_len = templ[2].ulValueLen;
id_len = templ[3].ulValueLen;
value_len = templ[4].ulValueLen;
- label_len = templ[5].ulValueLen;
/*
* For PKCS#11 CKC_X_509 certificate objects,
@@ -288,17 +291,6 @@ PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
SETATTR(templ, i, CKA_VALUE, value, value_len);
i++;
- if (label_len > 0) {
- label = malloc(label_len + 1);
- if (label == NULL) {
- rv = KMF_ERR_MEMORY;
- goto errout;
- }
- (void) memset(label, 0, label_len + 1);
- SETATTR(templ, i, CKA_LABEL, label,
- label_len);
- i++;
- }
/* re-query the object with room for the value attr */
ckrv = C_GetAttributeValue(kmfh->pk11handle, hObj,
@@ -315,7 +307,11 @@ PK11Cert2KMFCert(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE hObj,
kmfcert->kmf_private.flags |= KMF_FLAG_CERT_SIGNED;
kmfcert->kmf_private.keystore_type =
KMF_KEYSTORE_PK11TOKEN;
- kmfcert->kmf_private.label = (char *)label;
+
+ ckrv = getObjectLabel(kmfh, hObj, &label);
+ if (ckrv == CKR_OK && label != NULL) {
+ kmfcert->kmf_private.label = (char *)label;
+ }
rv = KMF_OK;
}
@@ -1024,7 +1020,7 @@ CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert)
CK_RV ckrv;
CK_ULONG subject_len, issuer_len, serno_len;
- CK_BYTE *subject, *issuer, *serial;
+ CK_BYTE *subject, *issuer, *serial, nullserno;
CK_BBOOL true = TRUE;
CK_CERTIFICATE_TYPE certtype = CKC_X_509;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
@@ -1082,8 +1078,13 @@ CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert)
serial = signed_cert_ptr->certificate.serialNumber.val;
serno_len = signed_cert_ptr->certificate.serialNumber.len;
} else {
- rv = KMF_ERR_ENCODING;
- goto cleanup;
+ /*
+ * 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 */
@@ -1110,7 +1111,6 @@ CreateCertObject(KMF_HANDLE_T handle, char *label, KMF_DATA *pcert)
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
@@ -1999,6 +1999,7 @@ 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[8] = {
{ CKA_MODULUS, NULL, 0 },
@@ -2013,10 +2014,16 @@ get_raw_rsa(KMF_HANDLE *kmfh, CK_OBJECT_HANDLE obj, KMF_RAW_RSA_KEY *rawrsa)
CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
int i;
- if ((rv = C_GetAttributeValue(sess, obj,
+ if ((ckrv = C_GetAttributeValue(sess, obj,
rsa_pri_attrs, count)) != CKR_OK) {
- SET_ERROR(kmfh, rv);
- return (KMF_ERR_INTERNAL);
+ 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. */
@@ -2314,7 +2321,6 @@ KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
CK_ATTRIBUTE pTmpl[10];
CK_OBJECT_CLASS class;
CK_BBOOL true = TRUE;
- CK_BBOOL false = FALSE;
CK_ULONG alg;
CK_BBOOL is_token;
@@ -2332,15 +2338,13 @@ KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
else
want_keys = MAXINT; /* count them all */
+ is_token = parms->pkcs11parms.token;
if (parms->keyclass == KMF_ASYM_PUB) {
class = CKO_PUBLIC_KEY;
- is_token = false;
} else if (parms->keyclass == KMF_ASYM_PRI) {
class = CKO_PRIVATE_KEY;
- is_token = true;
} else if (parms->keyclass == KMF_SYMMETRIC) {
class = CKO_SECRET_KEY;
- is_token = true;
} else {
return (KMF_ERR_BAD_KEY_CLASS);
}
@@ -2403,7 +2407,11 @@ KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
i++;
}
- if (is_token) {
+ /*
+ * Authenticate if the object is a token object,
+ * a private or secred key, or if the user passed in credentials.
+ */
+ if (parms->cred.credlen > 0) {
rv = pk11_authenticate(handle, &parms->cred);
if (rv != KMF_OK) {
return (rv);
@@ -2462,17 +2470,18 @@ KMFPK11_FindKey(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS *parms,
/* "numkeys" indicates the number that were actually found */
*numkeys = n;
}
- if (ckrv == KMF_OK && keys != NULL && (*numkeys) > 0 &&
- parms->format == KMF_FORMAT_RAWKEY) {
- /* Convert keys to "rawkey" format */
- for (i = 0; i < (*numkeys); i++) {
- KMF_RAW_KEY_DATA *rkey = NULL;
- rv = keyObj2RawKey(handle, &keys[i], &rkey);
- if (rv == KMF_OK) {
- keys[i].keyp = rkey;
- keys[i].israw = TRUE;
- } else {
- break;
+ if (ckrv == KMF_OK && keys != NULL && (*numkeys) > 0) {
+ if (parms->format == KMF_FORMAT_RAWKEY) {
+ /* Convert keys to "rawkey" format */
+ for (i = 0; i < (*numkeys); i++) {
+ KMF_RAW_KEY_DATA *rkey = NULL;
+ rv = keyObj2RawKey(handle, &keys[i], &rkey);
+ if (rv == KMF_OK) {
+ keys[i].keyp = rkey;
+ keys[i].israw = TRUE;
+ } else {
+ break;
+ }
}
}
}
@@ -2604,6 +2613,7 @@ KMFPK11_StorePrivateKey(KMF_HANDLE_T handle, KMF_STOREKEY_PARAMS *params,
SETATTR(templ, i, CKA_TOKEN, &cktrue, sizeof (cktrue)); i++;
SETATTR(templ, i, CKA_PRIVATE, &cktrue, sizeof (cktrue)); i++;
SETATTR(templ, i, CKA_SUBJECT, subject.Data, subject.Length); i++;
+ SETATTR(templ, i, CKA_DECRYPT, &cktrue, sizeof (cktrue)); i++;
/*
* Only set the KeyUsage stuff if the KU extension was present.