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
This commit is contained in:
parent
a8c05c6408
commit
89a8d4525e
19
ssh-agent.c
19
ssh-agent.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh-agent.c,v 1.252 2020/01/23 07:10:22 dtucker Exp $ */
|
/* $OpenBSD: ssh-agent.c,v 1.253 2020/01/25 00:03:36 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -633,6 +633,7 @@ static void
|
||||||
process_add_smartcard_key(SocketEntry *e)
|
process_add_smartcard_key(SocketEntry *e)
|
||||||
{
|
{
|
||||||
char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
|
char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
|
||||||
|
char **comments = NULL;
|
||||||
int r, i, count = 0, success = 0, confirm = 0;
|
int r, i, count = 0, success = 0, confirm = 0;
|
||||||
u_int seconds;
|
u_int seconds;
|
||||||
time_t death = 0;
|
time_t death = 0;
|
||||||
|
@ -682,28 +683,34 @@ process_add_smartcard_key(SocketEntry *e)
|
||||||
if (lifetime && !death)
|
if (lifetime && !death)
|
||||||
death = monotime() + lifetime;
|
death = monotime() + lifetime;
|
||||||
|
|
||||||
count = pkcs11_add_provider(canonical_provider, pin, &keys);
|
count = pkcs11_add_provider(canonical_provider, pin, &keys, &comments);
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
k = keys[i];
|
k = keys[i];
|
||||||
if (lookup_identity(k) == NULL) {
|
if (lookup_identity(k) == NULL) {
|
||||||
id = xcalloc(1, sizeof(Identity));
|
id = xcalloc(1, sizeof(Identity));
|
||||||
id->key = k;
|
id->key = k;
|
||||||
|
keys[i] = NULL; /* transferred */
|
||||||
id->provider = xstrdup(canonical_provider);
|
id->provider = xstrdup(canonical_provider);
|
||||||
id->comment = xstrdup(canonical_provider); /* XXX */
|
if (*comments[i] != '\0') {
|
||||||
|
id->comment = comments[i];
|
||||||
|
comments[i] = NULL; /* transferred */
|
||||||
|
} else {
|
||||||
|
id->comment = xstrdup(canonical_provider);
|
||||||
|
}
|
||||||
id->death = death;
|
id->death = death;
|
||||||
id->confirm = confirm;
|
id->confirm = confirm;
|
||||||
TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
|
TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
|
||||||
idtab->nentries++;
|
idtab->nentries++;
|
||||||
success = 1;
|
success = 1;
|
||||||
} else {
|
|
||||||
sshkey_free(k);
|
|
||||||
}
|
}
|
||||||
keys[i] = NULL;
|
sshkey_free(keys[i]);
|
||||||
|
free(comments[i]);
|
||||||
}
|
}
|
||||||
send:
|
send:
|
||||||
free(pin);
|
free(pin);
|
||||||
free(provider);
|
free(provider);
|
||||||
free(keys);
|
free(keys);
|
||||||
|
free(comments);
|
||||||
send_status(e, success);
|
send_status(e, success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
ssh-keygen.c
14
ssh-keygen.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh-keygen.c,v 1.391 2020/01/24 05:33:01 djm Exp $ */
|
/* $OpenBSD: ssh-keygen.c,v 1.392 2020/01/25 00:03:36 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -829,13 +829,13 @@ do_download(struct passwd *pw)
|
||||||
int i, nkeys;
|
int i, nkeys;
|
||||||
enum sshkey_fp_rep rep;
|
enum sshkey_fp_rep rep;
|
||||||
int fptype;
|
int fptype;
|
||||||
char *fp, *ra;
|
char *fp, *ra, **comments = NULL;
|
||||||
|
|
||||||
fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
|
fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
|
||||||
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
|
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
|
||||||
|
|
||||||
pkcs11_init(1);
|
pkcs11_init(1);
|
||||||
nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys);
|
nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys, &comments);
|
||||||
if (nkeys <= 0)
|
if (nkeys <= 0)
|
||||||
fatal("cannot read public key from pkcs11");
|
fatal("cannot read public key from pkcs11");
|
||||||
for (i = 0; i < nkeys; i++) {
|
for (i = 0; i < nkeys; i++) {
|
||||||
|
@ -853,10 +853,13 @@ do_download(struct passwd *pw)
|
||||||
free(fp);
|
free(fp);
|
||||||
} else {
|
} else {
|
||||||
(void) sshkey_write(keys[i], stdout); /* XXX check */
|
(void) sshkey_write(keys[i], stdout); /* XXX check */
|
||||||
fprintf(stdout, "\n");
|
fprintf(stdout, "%s%s\n",
|
||||||
|
*(comments[i]) == '\0' ? "" : " ", comments[i]);
|
||||||
}
|
}
|
||||||
|
free(comments[i]);
|
||||||
sshkey_free(keys[i]);
|
sshkey_free(keys[i]);
|
||||||
}
|
}
|
||||||
|
free(comments);
|
||||||
free(keys);
|
free(keys);
|
||||||
pkcs11_terminate();
|
pkcs11_terminate();
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -1703,7 +1706,8 @@ load_pkcs11_key(char *path)
|
||||||
fatal("Couldn't load CA public key \"%s\": %s",
|
fatal("Couldn't load CA public key \"%s\": %s",
|
||||||
path, ssh_err(r));
|
path, ssh_err(r));
|
||||||
|
|
||||||
nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys);
|
nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase,
|
||||||
|
&keys, NULL);
|
||||||
debug3("%s: %d keys", __func__, nkeys);
|
debug3("%s: %d keys", __func__, nkeys);
|
||||||
if (nkeys <= 0)
|
if (nkeys <= 0)
|
||||||
fatal("cannot read public key from pkcs11");
|
fatal("cannot read public key from pkcs11");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh-pkcs11-client.c,v 1.15 2019/01/21 12:53:35 djm Exp $ */
|
/* $OpenBSD: ssh-pkcs11-client.c,v 1.16 2020/01/25 00:03:36 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
||||||
* Copyright (c) 2014 Pedro Martelletto. All rights reserved.
|
* Copyright (c) 2014 Pedro Martelletto. All rights reserved.
|
||||||
|
@ -312,11 +312,13 @@ pkcs11_start_helper(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
|
pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
|
||||||
|
char ***labelsp)
|
||||||
{
|
{
|
||||||
struct sshkey *k;
|
struct sshkey *k;
|
||||||
int r, type;
|
int r, type;
|
||||||
u_char *blob;
|
u_char *blob;
|
||||||
|
char *label;
|
||||||
size_t blen;
|
size_t blen;
|
||||||
u_int nkeys, i;
|
u_int nkeys, i;
|
||||||
struct sshbuf *msg;
|
struct sshbuf *msg;
|
||||||
|
@ -338,16 +340,22 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
|
||||||
if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
|
if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
|
||||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
*keysp = xcalloc(nkeys, sizeof(struct sshkey *));
|
*keysp = xcalloc(nkeys, sizeof(struct sshkey *));
|
||||||
|
if (labelsp)
|
||||||
|
*labelsp = xcalloc(nkeys, sizeof(char *));
|
||||||
for (i = 0; i < nkeys; i++) {
|
for (i = 0; i < nkeys; i++) {
|
||||||
/* XXX clean up properly instead of fatal() */
|
/* XXX clean up properly instead of fatal() */
|
||||||
if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
|
if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
|
||||||
(r = sshbuf_skip_string(msg)) != 0)
|
(r = sshbuf_get_cstring(msg, &label, NULL)) != 0)
|
||||||
fatal("%s: buffer error: %s",
|
fatal("%s: buffer error: %s",
|
||||||
__func__, ssh_err(r));
|
__func__, ssh_err(r));
|
||||||
if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
|
if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
|
||||||
fatal("%s: bad key: %s", __func__, ssh_err(r));
|
fatal("%s: bad key: %s", __func__, ssh_err(r));
|
||||||
wrap_key(k);
|
wrap_key(k);
|
||||||
(*keysp)[i] = k;
|
(*keysp)[i] = k;
|
||||||
|
if (labelsp)
|
||||||
|
(*labelsp)[i] = label;
|
||||||
|
else
|
||||||
|
free(label);
|
||||||
free(blob);
|
free(blob);
|
||||||
}
|
}
|
||||||
} else if (type == SSH2_AGENT_FAILURE) {
|
} else if (type == SSH2_AGENT_FAILURE) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh-pkcs11-helper.c,v 1.21 2019/09/06 05:23:55 djm Exp $ */
|
/* $OpenBSD: ssh-pkcs11-helper.c,v 1.22 2020/01/25 00:03:36 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
struct pkcs11_keyinfo {
|
struct pkcs11_keyinfo {
|
||||||
struct sshkey *key;
|
struct sshkey *key;
|
||||||
char *providername;
|
char *providername, *label;
|
||||||
TAILQ_ENTRY(pkcs11_keyinfo) next;
|
TAILQ_ENTRY(pkcs11_keyinfo) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,13 +63,14 @@ struct sshbuf *iqueue;
|
||||||
struct sshbuf *oqueue;
|
struct sshbuf *oqueue;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_key(struct sshkey *k, char *name)
|
add_key(struct sshkey *k, char *name, char *label)
|
||||||
{
|
{
|
||||||
struct pkcs11_keyinfo *ki;
|
struct pkcs11_keyinfo *ki;
|
||||||
|
|
||||||
ki = xcalloc(1, sizeof(*ki));
|
ki = xcalloc(1, sizeof(*ki));
|
||||||
ki->providername = xstrdup(name);
|
ki->providername = xstrdup(name);
|
||||||
ki->key = k;
|
ki->key = k;
|
||||||
|
ki->label = xstrdup(label);
|
||||||
TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next);
|
TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +84,7 @@ del_keys_by_name(char *name)
|
||||||
if (!strcmp(ki->providername, name)) {
|
if (!strcmp(ki->providername, name)) {
|
||||||
TAILQ_REMOVE(&pkcs11_keylist, ki, next);
|
TAILQ_REMOVE(&pkcs11_keylist, ki, next);
|
||||||
free(ki->providername);
|
free(ki->providername);
|
||||||
|
free(ki->label);
|
||||||
sshkey_free(ki->key);
|
sshkey_free(ki->key);
|
||||||
free(ki);
|
free(ki);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,7 @@ lookup_key(struct sshkey *k)
|
||||||
struct pkcs11_keyinfo *ki;
|
struct pkcs11_keyinfo *ki;
|
||||||
|
|
||||||
TAILQ_FOREACH(ki, &pkcs11_keylist, next) {
|
TAILQ_FOREACH(ki, &pkcs11_keylist, next) {
|
||||||
debug("check %p %s", ki, ki->providername);
|
debug("check %p %s %s", ki, ki->providername, ki->label);
|
||||||
if (sshkey_equal(k, ki->key))
|
if (sshkey_equal(k, ki->key))
|
||||||
return (ki->key);
|
return (ki->key);
|
||||||
}
|
}
|
||||||
|
@ -121,13 +123,14 @@ process_add(void)
|
||||||
u_char *blob;
|
u_char *blob;
|
||||||
size_t blen;
|
size_t blen;
|
||||||
struct sshbuf *msg;
|
struct sshbuf *msg;
|
||||||
|
char **labels = NULL;
|
||||||
|
|
||||||
if ((msg = sshbuf_new()) == NULL)
|
if ((msg = sshbuf_new()) == NULL)
|
||||||
fatal("%s: sshbuf_new failed", __func__);
|
fatal("%s: sshbuf_new failed", __func__);
|
||||||
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
|
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
|
||||||
(r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0)
|
(r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0)
|
||||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) {
|
if ((nkeys = pkcs11_add_provider(name, pin, &keys, &labels)) > 0) {
|
||||||
if ((r = sshbuf_put_u8(msg,
|
if ((r = sshbuf_put_u8(msg,
|
||||||
SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
|
SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
|
||||||
(r = sshbuf_put_u32(msg, nkeys)) != 0)
|
(r = sshbuf_put_u32(msg, nkeys)) != 0)
|
||||||
|
@ -139,11 +142,12 @@ process_add(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((r = sshbuf_put_string(msg, blob, blen)) != 0 ||
|
if ((r = sshbuf_put_string(msg, blob, blen)) != 0 ||
|
||||||
(r = sshbuf_put_cstring(msg, name)) != 0)
|
(r = sshbuf_put_cstring(msg, labels[i])) != 0)
|
||||||
fatal("%s: buffer error: %s",
|
fatal("%s: buffer error: %s",
|
||||||
__func__, ssh_err(r));
|
__func__, ssh_err(r));
|
||||||
free(blob);
|
free(blob);
|
||||||
add_key(keys[i], name);
|
add_key(keys[i], name, labels[i]);
|
||||||
|
free(labels[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
|
if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
|
||||||
|
@ -151,7 +155,8 @@ process_add(void)
|
||||||
if ((r = sshbuf_put_u32(msg, -nkeys)) != 0)
|
if ((r = sshbuf_put_u32(msg, -nkeys)) != 0)
|
||||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
}
|
}
|
||||||
free(keys);
|
free(labels);
|
||||||
|
free(keys); /* keys themselves are transferred to pkcs11_keylist */
|
||||||
free(pin);
|
free(pin);
|
||||||
free(name);
|
free(name);
|
||||||
send_msg(msg);
|
send_msg(msg);
|
||||||
|
|
140
ssh-pkcs11.c
140
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) 2010 Markus Friedl. All rights reserved.
|
||||||
* Copyright (c) 2014 Pedro Martelletto. All rights reserved.
|
* Copyright (c) 2014 Pedro Martelletto. All rights reserved.
|
||||||
|
@ -893,15 +893,16 @@ fail:
|
||||||
return (key);
|
return (key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sshkey *
|
static int
|
||||||
pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
|
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_ATTRIBUTE cert_attr[3];
|
||||||
CK_SESSION_HANDLE session;
|
CK_SESSION_HANDLE session;
|
||||||
CK_FUNCTION_LIST *f = NULL;
|
CK_FUNCTION_LIST *f = NULL;
|
||||||
CK_RV rv;
|
CK_RV rv;
|
||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
|
X509_NAME *x509_name = NULL;
|
||||||
EVP_PKEY *evp;
|
EVP_PKEY *evp;
|
||||||
RSA *rsa = NULL;
|
RSA *rsa = NULL;
|
||||||
#ifdef OPENSSL_HAS_ECC
|
#ifdef OPENSSL_HAS_ECC
|
||||||
|
@ -913,6 +914,10 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
|
||||||
int nid;
|
int nid;
|
||||||
#endif
|
#endif
|
||||||
const u_char *cp;
|
const u_char *cp;
|
||||||
|
char *subject = NULL;
|
||||||
|
|
||||||
|
*keyp = NULL;
|
||||||
|
*labelp = NULL;
|
||||||
|
|
||||||
memset(&cert_attr, 0, sizeof(cert_attr));
|
memset(&cert_attr, 0, sizeof(cert_attr));
|
||||||
cert_attr[0].type = CKA_ID;
|
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);
|
rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
|
||||||
if (rv != CKR_OK) {
|
if (rv != CKR_OK) {
|
||||||
error("C_GetAttributeValue failed: %lu", rv);
|
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 ||
|
if (cert_attr[1].ulValueLen == 0 ||
|
||||||
cert_attr[2].ulValueLen == 0) {
|
cert_attr[2].ulValueLen == 0) {
|
||||||
error("invalid attribute length");
|
error("invalid attribute length");
|
||||||
return (NULL);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate buffers for attributes */
|
/* 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);
|
rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
|
||||||
if (rv != CKR_OK) {
|
if (rv != CKR_OK) {
|
||||||
error("C_GetAttributeValue failed: %lu", rv);
|
error("C_GetAttributeValue failed: %lu", rv);
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
x509 = X509_new();
|
/* Decode DER-encoded cert subject */
|
||||||
if (x509 == NULL) {
|
cp = cert_attr[2].pValue;
|
||||||
error("x509_new failed");
|
if ((x509_name = d2i_X509_NAME(NULL, &cp,
|
||||||
goto fail;
|
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;
|
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");
|
error("d2i_x509 failed");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
evp = X509_get_pubkey(x509);
|
if ((evp = X509_get_pubkey(x509)) == NULL) {
|
||||||
if (evp == NULL) {
|
|
||||||
error("X509_get_pubkey failed");
|
error("X509_get_pubkey failed");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
|
if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
|
||||||
if (EVP_PKEY_get0_RSA(evp) == NULL) {
|
if (EVP_PKEY_get0_RSA(evp) == NULL) {
|
||||||
error("invalid x509; no rsa key");
|
error("invalid x509; no rsa key");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
|
if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
|
||||||
error("RSAPublicKey_dup failed");
|
error("RSAPublicKey_dup failed");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
|
if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
|
||||||
goto fail;
|
goto out;
|
||||||
|
|
||||||
key = sshkey_new(KEY_UNSPEC);
|
key = sshkey_new(KEY_UNSPEC);
|
||||||
if (key == NULL) {
|
if (key == NULL) {
|
||||||
error("sshkey_new failed");
|
error("sshkey_new failed");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
key->rsa = rsa;
|
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) {
|
} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
|
||||||
if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
|
if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
|
||||||
error("invalid x509; no ec key");
|
error("invalid x509; no ec key");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
|
if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
|
||||||
error("EC_KEY_dup failed");
|
error("EC_KEY_dup failed");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
nid = sshkey_ecdsa_key_to_nid(ec);
|
nid = sshkey_ecdsa_key_to_nid(ec);
|
||||||
if (nid < 0) {
|
if (nid < 0) {
|
||||||
error("couldn't get curve nid");
|
error("couldn't get curve nid");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
|
if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
|
||||||
goto fail;
|
goto out;
|
||||||
|
|
||||||
key = sshkey_new(KEY_UNSPEC);
|
key = sshkey_new(KEY_UNSPEC);
|
||||||
if (key == NULL) {
|
if (key == NULL) {
|
||||||
error("sshkey_new failed");
|
error("sshkey_new failed");
|
||||||
goto fail;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
key->ecdsa = ec;
|
key->ecdsa = ec;
|
||||||
|
@ -1025,10 +1031,11 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
|
||||||
key->flags |= SSHKEY_FLAG_EXT;
|
key->flags |= SSHKEY_FLAG_EXT;
|
||||||
ec = NULL; /* now owned by key */
|
ec = NULL; /* now owned by key */
|
||||||
#endif /* HAVE_EC_KEY_METHOD_NEW */
|
#endif /* HAVE_EC_KEY_METHOD_NEW */
|
||||||
} else
|
} else {
|
||||||
error("unknown certificate key type");
|
error("unknown certificate key type");
|
||||||
|
goto out;
|
||||||
fail:
|
}
|
||||||
|
out:
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
free(cert_attr[i].pValue);
|
free(cert_attr[i].pValue);
|
||||||
X509_free(x509);
|
X509_free(x509);
|
||||||
|
@ -1036,8 +1043,14 @@ fail:
|
||||||
#ifdef OPENSSL_HAS_ECC
|
#ifdef OPENSSL_HAS_ECC
|
||||||
EC_KEY_free(ec);
|
EC_KEY_free(ec);
|
||||||
#endif
|
#endif
|
||||||
|
if (key == NULL) {
|
||||||
return (key);
|
free(subject);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* success */
|
||||||
|
*keyp = key;
|
||||||
|
*labelp = subject;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1058,7 +1071,7 @@ have_rsa_key(const RSA *rsa)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
|
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;
|
struct sshkey *key = NULL;
|
||||||
CK_OBJECT_CLASS key_class;
|
CK_OBJECT_CLASS key_class;
|
||||||
|
@ -1069,6 +1082,7 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
|
||||||
CK_OBJECT_HANDLE obj;
|
CK_OBJECT_HANDLE obj;
|
||||||
CK_ULONG n = 0;
|
CK_ULONG n = 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
char *label;
|
||||||
|
|
||||||
memset(&key_attr, 0, sizeof(key_attr));
|
memset(&key_attr, 0, sizeof(key_attr));
|
||||||
memset(&obj, 0, sizeof(obj));
|
memset(&obj, 0, sizeof(obj));
|
||||||
|
@ -1110,18 +1124,19 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key = NULL;
|
||||||
|
label = NULL;
|
||||||
switch (ck_cert_type) {
|
switch (ck_cert_type) {
|
||||||
case CKC_X_509:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
/* XXX print key type? */
|
error("skipping unsupported certificate type %lu",
|
||||||
key = NULL;
|
ck_cert_type);
|
||||||
error("skipping unsupported certificate type");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == NULL) {
|
|
||||||
error("failed to fetch key");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1132,6 +1147,11 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
|
||||||
*keysp = xrecallocarray(*keysp, *nkeys,
|
*keysp = xrecallocarray(*keysp, *nkeys,
|
||||||
*nkeys + 1, sizeof(struct sshkey *));
|
*nkeys + 1, sizeof(struct sshkey *));
|
||||||
(*keysp)[*nkeys] = key;
|
(*keysp)[*nkeys] = key;
|
||||||
|
if (labelsp != NULL) {
|
||||||
|
*labelsp = xrecallocarray(*labelsp, *nkeys,
|
||||||
|
*nkeys + 1, sizeof(char *));
|
||||||
|
(*labelsp)[*nkeys] = xstrdup((char *)label);
|
||||||
|
}
|
||||||
*nkeys = *nkeys + 1;
|
*nkeys = *nkeys + 1;
|
||||||
debug("have %d keys", *nkeys);
|
debug("have %d keys", *nkeys);
|
||||||
}
|
}
|
||||||
|
@ -1155,11 +1175,11 @@ fail:
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
|
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;
|
struct sshkey *key = NULL;
|
||||||
CK_OBJECT_CLASS key_class;
|
CK_OBJECT_CLASS key_class;
|
||||||
CK_ATTRIBUTE key_attr[1];
|
CK_ATTRIBUTE key_attr[2];
|
||||||
CK_SESSION_HANDLE session;
|
CK_SESSION_HANDLE session;
|
||||||
CK_FUNCTION_LIST *f = NULL;
|
CK_FUNCTION_LIST *f = NULL;
|
||||||
CK_RV rv;
|
CK_RV rv;
|
||||||
|
@ -1186,6 +1206,7 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
CK_KEY_TYPE ck_key_type;
|
CK_KEY_TYPE ck_key_type;
|
||||||
|
CK_UTF8CHAR label[256];
|
||||||
|
|
||||||
rv = f->C_FindObjects(session, &obj, 1, &n);
|
rv = f->C_FindObjects(session, &obj, 1, &n);
|
||||||
if (rv != CKR_OK) {
|
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].type = CKA_KEY_TYPE;
|
||||||
key_attr[0].pValue = &ck_key_type;
|
key_attr[0].pValue = &ck_key_type;
|
||||||
key_attr[0].ulValueLen = sizeof(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) {
|
if (rv != CKR_OK) {
|
||||||
error("C_GetAttributeValue failed: %lu", rv);
|
error("C_GetAttributeValue failed: %lu", rv);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label[key_attr[1].ulValueLen] = '\0';
|
||||||
|
|
||||||
switch (ck_key_type) {
|
switch (ck_key_type) {
|
||||||
case CKK_RSA:
|
case CKK_RSA:
|
||||||
key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
|
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,
|
*keysp = xrecallocarray(*keysp, *nkeys,
|
||||||
*nkeys + 1, sizeof(struct sshkey *));
|
*nkeys + 1, sizeof(struct sshkey *));
|
||||||
(*keysp)[*nkeys] = key;
|
(*keysp)[*nkeys] = key;
|
||||||
|
if (labelsp != NULL) {
|
||||||
|
*labelsp = xrecallocarray(*labelsp, *nkeys,
|
||||||
|
*nkeys + 1, sizeof(char *));
|
||||||
|
(*labelsp)[*nkeys] = xstrdup((char *)label);
|
||||||
|
}
|
||||||
*nkeys = *nkeys + 1;
|
*nkeys = *nkeys + 1;
|
||||||
debug("have %d keys", *nkeys);
|
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.
|
* keyp is provided, fetch keys.
|
||||||
*/
|
*/
|
||||||
static int
|
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)
|
struct pkcs11_provider **providerp, CK_ULONG user)
|
||||||
{
|
{
|
||||||
int nkeys, need_finalize = 0;
|
int nkeys, need_finalize = 0;
|
||||||
|
@ -1459,6 +1491,8 @@ pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
|
||||||
|
|
||||||
if (keyp != NULL)
|
if (keyp != NULL)
|
||||||
*keyp = NULL;
|
*keyp = NULL;
|
||||||
|
if (labelsp != NULL)
|
||||||
|
*labelsp = NULL;
|
||||||
|
|
||||||
if (pkcs11_provider_lookup(provider_id) != NULL) {
|
if (pkcs11_provider_lookup(provider_id) != NULL) {
|
||||||
debug("%s: provider already registered: %s",
|
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 ||
|
if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
|
||||||
keyp == NULL)
|
keyp == NULL)
|
||||||
continue;
|
continue;
|
||||||
pkcs11_fetch_keys(p, i, keyp, &nkeys);
|
pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
|
||||||
pkcs11_fetch_certs(p, i, keyp, &nkeys);
|
pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
|
||||||
if (nkeys == 0 && !p->slotinfo[i].logged_in &&
|
if (nkeys == 0 && !p->slotinfo[i].logged_in &&
|
||||||
pkcs11_interactive) {
|
pkcs11_interactive) {
|
||||||
/*
|
/*
|
||||||
|
@ -1569,8 +1603,8 @@ pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
|
||||||
error("login failed");
|
error("login failed");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pkcs11_fetch_keys(p, i, keyp, &nkeys);
|
pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
|
||||||
pkcs11_fetch_certs(p, i, keyp, &nkeys);
|
pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1601,12 +1635,14 @@ fail:
|
||||||
* fails if provider already exists
|
* fails if provider already exists
|
||||||
*/
|
*/
|
||||||
int
|
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;
|
struct pkcs11_provider *p = NULL;
|
||||||
int nkeys;
|
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 */
|
/* no keys found or some other error, de-register provider */
|
||||||
if (nkeys <= 0 && p != NULL) {
|
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)
|
if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
|
||||||
debug("%s: provider \"%s\" available", __func__, provider_id);
|
debug("%s: provider \"%s\" available", __func__, provider_id);
|
||||||
else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, &p,
|
else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
|
||||||
CKU_SO)) < 0) {
|
&p, CKU_SO)) < 0) {
|
||||||
debug("%s: could not register provider %s", __func__,
|
debug("%s: could not register provider %s", __func__,
|
||||||
provider_id);
|
provider_id);
|
||||||
goto out;
|
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) {
|
if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
|
||||||
debug("%s: using provider \"%s\"", __func__, provider_id);
|
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) {
|
CKU_SO) < 0) {
|
||||||
debug("%s: could not register provider %s", __func__,
|
debug("%s: could not register provider %s", __func__,
|
||||||
provider_id);
|
provider_id);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh-pkcs11.h,v 1.5 2019/01/20 22:51:37 djm Exp $ */
|
/* $OpenBSD: ssh-pkcs11.h,v 1.6 2020/01/25 00:03:36 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
* Copyright (c) 2010 Markus Friedl. All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
int pkcs11_init(int);
|
int pkcs11_init(int);
|
||||||
void pkcs11_terminate(void);
|
void pkcs11_terminate(void);
|
||||||
int pkcs11_add_provider(char *, char *, struct sshkey ***);
|
int pkcs11_add_provider(char *, char *, struct sshkey ***, char ***);
|
||||||
int pkcs11_del_provider(char *);
|
int pkcs11_del_provider(char *);
|
||||||
#ifdef WITH_PKCS11_KEYGEN
|
#ifdef WITH_PKCS11_KEYGEN
|
||||||
struct sshkey *
|
struct sshkey *
|
||||||
|
|
12
ssh.c
12
ssh.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: ssh.c,v 1.513 2020/01/23 10:24:29 dtucker Exp $ */
|
/* $OpenBSD: ssh.c,v 1.514 2020/01/25 00:03:36 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -2072,7 +2072,8 @@ load_public_identity_files(struct passwd *pw)
|
||||||
struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
|
struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
|
||||||
int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
|
int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
|
||||||
#ifdef ENABLE_PKCS11
|
#ifdef ENABLE_PKCS11
|
||||||
struct sshkey **keys;
|
struct sshkey **keys = NULL;
|
||||||
|
char **comments = NULL;
|
||||||
int nkeys;
|
int nkeys;
|
||||||
#endif /* PKCS11 */
|
#endif /* PKCS11 */
|
||||||
|
|
||||||
|
@ -2091,18 +2092,19 @@ load_public_identity_files(struct passwd *pw)
|
||||||
options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
|
options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
|
||||||
(pkcs11_init(!options.batch_mode) == 0) &&
|
(pkcs11_init(!options.batch_mode) == 0) &&
|
||||||
(nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
|
(nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
|
||||||
&keys)) > 0) {
|
&keys, &comments)) > 0) {
|
||||||
for (i = 0; i < nkeys; i++) {
|
for (i = 0; i < nkeys; i++) {
|
||||||
if (n_ids >= SSH_MAX_IDENTITY_FILES) {
|
if (n_ids >= SSH_MAX_IDENTITY_FILES) {
|
||||||
sshkey_free(keys[i]);
|
sshkey_free(keys[i]);
|
||||||
|
free(comments[i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
identity_keys[n_ids] = keys[i];
|
identity_keys[n_ids] = keys[i];
|
||||||
identity_files[n_ids] =
|
identity_files[n_ids] = comments[i]; /* transferred */
|
||||||
xstrdup(options.pkcs11_provider); /* XXX */
|
|
||||||
n_ids++;
|
n_ids++;
|
||||||
}
|
}
|
||||||
free(keys);
|
free(keys);
|
||||||
|
free(comments);
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_PKCS11 */
|
#endif /* ENABLE_PKCS11 */
|
||||||
for (i = 0; i < options.num_identity_files; i++) {
|
for (i = 0; i < options.num_identity_files; i++) {
|
||||||
|
|
Loading…
Reference in New Issue