summaryrefslogtreecommitdiff
path: root/ssh-pkcs11.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-01-25 00:03:36 +0000
committerDamien Miller <djm@mindrot.org>2020-01-25 11:35:55 +1100
commit89a8d4525e8edd9958ed3df60cf683551142eae0 (patch)
tree5251d0355691f30dca76d17724dd0d2123285e6e /ssh-pkcs11.c
parenta8c05c640873621681ab64d2e47a314592d5efa2 (diff)
downloadopenssh-git-89a8d4525e8edd9958ed3df60cf683551142eae0.tar.gz
upstream: expose PKCS#11 key labels/X.509 subjects as comments
Extract the key label or X.509 subject string when PKCS#11 keys are retrieved from the token and plumb this through to places where it may be used as a comment. based on https://github.com/openssh/openssh-portable/pull/138 by Danielle Church feedback and ok markus@ OpenBSD-Commit-ID: cae1fda10d9e10971dea29520916e27cfec7ca35
Diffstat (limited to 'ssh-pkcs11.c')
-rw-r--r--ssh-pkcs11.c142
1 files changed, 89 insertions, 53 deletions
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index 09f1ea34..a302c79c 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11.c,v 1.46 2019/10/01 10:22:53 djm Exp $ */
+/* $OpenBSD: ssh-pkcs11.c,v 1.47 2020/01/25 00:03:36 djm Exp $ */
/*
* Copyright (c) 2010 Markus Friedl. All rights reserved.
* Copyright (c) 2014 Pedro Martelletto. All rights reserved.
@@ -893,15 +893,16 @@ fail:
return (key);
}
-static struct sshkey *
+static int
pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
- CK_OBJECT_HANDLE *obj)
+ CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
{
CK_ATTRIBUTE cert_attr[3];
CK_SESSION_HANDLE session;
CK_FUNCTION_LIST *f = NULL;
CK_RV rv;
X509 *x509 = NULL;
+ X509_NAME *x509_name = NULL;
EVP_PKEY *evp;
RSA *rsa = NULL;
#ifdef OPENSSL_HAS_ECC
@@ -912,7 +913,11 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
#ifdef HAVE_EC_KEY_METHOD_NEW
int nid;
#endif
- const u_char *cp;
+ const u_char *cp;
+ char *subject = NULL;
+
+ *keyp = NULL;
+ *labelp = NULL;
memset(&cert_attr, 0, sizeof(cert_attr));
cert_attr[0].type = CKA_ID;
@@ -926,7 +931,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
if (rv != CKR_OK) {
error("C_GetAttributeValue failed: %lu", rv);
- return (NULL);
+ return -1;
}
/*
@@ -937,7 +942,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
if (cert_attr[1].ulValueLen == 0 ||
cert_attr[2].ulValueLen == 0) {
error("invalid attribute length");
- return (NULL);
+ return -1;
}
/* allocate buffers for attributes */
@@ -949,44 +954,45 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
if (rv != CKR_OK) {
error("C_GetAttributeValue failed: %lu", rv);
- goto fail;
+ goto out;
}
- x509 = X509_new();
- if (x509 == NULL) {
- error("x509_new failed");
- goto fail;
- }
+ /* Decode DER-encoded cert subject */
+ cp = cert_attr[2].pValue;
+ if ((x509_name = d2i_X509_NAME(NULL, &cp,
+ cert_attr[1].ulValueLen)) == NULL ||
+ (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
+ subject = xstrdup("invalid subject");
+ X509_NAME_free(x509_name);
cp = cert_attr[2].pValue;
- if (d2i_X509(&x509, &cp, cert_attr[2].ulValueLen) == NULL) {
+ if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
error("d2i_x509 failed");
- goto fail;
+ goto out;
}
- evp = X509_get_pubkey(x509);
- if (evp == NULL) {
+ if ((evp = X509_get_pubkey(x509)) == NULL) {
error("X509_get_pubkey failed");
- goto fail;
+ goto out;
}
if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
if (EVP_PKEY_get0_RSA(evp) == NULL) {
error("invalid x509; no rsa key");
- goto fail;
+ goto out;
}
if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
error("RSAPublicKey_dup failed");
- goto fail;
+ goto out;
}
if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
- goto fail;
+ goto out;
key = sshkey_new(KEY_UNSPEC);
if (key == NULL) {
error("sshkey_new failed");
- goto fail;
+ goto out;
}
key->rsa = rsa;
@@ -997,26 +1003,26 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
error("invalid x509; no ec key");
- goto fail;
+ goto out;
}
if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
error("EC_KEY_dup failed");
- goto fail;
+ goto out;
}
nid = sshkey_ecdsa_key_to_nid(ec);
if (nid < 0) {
error("couldn't get curve nid");
- goto fail;
+ goto out;
}
if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
- goto fail;
+ goto out;
key = sshkey_new(KEY_UNSPEC);
if (key == NULL) {
error("sshkey_new failed");
- goto fail;
+ goto out;
}
key->ecdsa = ec;
@@ -1025,10 +1031,11 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
key->flags |= SSHKEY_FLAG_EXT;
ec = NULL; /* now owned by key */
#endif /* HAVE_EC_KEY_METHOD_NEW */
- } else
+ } else {
error("unknown certificate key type");
-
-fail:
+ goto out;
+ }
+ out:
for (i = 0; i < 3; i++)
free(cert_attr[i].pValue);
X509_free(x509);
@@ -1036,8 +1043,14 @@ fail:
#ifdef OPENSSL_HAS_ECC
EC_KEY_free(ec);
#endif
-
- return (key);
+ if (key == NULL) {
+ free(subject);
+ return -1;
+ }
+ /* success */
+ *keyp = key;
+ *labelp = subject;
+ return 0;
}
#if 0
@@ -1058,7 +1071,7 @@ have_rsa_key(const RSA *rsa)
*/
static int
pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
- struct sshkey ***keysp, int *nkeys)
+ struct sshkey ***keysp, char ***labelsp, int *nkeys)
{
struct sshkey *key = NULL;
CK_OBJECT_CLASS key_class;
@@ -1069,6 +1082,7 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
CK_OBJECT_HANDLE obj;
CK_ULONG n = 0;
int ret = -1;
+ char *label;
memset(&key_attr, 0, sizeof(key_attr));
memset(&obj, 0, sizeof(obj));
@@ -1110,18 +1124,19 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
goto fail;
}
+ key = NULL;
+ label = NULL;
switch (ck_cert_type) {
case CKC_X_509:
- key = pkcs11_fetch_x509_pubkey(p, slotidx, &obj);
+ if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
+ &key, &label) != 0) {
+ error("failed to fetch key");
+ continue;
+ }
break;
default:
- /* XXX print key type? */
- key = NULL;
- error("skipping unsupported certificate type");
- }
-
- if (key == NULL) {
- error("failed to fetch key");
+ error("skipping unsupported certificate type %lu",
+ ck_cert_type);
continue;
}
@@ -1132,6 +1147,11 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
*keysp = xrecallocarray(*keysp, *nkeys,
*nkeys + 1, sizeof(struct sshkey *));
(*keysp)[*nkeys] = key;
+ if (labelsp != NULL) {
+ *labelsp = xrecallocarray(*labelsp, *nkeys,
+ *nkeys + 1, sizeof(char *));
+ (*labelsp)[*nkeys] = xstrdup((char *)label);
+ }
*nkeys = *nkeys + 1;
debug("have %d keys", *nkeys);
}
@@ -1155,11 +1175,11 @@ fail:
*/
static int
pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
- struct sshkey ***keysp, int *nkeys)
+ struct sshkey ***keysp, char ***labelsp, int *nkeys)
{
struct sshkey *key = NULL;
CK_OBJECT_CLASS key_class;
- CK_ATTRIBUTE key_attr[1];
+ CK_ATTRIBUTE key_attr[2];
CK_SESSION_HANDLE session;
CK_FUNCTION_LIST *f = NULL;
CK_RV rv;
@@ -1186,6 +1206,7 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
while (1) {
CK_KEY_TYPE ck_key_type;
+ CK_UTF8CHAR label[256];
rv = f->C_FindObjects(session, &obj, 1, &n);
if (rv != CKR_OK) {
@@ -1200,13 +1221,18 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
key_attr[0].type = CKA_KEY_TYPE;
key_attr[0].pValue = &ck_key_type;
key_attr[0].ulValueLen = sizeof(ck_key_type);
+ key_attr[1].type = CKA_LABEL;
+ key_attr[1].pValue = &label;
+ key_attr[1].ulValueLen = sizeof(label) - 1;
- rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
+ rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
if (rv != CKR_OK) {
error("C_GetAttributeValue failed: %lu", rv);
goto fail;
}
+ label[key_attr[1].ulValueLen] = '\0';
+
switch (ck_key_type) {
case CKK_RSA:
key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
@@ -1234,6 +1260,11 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
*keysp = xrecallocarray(*keysp, *nkeys,
*nkeys + 1, sizeof(struct sshkey *));
(*keysp)[*nkeys] = key;
+ if (labelsp != NULL) {
+ *labelsp = xrecallocarray(*labelsp, *nkeys,
+ *nkeys + 1, sizeof(char *));
+ (*labelsp)[*nkeys] = xstrdup((char *)label);
+ }
*nkeys = *nkeys + 1;
debug("have %d keys", *nkeys);
}
@@ -1440,7 +1471,8 @@ pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
* keyp is provided, fetch keys.
*/
static int
-pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
+pkcs11_register_provider(char *provider_id, char *pin,
+ struct sshkey ***keyp, char ***labelsp,
struct pkcs11_provider **providerp, CK_ULONG user)
{
int nkeys, need_finalize = 0;
@@ -1459,6 +1491,8 @@ pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
if (keyp != NULL)
*keyp = NULL;
+ if (labelsp != NULL)
+ *labelsp = NULL;
if (pkcs11_provider_lookup(provider_id) != NULL) {
debug("%s: provider already registered: %s",
@@ -1556,8 +1590,8 @@ pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
keyp == NULL)
continue;
- pkcs11_fetch_keys(p, i, keyp, &nkeys);
- pkcs11_fetch_certs(p, i, keyp, &nkeys);
+ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
+ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
if (nkeys == 0 && !p->slotinfo[i].logged_in &&
pkcs11_interactive) {
/*
@@ -1569,8 +1603,8 @@ pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
error("login failed");
continue;
}
- pkcs11_fetch_keys(p, i, keyp, &nkeys);
- pkcs11_fetch_certs(p, i, keyp, &nkeys);
+ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
+ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
}
}
@@ -1601,12 +1635,14 @@ fail:
* fails if provider already exists
*/
int
-pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
+pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
+ char ***labelsp)
{
struct pkcs11_provider *p = NULL;
int nkeys;
- nkeys = pkcs11_register_provider(provider_id, pin, keyp, &p, CKU_USER);
+ nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
+ &p, CKU_USER);
/* no keys found or some other error, de-register provider */
if (nkeys <= 0 && p != NULL) {
@@ -1638,8 +1674,8 @@ pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
debug("%s: provider \"%s\" available", __func__, provider_id);
- else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, &p,
- CKU_SO)) < 0) {
+ else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
+ &p, CKU_SO)) < 0) {
debug("%s: could not register provider %s", __func__,
provider_id);
goto out;
@@ -1710,7 +1746,7 @@ pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
debug("%s: using provider \"%s\"", __func__, provider_id);
- } else if (pkcs11_register_provider(provider_id, pin, NULL, &p,
+ } else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
CKU_SO) < 0) {
debug("%s: could not register provider %s", __func__,
provider_id);