aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2019-03-03 09:26:47 -0800
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2019-03-03 21:22:10 -0800
commit68837c9c819e281591d398327b6eb8226d234bdc (patch)
tree01f803395cb25c12827e420ab001b7dfe8d27c4f
parent11496cac99601f41aa35aa86f8b2cb30ff073b45 (diff)
downloadopenssl-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.c12
-rw-r--r--crypto.c90
-rw-r--r--openssl-pkcs11.h3
-rw-r--r--pkcs11.c89
4 files changed, 157 insertions, 37 deletions
diff --git a/cache.c b/cache.c
index b29ce8b..a461259 100644
--- a/cache.c
+++ b/cache.c
@@ -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);
}
}
diff --git a/crypto.c b/crypto.c
index 0a5747d..d823ee5 100644
--- a/crypto.c
+++ b/crypto.c
@@ -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);
diff --git a/pkcs11.c b/pkcs11.c
index 8c56019..e6a2d9c 100644
--- a/pkcs11.c
+++ b/pkcs11.c
@@ -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;