diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2019-03-03 09:26:47 -0800 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2019-03-03 21:22:10 -0800 |
commit | 68837c9c819e281591d398327b6eb8226d234bdc (patch) | |
tree | 01f803395cb25c12827e420ab001b7dfe8d27c4f | |
parent | 11496cac99601f41aa35aa86f8b2cb30ff073b45 (diff) | |
download | openssl-pkcs11-export-68837c9c819e281591d398327b6eb8226d234bdc.tar.gz |
Add ability to have key and certificate
Firefox seems to require the token to store the private key and the
certificate, so you can't simply use a token for a private key and an
external certificate. Thus we add the ability to specify a
certificate instead of a public key. In that case, the token will
have three objects: the certificate, the public key (extracted from
the certificate) and the private key.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | cache.c | 12 | ||||
-rw-r--r-- | crypto.c | 90 | ||||
-rw-r--r-- | openssl-pkcs11.h | 3 | ||||
-rw-r--r-- | pkcs11.c | 89 |
4 files changed, 157 insertions, 37 deletions
@@ -196,8 +196,15 @@ void cache_load_crypto_keys(void) kv = kv_get(&s[i], INI_PUBLIC_KEY); if (!kv) { - fprintf(stderr, "key '%s' has no '%s' value\n", - s[i].section, INI_PUBLIC_KEY); + kv = kv_get(&s[i], INI_CERT); + if (kv) + crypto_load_cert(i, kv->value); + } else { + crypto_load_public_key(i, kv->value); + } + if (!kv) { + fprintf(stderr, "key '%s' has no '%s' or '%s' value\n", + s[i].section, INI_PUBLIC_KEY, INI_CERT); /* * a bit nasty, but removing the section * in-place means we have to do over the value @@ -206,6 +213,5 @@ void cache_load_crypto_keys(void) remove_section(i--); continue; } - crypto_load_public_key(i, kv->value); } } @@ -16,6 +16,7 @@ #include <openssl/pem.h> #include <openssl/err.h> #include <openssl/ui.h> +#include <openssl/x509.h> #include "openssl-pkcs11.h" #include "crypto.h" @@ -61,14 +62,33 @@ static void populate_global(int sec_num) { cache_add_by_secnum(sec_num, "CKA_TOKEN", - (const char *)(BOOL_FOR_PRIVATE | BOOL_FOR_PUBLIC), + (const char *)(BOOL_FOR_PRIVATE | BOOL_FOR_PUBLIC | + BOOL_FOR_CERT), CACHE_INT); cache_add_by_secnum(sec_num, "CKA_PRIVATE", (const char *)BOOL_FOR_PRIVATE, CACHE_INT); cache_add_by_secnum(sec_num, "CKA_SIGN", (const char *)BOOL_FOR_PRIVATE, CACHE_INT); cache_add_by_secnum(sec_num, "CKA_VERIFY", - (const char *)BOOL_FOR_PUBLIC, CACHE_INT); + (const char *)(BOOL_FOR_PUBLIC | BOOL_FOR_CERT), + CACHE_INT); +} + +static int populate_public_key(int sec_num, EVP_PKEY *pkey) +{ + populate_global(sec_num); + switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) { + case EVP_PKEY_RSA: + crypto_rsa_populate(sec_num, pkey); + break; + case EVP_PKEY_EC: + crypto_ec_populate(sec_num, pkey); + break; + default: + fprintf(stderr, "Unknown key type\n"); + return -1; + } + return 0; } int crypto_load_public_key(int sec_num, const char *pub) @@ -93,20 +113,64 @@ int crypto_load_public_key(int sec_num, const char *pub) return -1; } - populate_global(sec_num); - switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) { - case EVP_PKEY_RSA: - crypto_rsa_populate(sec_num, pkey); - break; - case EVP_PKEY_EC: - crypto_ec_populate(sec_num, pkey); - break; - default: - fprintf(stderr, "Unknown key type\n"); + return populate_public_key(sec_num, pkey); +} + +int crypto_load_cert(int sec_num, const char *cert) +{ + FILE *file; + X509 *x509; + X509_NAME *name; + wordexp_t w; + int len, ret; + char *d, *z; + ASN1_INTEGER *sn; + + wordexp(cert, &w, 0); + file = fopen(w.we_wordv[0], "r"); + wordfree(&w); + if (!file) { + fprintf(stderr, "failed to open public key file %s: %s\n", + + cert, strerror(errno)); + return -1; + } + x509 = PEM_read_X509(file, NULL, NULL, NULL); + if (!x509) { + fprintf(stderr, "failed to read public key %s:\n", cert); + ERR_print_errors_fp(stderr); return -1; } - return 0; + len = i2d_X509(x509, NULL); + z = d = OPENSSL_malloc(len); + i2d_X509(x509, (unsigned char **)&z); + cache_add_by_secnum(sec_num, "CKA_VALUE", d, len); + + name = X509_get_issuer_name(x509); + len = i2d_X509_NAME(name, NULL); + z = d = OPENSSL_malloc(len); + i2d_X509_NAME(name, (unsigned char **)&z); + cache_add_by_secnum(sec_num, "CKA_ISSUER", d, len); + + name = X509_get_subject_name(x509); + len = i2d_X509_NAME(name, NULL); + z = d = OPENSSL_malloc(len); + i2d_X509_NAME(name, (unsigned char **)&z); + cache_add_by_secnum(sec_num, "CKA_SUBJECT", d, len); + + sn = X509_get_serialNumber(x509); + len = i2d_ASN1_INTEGER(sn, NULL); + z = d = OPENSSL_malloc(len); + i2d_ASN1_INTEGER(sn, (unsigned char **)&z); + cache_add_by_secnum(sec_num, "CKA_SERIAL_NUMBER", d, len); + + cache_add_by_secnum(sec_num, "CKA_CERTIFICATE_TYPE", + (const char*)CKC_X_509, CACHE_INT); + + ret = populate_public_key(sec_num, X509_get_pubkey(x509)); + X509_free(x509); + return ret; } static int diff --git a/openssl-pkcs11.h b/openssl-pkcs11.h index af71fa8..a1d5e12 100644 --- a/openssl-pkcs11.h +++ b/openssl-pkcs11.h @@ -16,15 +16,18 @@ #define GLOBAL_SECTION "global" #define GLOBAL_SECTION_NUM 0 #define INI_PUBLIC_KEY "public key" +#define INI_CERT "certificate" #define CACHE_INT (-1) #define CACHE_PKEY (-2) #define BOOL_FOR_PUBLIC (1<<0) #define BOOL_FOR_PRIVATE (1<<1) +#define BOOL_FOR_CERT (1<<2) /* crypto.c exported functions */ int crypto_load_public_key(int sec_num, const char *pub); +int crypto_load_cert(int sec_num, const char *cert); int crypto_load_private_key(int sec_num, const unsigned char *pin, int pin_len); void crypto_free_private_key(int sec_num); void crypto_cache_free_pkey(void *pkey); @@ -24,22 +24,23 @@ static CK_FUNCTION_LIST module_functions; * of the object. The upper bits are the shifted section number */ enum obj_type { KEY_PUBLIC = 0, - KEY_PRIVATE = 1 + KEY_PRIVATE = 1, + KEY_CERT = 2, }; static inline int obj_to_section(int obj) { - return obj >> 1; + return obj >> 2; } static inline int section_to_obj(int sec) { - return sec << 1; + return sec << 2; } static inline enum obj_type obj_type(int obj) { - return obj & 1; + return obj & 3; } static inline int obj_to_attr(int obj) @@ -49,10 +50,18 @@ static inline int obj_to_attr(int obj) return BOOL_FOR_PUBLIC; case KEY_PRIVATE: return BOOL_FOR_PRIVATE; + case KEY_CERT: + return BOOL_FOR_CERT; } return 0; /* notreached; gcc error */ } +/* trick: certificates are the only object to have CKA_VALUE */ +static inline int has_cert(int sec_num) +{ + return cache_get_by_secnum(sec_num, "CKA_VALUE", NULL) != NULL; +} + static inline CK_OBJECT_CLASS obj_to_class(int obj) { switch (obj_type(obj)) { @@ -60,6 +69,8 @@ static inline CK_OBJECT_CLASS obj_to_class(int obj) return CKO_PUBLIC_KEY; case KEY_PRIVATE: return CKO_PRIVATE_KEY; + case KEY_CERT: + return CKO_CERTIFICATE; } return 0; /* notreached; gcc error */ } @@ -358,8 +369,12 @@ getattribute(unsigned long obj, CK_ATTRIBUTE_PTR attr) Xa(CKA_EC_POINT); Xa(CKA_EC_PARAMS); Xa(CKA_VALUE); + Xa(CKA_ISSUER); + Xa(CKA_SUBJECT); + Xa(CKA_SERIAL_NUMBER); Xl(CKA_MODULUS_BITS); Xl(CKA_KEY_TYPE); + Xl(CKA_CERTIFICATE_TYPE); Xb(CKA_TOKEN); Xb(CKA_WRAP); Xb(CKA_UNWRAP); @@ -426,20 +441,29 @@ C_FindObjectsInit(CK_SESSION_HANDLE handle, CK_ATTRIBUTE_PTR template, memcmp(attr.pValue, template[i].pValue, attr.ulValueLen) != 0) goto fail; } - if (!logged_in(handle)) { - if (find_restriction == CKO_PRIVATE_KEY) + if (find_restriction != CKO_PUBLIC_KEY && + find_restriction != CKO_PRIVATE_KEY && + find_restriction != CKO_CERTIFICATE) + goto fail; + if (!find_restriction) { + cur_find = 1; + if (logged_in(handle)) + cur_find++; + if (has_cert(handle)) + cur_find++; + } else { + /* only one key */ + if (find_restriction == CKO_PRIVATE_KEY && !logged_in(handle)) + goto fail; + + if (find_restriction == CKO_CERTIFICATE && !has_cert(handle)) goto fail; - else - find_restriction = CKO_PUBLIC_KEY; - } - if (!find_restriction) - cur_find = 2; - else - /* only one key */ cur_find = 1; + } fail: set_find(handle, cur_find, find_restriction); + printf("find init with find_restriction=%ld, cur_find=%d\n", find_restriction, cur_find); return CKR_OK; } @@ -450,22 +474,45 @@ C_FindObjects(CK_SESSION_HANDLE handle, CK_OBJECT_HANDLE_PTR objs, { const int pub_obj = section_to_obj(handle) | KEY_PUBLIC; const int priv_obj = section_to_obj(handle) | KEY_PRIVATE; + const int cert_obj = section_to_obj(handle) | KEY_CERT; int cur_find; CK_OBJECT_CLASS find_restriction; get_find(handle, &cur_find, &find_restriction); if (cur_find > 0 && max >= cur_find) { - if (find_restriction == CKO_PRIVATE_KEY) { - *count = 1; - objs[0] = priv_obj; - } else if (find_restriction == CKO_PUBLIC_KEY) { + if (find_restriction != 0) { *count = 1; - objs[0] = pub_obj; + switch (find_restriction) { + case CKO_PRIVATE_KEY: + objs[0] = priv_obj; + break; + + case CKO_PUBLIC_KEY: + objs[0] = pub_obj; + break; + + case CKO_CERTIFICATE: + objs[0] = cert_obj; + break; + + default: + *count = 0; + } } else { - *count = 2; - objs[0] = pub_obj; - objs[1] = priv_obj; + /* no find restriction: are we logged in and do we have certificates? */ + if (logged_in(handle)) { + *count = 2; + objs[0] = pub_obj; + objs[1] = priv_obj; + } else { + *count = 1; + objs[0] = pub_obj; + } + if (has_cert(handle)) { + objs[*count] = cert_obj; + (*count)++; + } } } else { *count = 0; |