diff options
author | wyllys <none@none> | 2007-01-11 18:12:31 -0800 |
---|---|---|
committer | wyllys <none@none> | 2007-01-11 18:12:31 -0800 |
commit | 71593db26bb6ef7b739cffe06d53bf990cac112c (patch) | |
tree | 00b868c1641a6b333cbb82ec94e8890bbd11c62c /usr/src/lib/libkmf | |
parent | 24424a35444c8487648be681d47bee4f57af0ffc (diff) | |
download | illumos-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.h | 5 | ||||
-rw-r--r-- | usr/src/lib/libkmf/include/kmftypes.h | 12 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/certop.c | 45 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/generalop.c | 10 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/mapfile-vers | 5 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/pk11tokens.c | 13 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_openssl/common/mapfile-vers | 4 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c | 348 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c | 116 |
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. |