summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-01-20 22:51:37 +0000
committerDamien Miller <djm@mindrot.org>2019-01-21 10:54:37 +1100
commit93f02107f44d63a016d8c23ebd2ca9205c495c48 (patch)
tree1d8d6ca8e146c9bd325614f33a59adf7199b40c9
parentaa22c20e0c36c2fc610cfcc793b0d14079c38814 (diff)
upstream: add support for ECDSA keys in PKCS#11 tokens
Work by markus@ and Pedro Martelletto, feedback and ok me@ OpenBSD-Commit-ID: a37d651e221341376636056512bddfc16efb4424
-rw-r--r--ssh-pkcs11-client.c103
-rw-r--r--ssh-pkcs11-helper.c40
-rw-r--r--ssh-pkcs11.c1374
-rw-r--r--ssh-pkcs11.h18
-rw-r--r--sshkey.h3
5 files changed, 1302 insertions, 236 deletions
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
index d1241ce67..6e16b2f9a 100644
--- a/ssh-pkcs11-client.c
+++ b/ssh-pkcs11-client.c
@@ -1,6 +1,7 @@
1/* $OpenBSD: ssh-pkcs11-client.c,v 1.10 2018/07/09 21:59:10 markus Exp $ */ 1/* $OpenBSD: ssh-pkcs11-client.c,v 1.12 2019/01/20 22:51:37 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
4 * 5 *
5 * Permission to use, copy, modify, and distribute this software for any 6 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
@@ -30,6 +31,7 @@
30#include <unistd.h> 31#include <unistd.h>
31#include <errno.h> 32#include <errno.h>
32 33
34#include <openssl/ecdsa.h>
33#include <openssl/rsa.h> 35#include <openssl/rsa.h>
34 36
35#include "openbsd-compat/openssl-compat.h" 37#include "openbsd-compat/openssl-compat.h"
@@ -113,8 +115,7 @@ pkcs11_terminate(void)
113} 115}
114 116
115static int 117static int
116pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 118rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
117 int padding)
118{ 119{
119 struct sshkey key; /* XXX */ 120 struct sshkey key; /* XXX */
120 u_char *blob, *signature = NULL; 121 u_char *blob, *signature = NULL;
@@ -154,18 +155,89 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
154 return (ret); 155 return (ret);
155} 156}
156 157
157/* redirect the private key encrypt operation to the ssh-pkcs11-helper */ 158static ECDSA_SIG *
159ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
160 const BIGNUM *rp, EC_KEY *ec)
161{
162 struct sshkey key; /* XXX */
163 u_char *blob, *signature = NULL;
164 const u_char *cp;
165 size_t blen, slen = 0;
166 ECDSA_SIG *ret = NULL;
167 struct sshbuf *msg;
168 int r;
169
170 key.type = KEY_ECDSA;
171 key.ecdsa = ec;
172 key.ecdsa_nid = sshkey_ecdsa_key_to_nid(ec);
173 if (key.ecdsa_nid < 0) {
174 error("%s: couldn't get curve nid", __func__);
175 return (NULL);
176 }
177 if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) {
178 error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
179 return (NULL);
180 }
181 if ((msg = sshbuf_new()) == NULL)
182 fatal("%s: sshbuf_new failed", __func__);
183 if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
184 (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
185 (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
186 (r = sshbuf_put_u32(msg, 0)) != 0)
187 fatal("%s: buffer error: %s", __func__, ssh_err(r));
188 free(blob);
189 send_msg(msg);
190 sshbuf_reset(msg);
191
192 if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
193 if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
194 fatal("%s: buffer error: %s", __func__, ssh_err(r));
195 cp = signature;
196 ret = d2i_ECDSA_SIG(NULL, &cp, slen);
197 free(signature);
198 }
199
200 sshbuf_free(msg);
201 return (ret);
202}
203
204static RSA_METHOD *helper_rsa;
205static EC_KEY_METHOD *helper_ecdsa;
206
207/* redirect private key crypto operations to the ssh-pkcs11-helper */
208static void
209wrap_key(struct sshkey *k)
210{
211 if (k->type == KEY_RSA)
212 RSA_set_method(k->rsa, helper_rsa);
213 else if (k->type == KEY_ECDSA)
214 EC_KEY_set_method(k->ecdsa, helper_ecdsa);
215 else
216 fatal("%s: unknown key type", __func__);
217}
218
158static int 219static int
159wrap_key(RSA *rsa) 220pkcs11_start_helper_methods(void)
160{ 221{
161 static RSA_METHOD *helper_rsa; 222 if (helper_ecdsa != NULL)
223 return (0);
224
225 int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
226 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
227 if (helper_ecdsa != NULL)
228 return (0);
229 helper_ecdsa = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
230 if (helper_ecdsa == NULL)
231 return (-1);
232 EC_KEY_METHOD_get_sign(helper_ecdsa, &orig_sign, NULL, NULL);
233 EC_KEY_METHOD_set_sign(helper_ecdsa, orig_sign, NULL, ecdsa_do_sign);
162 234
163 if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL) 235 if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL)
164 fatal("%s: RSA_meth_dup failed", __func__); 236 fatal("%s: RSA_meth_dup failed", __func__);
165 if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") || 237 if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") ||
166 !RSA_meth_set_priv_enc(helper_rsa, pkcs11_rsa_private_encrypt)) 238 !RSA_meth_set_priv_enc(helper_rsa, rsa_encrypt))
167 fatal("%s: failed to prepare method", __func__); 239 fatal("%s: failed to prepare method", __func__);
168 RSA_set_method(rsa, helper_rsa); 240
169 return (0); 241 return (0);
170} 242}
171 243
@@ -174,6 +246,11 @@ pkcs11_start_helper(void)
174{ 246{
175 int pair[2]; 247 int pair[2];
176 248
249 if (pkcs11_start_helper_methods() == -1) {
250 error("pkcs11_start_helper_methods failed");
251 return (-1);
252 }
253
177 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { 254 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
178 error("socketpair: %s", strerror(errno)); 255 error("socketpair: %s", strerror(errno));
179 return (-1); 256 return (-1);
@@ -204,7 +281,7 @@ int
204pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp) 281pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
205{ 282{
206 struct sshkey *k; 283 struct sshkey *k;
207 int r; 284 int r, type;
208 u_char *blob; 285 u_char *blob;
209 size_t blen; 286 size_t blen;
210 u_int nkeys, i; 287 u_int nkeys, i;
@@ -222,7 +299,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
222 send_msg(msg); 299 send_msg(msg);
223 sshbuf_reset(msg); 300 sshbuf_reset(msg);
224 301
225 if (recv_msg(msg) == SSH2_AGENT_IDENTITIES_ANSWER) { 302 type = recv_msg(msg);
303 if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
226 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) 304 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
227 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 305 fatal("%s: buffer error: %s", __func__, ssh_err(r));
228 *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); 306 *keysp = xcalloc(nkeys, sizeof(struct sshkey *));
@@ -234,10 +312,13 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
234 __func__, ssh_err(r)); 312 __func__, ssh_err(r));
235 if ((r = sshkey_from_blob(blob, blen, &k)) != 0) 313 if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
236 fatal("%s: bad key: %s", __func__, ssh_err(r)); 314 fatal("%s: bad key: %s", __func__, ssh_err(r));
237 wrap_key(k->rsa); 315 wrap_key(k);
238 (*keysp)[i] = k; 316 (*keysp)[i] = k;
239 free(blob); 317 free(blob);
240 } 318 }
319 } else if (type == SSH2_AGENT_FAILURE) {
320 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
321 nkeys = -1;
241 } else { 322 } else {
242 nkeys = -1; 323 nkeys = -1;
243 } 324 }
diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c
index 6301033c5..92c6728ba 100644
--- a/ssh-pkcs11-helper.c
+++ b/ssh-pkcs11-helper.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-pkcs11-helper.c,v 1.14 2018/01/08 15:18:46 markus Exp $ */ 1/* $OpenBSD: ssh-pkcs11-helper.c,v 1.15 2019/01/20 22:51:37 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * 4 *
@@ -110,7 +110,7 @@ static void
110process_add(void) 110process_add(void)
111{ 111{
112 char *name, *pin; 112 char *name, *pin;
113 struct sshkey **keys; 113 struct sshkey **keys = NULL;
114 int r, i, nkeys; 114 int r, i, nkeys;
115 u_char *blob; 115 u_char *blob;
116 size_t blen; 116 size_t blen;
@@ -139,11 +139,13 @@ process_add(void)
139 free(blob); 139 free(blob);
140 add_key(keys[i], name); 140 add_key(keys[i], name);
141 } 141 }
142 free(keys);
143 } else { 142 } else {
144 if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0) 143 if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0)
145 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 144 fatal("%s: buffer error: %s", __func__, ssh_err(r));
145 if ((r = sshbuf_put_u32(msg, -nkeys)) != 0)
146 fatal("%s: buffer error: %s", __func__, ssh_err(r));
146 } 147 }
148 free(keys);
147 free(pin); 149 free(pin);
148 free(name); 150 free(name);
149 send_msg(msg); 151 send_msg(msg);
@@ -192,15 +194,33 @@ process_sign(void)
192 else { 194 else {
193 if ((found = lookup_key(key)) != NULL) { 195 if ((found = lookup_key(key)) != NULL) {
194#ifdef WITH_OPENSSL 196#ifdef WITH_OPENSSL
197 u_int xslen;
195 int ret; 198 int ret;
196 199
197 slen = RSA_size(key->rsa); 200 if (key->type == KEY_RSA) {
198 signature = xmalloc(slen); 201 slen = RSA_size(key->rsa);
199 if ((ret = RSA_private_encrypt(dlen, data, signature, 202 signature = xmalloc(slen);
200 found->rsa, RSA_PKCS1_PADDING)) != -1) { 203 ret = RSA_private_encrypt(dlen, data, signature,
201 slen = ret; 204 found->rsa, RSA_PKCS1_PADDING);
202 ok = 0; 205 if (ret != -1) {
203 } 206 slen = ret;
207 ok = 0;
208 }
209 } else if (key->type == KEY_ECDSA) {
210 xslen = ECDSA_size(key->ecdsa);
211 signature = xmalloc(xslen);
212 /* "The parameter type is ignored." */
213 ret = ECDSA_sign(-1, data, dlen, signature,
214 &xslen, found->ecdsa);
215 if (ret != 0)
216 ok = 0;
217 else
218 error("%s: ECDSA_sign"
219 " returns %d", __func__, ret);
220 slen = xslen;
221 } else
222 error("%s: don't know how to sign with key "
223 "type %d", __func__, (int)key->type);
204#endif /* WITH_OPENSSL */ 224#endif /* WITH_OPENSSL */
205 } 225 }
206 sshkey_free(key); 226 sshkey_free(key);
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index 775de9642..01f968a9b 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -1,6 +1,7 @@
1/* $OpenBSD: ssh-pkcs11.c,v 1.26 2018/02/07 02:06:51 jsing Exp $ */ 1/* $OpenBSD: ssh-pkcs11.c,v 1.28 2019/01/20 22:51:37 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
4 * 5 *
5 * Permission to use, copy, modify, and distribute this software for any 6 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
@@ -19,20 +20,24 @@
19 20
20#ifdef ENABLE_PKCS11 21#ifdef ENABLE_PKCS11
21 22
22#include <sys/types.h>
23#ifdef HAVE_SYS_TIME_H 23#ifdef HAVE_SYS_TIME_H
24# include <sys/time.h> 24# include <sys/time.h>
25#endif 25#endif
26
27#include <sys/types.h>
26#include <stdarg.h> 28#include <stdarg.h>
27#include <stdio.h> 29#include <stdio.h>
28 30
31#include <ctype.h>
29#include <string.h> 32#include <string.h>
30#include <dlfcn.h> 33#include <dlfcn.h>
31 34
32#include "openbsd-compat/sys-queue.h" 35#include "openbsd-compat/sys-queue.h"
33#include "openbsd-compat/openssl-compat.h" 36#include "openbsd-compat/openssl-compat.h"
34 37
38#include <openssl/ecdsa.h>
35#include <openssl/x509.h> 39#include <openssl/x509.h>
40#include <openssl/err.h>
36 41
37#define CRYPTOKI_COMPAT 42#define CRYPTOKI_COMPAT
38#include "pkcs11.h" 43#include "pkcs11.h"
@@ -69,12 +74,25 @@ struct pkcs11_key {
69 CK_ULONG slotidx; 74 CK_ULONG slotidx;
70 int (*orig_finish)(RSA *rsa); 75 int (*orig_finish)(RSA *rsa);
71 RSA_METHOD *rsa_method; 76 RSA_METHOD *rsa_method;
77 EC_KEY_METHOD *ec_key_method;
72 char *keyid; 78 char *keyid;
73 int keyid_len; 79 int keyid_len;
74}; 80};
75 81
76int pkcs11_interactive = 0; 82int pkcs11_interactive = 0;
77 83
84#ifdef HAVE_DLOPEN
85static void
86ossl_error(const char *msg)
87{
88 unsigned long e;
89
90 while ((e = ERR_get_error()) != 0)
91 error("%s: %s: %.100s", __func__, msg,
92 ERR_error_string(e, NULL));
93}
94#endif
95
78int 96int
79pkcs11_init(int interactive) 97pkcs11_init(int interactive)
80{ 98{
@@ -84,9 +102,9 @@ pkcs11_init(int interactive)
84} 102}
85 103
86/* 104/*
87 * finalize a provider shared libarary, it's no longer usable. 105 * finalize a provider shared library, it's no longer usable.
88 * however, there might still be keys referencing this provider, 106 * however, there might still be keys referencing this provider,
89 * so the actuall freeing of memory is handled by pkcs11_provider_unref(). 107 * so the actual freeing of memory is handled by pkcs11_provider_unref().
90 * this is called when a provider gets unregistered. 108 * this is called when a provider gets unregistered.
91 */ 109 */
92static void 110static void
@@ -123,6 +141,7 @@ pkcs11_provider_unref(struct pkcs11_provider *p)
123 if (--p->refcount <= 0) { 141 if (--p->refcount <= 0) {
124 if (p->valid) 142 if (p->valid)
125 error("pkcs11_provider_unref: %p still valid", p); 143 error("pkcs11_provider_unref: %p still valid", p);
144 free(p->name);
126 free(p->slotlist); 145 free(p->slotlist);
127 free(p->slotinfo); 146 free(p->slotinfo);
128 free(p); 147 free(p);
@@ -218,43 +237,27 @@ pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
218 return (ret); 237 return (ret);
219} 238}
220 239
221/* openssl callback doing the actual signing operation */
222static int 240static int
223pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 241pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
224 int padding)
225{ 242{
226 struct pkcs11_key *k11;
227 struct pkcs11_slotinfo *si; 243 struct pkcs11_slotinfo *si;
228 CK_FUNCTION_LIST *f; 244 CK_FUNCTION_LIST *f;
229 CK_OBJECT_HANDLE obj; 245 CK_OBJECT_HANDLE obj;
230 CK_ULONG tlen = 0; 246 CK_RV rv;
231 CK_RV rv; 247 CK_OBJECT_CLASS private_key_class;
232 CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY; 248 CK_BBOOL true_val;
233 CK_BBOOL true_val = CK_TRUE; 249 CK_MECHANISM mech;
234 CK_MECHANISM mech = { 250 CK_ATTRIBUTE key_filter[3];
235 CKM_RSA_PKCS, NULL_PTR, 0
236 };
237 CK_ATTRIBUTE key_filter[] = {
238 {CKA_CLASS, NULL, sizeof(private_key_class) },
239 {CKA_ID, NULL, 0},
240 {CKA_SIGN, NULL, sizeof(true_val) }
241 };
242 char *pin = NULL, prompt[1024]; 251 char *pin = NULL, prompt[1024];
243 int rval = -1;
244
245 key_filter[0].pValue = &private_key_class;
246 key_filter[2].pValue = &true_val;
247 252
248 if ((k11 = RSA_get_app_data(rsa)) == NULL) {
249 error("RSA_get_app_data failed for rsa %p", rsa);
250 return (-1);
251 }
252 if (!k11->provider || !k11->provider->valid) { 253 if (!k11->provider || !k11->provider->valid) {
253 error("no pkcs11 (valid) provider for rsa %p", rsa); 254 error("no pkcs11 (valid) provider found");
254 return (-1); 255 return (-1);
255 } 256 }
257
256 f = k11->provider->function_list; 258 f = k11->provider->function_list;
257 si = &k11->provider->slotinfo[k11->slotidx]; 259 si = &k11->provider->slotinfo[k11->slotidx];
260
258 if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { 261 if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
259 if (!pkcs11_interactive) { 262 if (!pkcs11_interactive) {
260 error("need pin entry%s", (si->token.flags & 263 error("need pin entry%s", (si->token.flags &
@@ -283,23 +286,75 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
283 } 286 }
284 si->logged_in = 1; 287 si->logged_in = 1;
285 } 288 }
289
290 memset(&key_filter, 0, sizeof(key_filter));
291 private_key_class = CKO_PRIVATE_KEY;
292 key_filter[0].type = CKA_CLASS;
293 key_filter[0].pValue = &private_key_class;
294 key_filter[0].ulValueLen = sizeof(private_key_class);
295
296 key_filter[1].type = CKA_ID;
286 key_filter[1].pValue = k11->keyid; 297 key_filter[1].pValue = k11->keyid;
287 key_filter[1].ulValueLen = k11->keyid_len; 298 key_filter[1].ulValueLen = k11->keyid_len;
299
300 true_val = CK_TRUE;
301 key_filter[2].type = CKA_SIGN;
302 key_filter[2].pValue = &true_val;
303 key_filter[2].ulValueLen = sizeof(true_val);
304
288 /* try to find object w/CKA_SIGN first, retry w/o */ 305 /* try to find object w/CKA_SIGN first, retry w/o */
289 if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 && 306 if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
290 pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) { 307 pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
291 error("cannot find private key"); 308 error("cannot find private key");
292 } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) { 309 return (-1);
310 }
311
312 memset(&mech, 0, sizeof(mech));
313 mech.mechanism = mech_type;
314 mech.pParameter = NULL_PTR;
315 mech.ulParameterLen = 0;
316
317 if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
293 error("C_SignInit failed: %lu", rv); 318 error("C_SignInit failed: %lu", rv);
294 } else { 319 return (-1);
295 /* XXX handle CKR_BUFFER_TOO_SMALL */ 320 }
296 tlen = RSA_size(rsa); 321
297 rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen); 322 return (0);
298 if (rv == CKR_OK) 323}
299 rval = tlen; 324
300 else 325/* openssl callback doing the actual signing operation */
301 error("C_Sign failed: %lu", rv); 326static int
327pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
328 int padding)
329{
330 struct pkcs11_key *k11;
331 struct pkcs11_slotinfo *si;
332 CK_FUNCTION_LIST *f;
333 CK_ULONG tlen = 0;
334 CK_RV rv;
335 int rval = -1;
336
337 if ((k11 = RSA_get_app_data(rsa)) == NULL) {
338 error("RSA_get_app_data failed for rsa %p", rsa);
339 return (-1);
340 }
341
342 if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
343 error("pkcs11_get_key failed");
344 return (-1);
302 } 345 }
346
347 f = k11->provider->function_list;
348 si = &k11->provider->slotinfo[k11->slotidx];
349 tlen = RSA_size(rsa);
350
351 /* XXX handle CKR_BUFFER_TOO_SMALL */
352 rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
353 if (rv == CKR_OK)
354 rval = tlen;
355 else
356 error("C_Sign failed: %lu", rv);
357
303 return (rval); 358 return (rval);
304} 359}
305 360
@@ -344,6 +399,115 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
344 return (0); 399 return (0);
345} 400}
346 401
402/* openssl callback doing the actual signing operation */
403static ECDSA_SIG *
404ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
405 const BIGNUM *rp, EC_KEY *ec)
406{
407 struct pkcs11_key *k11;
408 struct pkcs11_slotinfo *si;
409 CK_FUNCTION_LIST *f;
410 CK_ULONG siglen = 0, bnlen;
411 CK_RV rv;
412 ECDSA_SIG *ret = NULL;
413 u_char *sig;
414 const u_char *cp;
415
416 if ((k11 = EC_KEY_get_ex_data(ec, 0)) == NULL) {
417 ossl_error("EC_KEY_get_key_method_data failed for ec");
418 return (NULL);
419 }
420
421 if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
422 error("pkcs11_get_key failed");
423 return (NULL);
424 }
425
426 f = k11->provider->function_list;
427 si = &k11->provider->slotinfo[k11->slotidx];
428
429 siglen = ECDSA_size(ec);
430 sig = xmalloc(siglen);
431
432 /* XXX handle CKR_BUFFER_TOO_SMALL */
433 rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
434 if (rv != CKR_OK) {
435 error("C_Sign failed: %lu", rv);
436 goto done;
437 }
438 cp = sig;
439 ret = d2i_ECDSA_SIG(NULL, &cp, siglen);
440 if (ret == NULL) {
441 /*
442 * d2i_ECDSA_SIG failed, so sig does not point to a DER-encoded
443 * sequence, but to the concatenation r|s.
444 */
445 if (siglen < 64 || siglen > 132 || siglen % 2) {
446 ossl_error("d2i_ECDSA_SIG failed");
447 goto done;
448 }
449 bnlen = siglen/2;
450 if ((ret = ECDSA_SIG_new()) == NULL) {
451 error("ECDSA_SIG_new failed");
452 goto done;
453 }
454 if (BN_bin2bn(sig, bnlen, ret->r) == NULL ||
455 BN_bin2bn(sig+bnlen, bnlen, ret->s) == NULL) {
456 ossl_error("d2i_ECDSA_SIG failed");
457 ECDSA_SIG_free(ret);
458 ret = NULL;
459 goto done;
460 }
461 }
462 done:
463 free(sig);
464
465 return (ret);
466}
467
468static EC_KEY_METHOD *ec_key_method;
469
470static int
471pkcs11_ecdsa_start_wrapper(void)
472{
473 int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
474 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
475
476 if (ec_key_method != NULL)
477 return (0);
478 ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
479 if (ec_key_method == NULL)
480 return (-1);
481 EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
482 EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
483 return (0);
484}
485
486static int
487pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
488 CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
489{
490 struct pkcs11_key *k11;
491
492 if (pkcs11_ecdsa_start_wrapper() == -1)
493 return (-1);
494
495 k11 = xcalloc(1, sizeof(*k11));
496 k11->provider = provider;
497 provider->refcount++; /* provider referenced by ECDSA key */
498 k11->slotidx = slotidx;
499 /* identify key object on smartcard */
500 k11->keyid_len = keyid_attrib->ulValueLen;
501 k11->keyid = xmalloc(k11->keyid_len);
502 memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
503 k11->ec_key_method = ec_key_method;
504
505 EC_KEY_set_method(ec, k11->ec_key_method);
506 EC_KEY_set_ex_data(ec, 0, k11);
507
508 return (0);
509}
510
347/* remove trailing spaces */ 511/* remove trailing spaces */
348static void 512static void
349rmspace(u_char *buf, size_t len) 513rmspace(u_char *buf, size_t len)
@@ -364,18 +528,19 @@ rmspace(u_char *buf, size_t len)
364 * if pin == NULL we delay login until key use 528 * if pin == NULL we delay login until key use
365 */ 529 */
366static int 530static int
367pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) 531pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
532 CK_ULONG user)
368{ 533{
369 CK_RV rv; 534 CK_RV rv;
370 CK_FUNCTION_LIST *f; 535 CK_FUNCTION_LIST *f;
371 CK_SESSION_HANDLE session; 536 CK_SESSION_HANDLE session;
372 int login_required; 537 int login_required, ret;
373 538
374 f = p->function_list; 539 f = p->function_list;
375 login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED; 540 login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
376 if (pin && login_required && !strlen(pin)) { 541 if (pin && login_required && !strlen(pin)) {
377 error("pin required"); 542 error("pin required");
378 return (-1); 543 return (-SSH_PKCS11_ERR_PIN_REQUIRED);
379 } 544 }
380 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| 545 if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
381 CKF_SERIAL_SESSION, NULL, NULL, &session)) 546 CKF_SERIAL_SESSION, NULL, NULL, &session))
@@ -384,13 +549,16 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin)
384 return (-1); 549 return (-1);
385 } 550 }
386 if (login_required && pin) { 551 if (login_required && pin) {
387 rv = f->C_Login(session, CKU_USER, 552 rv = f->C_Login(session, user,
388 (u_char *)pin, strlen(pin)); 553 (u_char *)pin, strlen(pin));
389 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) { 554 if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
390 error("C_Login failed: %lu", rv); 555 error("C_Login failed: %lu", rv);
556 ret = (rv == CKR_PIN_LOCKED) ?
557 -SSH_PKCS11_ERR_PIN_LOCKED :
558 -SSH_PKCS11_ERR_LOGIN_FAIL;
391 if ((rv = f->C_CloseSession(session)) != CKR_OK) 559 if ((rv = f->C_CloseSession(session)) != CKR_OK)
392 error("C_CloseSession failed: %lu", rv); 560 error("C_CloseSession failed: %lu", rv);
393 return (-1); 561 return (ret);
394 } 562 }
395 p->slotinfo[slotidx].logged_in = 1; 563 p->slotinfo[slotidx].logged_in = 1;
396 } 564 }
@@ -398,48 +566,6 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin)
398 return (0); 566 return (0);
399} 567}
400 568
401/*
402 * lookup public keys for token in slot identified by slotidx,
403 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
404 * keysp points to an (possibly empty) array with *nkeys keys.
405 */
406static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG,
407 CK_ATTRIBUTE [], CK_ATTRIBUTE [3], struct sshkey ***, int *)
408 __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE))));
409
410static int
411pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
412 struct sshkey ***keysp, int *nkeys)
413{
414 CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
415 CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
416 CK_ATTRIBUTE pubkey_filter[] = {
417 { CKA_CLASS, NULL, sizeof(pubkey_class) }
418 };
419 CK_ATTRIBUTE cert_filter[] = {
420 { CKA_CLASS, NULL, sizeof(cert_class) }
421 };
422 CK_ATTRIBUTE pubkey_attribs[] = {
423 { CKA_ID, NULL, 0 },
424 { CKA_MODULUS, NULL, 0 },
425 { CKA_PUBLIC_EXPONENT, NULL, 0 }
426 };
427 CK_ATTRIBUTE cert_attribs[] = {
428 { CKA_ID, NULL, 0 },
429 { CKA_SUBJECT, NULL, 0 },
430 { CKA_VALUE, NULL, 0 }
431 };
432 pubkey_filter[0].pValue = &pubkey_class;
433 cert_filter[0].pValue = &cert_class;
434
435 if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs,
436 keysp, nkeys) < 0 ||
437 pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs,
438 keysp, nkeys) < 0)
439 return (-1);
440 return (0);
441}
442
443static int 569static int
444pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key) 570pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
445{ 571{
@@ -451,6 +577,355 @@ pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
451 return (0); 577 return (0);
452} 578}
453 579
580static struct sshkey *
581pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
582 CK_OBJECT_HANDLE *obj)
583{
584 CK_ATTRIBUTE key_attr[3];
585 CK_SESSION_HANDLE session;
586 CK_FUNCTION_LIST *f = NULL;
587 CK_RV rv;
588 EC_KEY *ec = NULL;
589 EC_GROUP *group = NULL;
590 struct sshkey *key = NULL;
591 const unsigned char *attrp = NULL;
592 int i;
593 int nid;
594
595 memset(&key_attr, 0, sizeof(key_attr));
596 key_attr[0].type = CKA_ID;
597 key_attr[1].type = CKA_EC_POINT;
598 key_attr[2].type = CKA_EC_PARAMS;
599
600 session = p->slotinfo[slotidx].session;
601 f = p->function_list;
602
603 /* figure out size of the attributes */
604 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
605 if (rv != CKR_OK) {
606 error("C_GetAttributeValue failed: %lu", rv);
607 return (NULL);
608 }
609
610 /*
611 * Allow CKA_ID (always first attribute) to be empty, but
612 * ensure that none of the others are zero length.
613 * XXX assumes CKA_ID is always first.
614 */
615 if (key_attr[1].ulValueLen == 0 ||
616 key_attr[2].ulValueLen == 0) {
617 error("invalid attribute length");
618 return (NULL);
619 }
620
621 /* allocate buffers for attributes */
622 for (i = 0; i < 3; i++)
623 if (key_attr[i].ulValueLen > 0)
624 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
625
626 /* retrieve ID, public point and curve parameters of EC key */
627 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
628 if (rv != CKR_OK) {
629 error("C_GetAttributeValue failed: %lu", rv);
630 goto fail;
631 }
632
633 ec = EC_KEY_new();
634 if (ec == NULL) {
635 error("EC_KEY_new failed");
636 goto fail;
637 }
638
639 attrp = key_attr[2].pValue;
640 group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
641 if (group == NULL) {
642 ossl_error("d2i_ECPKParameters failed");
643 goto fail;
644 }
645
646 if (EC_KEY_set_group(ec, group) == 0) {
647 ossl_error("EC_KEY_set_group failed");
648 goto fail;
649 }
650
651 if (key_attr[1].ulValueLen <= 2) {
652 error("CKA_EC_POINT too small");
653 goto fail;
654 }
655
656 attrp = (const unsigned char *)key_attr[1].pValue;
657 if (o2i_ECPublicKey(&ec, &attrp, key_attr[1].ulValueLen) == NULL) {
658 /* try to skip DER header (octet string type and length byte) */
659 attrp = (const unsigned char *)key_attr[1].pValue + 2;
660 if (o2i_ECPublicKey(&ec, &attrp, key_attr[1].ulValueLen - 2)
661 == NULL) {
662 ossl_error("o2i_ECPublicKey failed");
663 goto fail;
664 }
665 }
666
667 nid = sshkey_ecdsa_key_to_nid(ec);
668 if (nid < 0) {
669 error("couldn't get curve nid");
670 goto fail;
671 }
672
673 if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
674 goto fail;
675
676 key = sshkey_new(KEY_UNSPEC);
677 if (key == NULL) {
678 error("sshkey_new failed");
679 goto fail;
680 }
681
682 key->ecdsa = ec;
683 key->ecdsa_nid = nid;
684 key->type = KEY_ECDSA;
685 key->flags |= SSHKEY_FLAG_EXT;
686 ec = NULL; /* now owned by key */
687
688fail:
689 for (i = 0; i < 3; i++)
690 free(key_attr[i].pValue);
691 if (ec)
692 EC_KEY_free(ec);
693 if (group)
694 EC_GROUP_free(group);
695
696 return (key);
697}
698
699static struct sshkey *
700pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
701 CK_OBJECT_HANDLE *obj)
702{
703 CK_ATTRIBUTE key_attr[3];
704 CK_SESSION_HANDLE session;
705 CK_FUNCTION_LIST *f = NULL;
706 CK_RV rv;
707 RSA *rsa = NULL;
708 BIGNUM *rsa_n, *rsa_e;
709 struct sshkey *key = NULL;
710 int i;
711
712 memset(&key_attr, 0, sizeof(key_attr));
713 key_attr[0].type = CKA_ID;
714 key_attr[1].type = CKA_MODULUS;
715 key_attr[2].type = CKA_PUBLIC_EXPONENT;
716
717 session = p->slotinfo[slotidx].session;
718 f = p->function_list;
719
720 /* figure out size of the attributes */
721 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
722 if (rv != CKR_OK) {
723 error("C_GetAttributeValue failed: %lu", rv);
724 return (NULL);
725 }
726
727 /*
728 * Allow CKA_ID (always first attribute) to be empty, but
729 * ensure that none of the others are zero length.
730 * XXX assumes CKA_ID is always first.
731 */
732 if (key_attr[1].ulValueLen == 0 ||
733 key_attr[2].ulValueLen == 0) {
734 error("invalid attribute length");
735 return (NULL);
736 }
737
738 /* allocate buffers for attributes */
739 for (i = 0; i < 3; i++)
740 if (key_attr[i].ulValueLen > 0)
741 key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
742
743 /* retrieve ID, modulus and public exponent of RSA key */
744 rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
745 if (rv != CKR_OK) {
746 error("C_GetAttributeValue failed: %lu", rv);
747 goto fail;
748 }
749
750 rsa = RSA_new();
751 if (rsa == NULL) {
752 error("RSA_new failed");
753 goto fail;
754 }
755
756 rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
757 rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
758 if (rsa_n == NULL || rsa_e == NULL) {
759 error("BN_bin2bn failed");
760 goto fail;
761 }
762 if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
763 fatal("%s: set key", __func__);
764 rsa_n = rsa_e = NULL; /* transferred */
765
766 if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
767 goto fail;
768
769 key = sshkey_new(KEY_UNSPEC);
770 if (key == NULL) {
771 error("sshkey_new failed");
772 goto fail;
773 }
774
775 key->rsa = rsa;
776 key->type = KEY_RSA;
777 key->flags |= SSHKEY_FLAG_EXT;
778 rsa = NULL; /* now owned by key */
779
780fail:
781 for (i = 0; i < 3; i++)
782 free(key_attr[i].pValue);
783 RSA_free(rsa);
784
785 return (key);
786}
787
788static struct sshkey *
789pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
790 CK_OBJECT_HANDLE *obj)
791{
792 CK_ATTRIBUTE cert_attr[3];
793 CK_SESSION_HANDLE session;
794 CK_FUNCTION_LIST *f = NULL;
795 CK_RV rv;
796 X509 *x509 = NULL;
797 EVP_PKEY *evp;
798 RSA *rsa = NULL;
799 EC_KEY *ec = NULL;
800 struct sshkey *key = NULL;
801 int i;
802 int nid;
803 const u_char *cp;
804
805 memset(&cert_attr, 0, sizeof(cert_attr));
806 cert_attr[0].type = CKA_ID;
807 cert_attr[1].type = CKA_SUBJECT;
808 cert_attr[2].type = CKA_VALUE;
809
810 session = p->slotinfo[slotidx].session;
811 f = p->function_list;
812
813 /* figure out size of the attributes */
814 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
815 if (rv != CKR_OK) {
816 error("C_GetAttributeValue failed: %lu", rv);
817 return (NULL);
818 }
819
820 /*
821 * Allow CKA_ID (always first attribute) to be empty, but
822 * ensure that none of the others are zero length.
823 * XXX assumes CKA_ID is always first.
824 */
825 if (cert_attr[1].ulValueLen == 0 ||
826 cert_attr[2].ulValueLen == 0) {
827 error("invalid attribute length");
828 return (NULL);
829 }
830
831 /* allocate buffers for attributes */
832 for (i = 0; i < 3; i++)
833 if (cert_attr[i].ulValueLen > 0)
834 cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
835
836 /* retrieve ID, subject and value of certificate */
837 rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
838 if (rv != CKR_OK) {
839 error("C_GetAttributeValue failed: %lu", rv);
840 goto fail;
841 }
842
843 x509 = X509_new();
844 if (x509 == NULL) {
845 error("x509_new failed");
846 goto fail;
847 }
848
849 cp = cert_attr[2].pValue;
850 if (d2i_X509(&x509, &cp, cert_attr[2].ulValueLen) == NULL) {
851 error("d2i_x509 failed");
852 goto fail;
853 }
854
855 evp = X509_get_pubkey(x509);
856 if (evp == NULL) {
857 error("X509_get_pubkey failed");
858 goto fail;
859 }
860
861 if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
862 if (EVP_PKEY_get0_RSA(evp) == NULL) {
863 error("invalid x509; no rsa key");
864 goto fail;
865 }
866 if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
867 error("RSAPublicKey_dup failed");
868 goto fail;
869 }
870
871 if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
872 goto fail;
873
874 key = sshkey_new(KEY_UNSPEC);
875 if (key == NULL) {
876 error("sshkey_new failed");
877 goto fail;
878 }
879
880 key->rsa = rsa;
881 key->type = KEY_RSA;
882 key->flags |= SSHKEY_FLAG_EXT;
883 rsa = NULL; /* now owned by key */
884 } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
885 /* XXX XXX fix accessor */
886 if (evp->pkey.ec == NULL) {
887 error("invalid x509; no ec key");
888 goto fail;
889 }
890 if ((ec = EC_KEY_dup(evp->pkey.ec)) == NULL) {
891 error("EC_KEY_dup failed");
892 goto fail;
893 }
894
895 nid = sshkey_ecdsa_key_to_nid(ec);
896 if (nid < 0) {
897 error("couldn't get curve nid");
898 goto fail;
899 }
900
901 if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
902 goto fail;
903
904 key = sshkey_new(KEY_UNSPEC);
905 if (key == NULL) {
906 error("sshkey_new failed");
907 goto fail;
908 }
909
910 key->ecdsa = ec;
911 key->ecdsa_nid = nid;
912 key->type = KEY_ECDSA;
913 key->flags |= SSHKEY_FLAG_EXT;
914 ec = NULL; /* now owned by key */
915 } else
916 error("unknown certificate key type");
917
918fail:
919 for (i = 0; i < 3; i++)
920 free(cert_attr[i].pValue);
921 X509_free(x509);
922 RSA_free(rsa);
923 EC_KEY_free(ec);
924
925 return (key);
926}
927
928#if 0
454static int 929static int
455have_rsa_key(const RSA *rsa) 930have_rsa_key(const RSA *rsa)
456{ 931{
@@ -459,140 +934,398 @@ have_rsa_key(const RSA *rsa)
459 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL); 934 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
460 return rsa_n != NULL && rsa_e != NULL; 935 return rsa_n != NULL && rsa_e != NULL;
461} 936}
937#endif
462 938
939/*
940 * lookup certificates for token in slot identified by slotidx,
941 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
942 * keysp points to an (possibly empty) array with *nkeys keys.
943 */
463static int 944static int
464pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, 945pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
465 CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3],
466 struct sshkey ***keysp, int *nkeys) 946 struct sshkey ***keysp, int *nkeys)
467{ 947{
468 struct sshkey *key; 948 struct sshkey *key = NULL;
469 RSA *rsa; 949 CK_OBJECT_CLASS key_class;
470 X509 *x509; 950 CK_ATTRIBUTE key_attr[1];
471 EVP_PKEY *evp; 951 CK_SESSION_HANDLE session;
472 int i; 952 CK_FUNCTION_LIST *f = NULL;
473 const u_char *cp; 953 CK_RV rv;
474 CK_RV rv; 954 CK_OBJECT_HANDLE obj;
475 CK_OBJECT_HANDLE obj; 955 CK_ULONG n = 0;
476 CK_ULONG nfound; 956 int ret = -1;
477 CK_SESSION_HANDLE session; 957
478 CK_FUNCTION_LIST *f; 958 memset(&key_attr, 0, sizeof(key_attr));
959 memset(&obj, 0, sizeof(obj));
960
961 key_class = CKO_CERTIFICATE;
962 key_attr[0].type = CKA_CLASS;
963 key_attr[0].pValue = &key_class;
964 key_attr[0].ulValueLen = sizeof(key_class);
479 965
480 f = p->function_list;
481 session = p->slotinfo[slotidx].session; 966 session = p->slotinfo[slotidx].session;
482 /* setup a filter the looks for public keys */ 967 f = p->function_list;
483 if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) { 968
969 rv = f->C_FindObjectsInit(session, key_attr, 1);
970 if (rv != CKR_OK) {
484 error("C_FindObjectsInit failed: %lu", rv); 971 error("C_FindObjectsInit failed: %lu", rv);
485 return (-1); 972 goto fail;
486 } 973 }
974
487 while (1) { 975 while (1) {
488 /* XXX 3 attributes in attribs[] */ 976 CK_CERTIFICATE_TYPE ck_cert_type;
489 for (i = 0; i < 3; i++) { 977
490 attribs[i].pValue = NULL; 978 rv = f->C_FindObjects(session, &obj, 1, &n);
491 attribs[i].ulValueLen = 0; 979 if (rv != CKR_OK) {
980 error("C_FindObjects failed: %lu", rv);
981 goto fail;
492 } 982 }
493 if ((rv = f->C_FindObjects(session, &obj, 1, &nfound)) != CKR_OK 983 if (n == 0)
494 || nfound == 0)
495 break; 984 break;
496 /* found a key, so figure out size of the attributes */ 985
497 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) 986 memset(&ck_cert_type, 0, sizeof(ck_cert_type));
498 != CKR_OK) { 987 memset(&key_attr, 0, sizeof(key_attr));
988 key_attr[0].type = CKA_CERTIFICATE_TYPE;
989 key_attr[0].pValue = &ck_cert_type;
990 key_attr[0].ulValueLen = sizeof(ck_cert_type);
991
992 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
993 if (rv != CKR_OK) {
499 error("C_GetAttributeValue failed: %lu", rv); 994 error("C_GetAttributeValue failed: %lu", rv);
500 continue; 995 goto fail;
501 } 996 }
502 /* 997
503 * Allow CKA_ID (always first attribute) to be empty, but 998 switch (ck_cert_type) {
504 * ensure that none of the others are zero length. 999 case CKC_X_509:
505 * XXX assumes CKA_ID is always first. 1000 key = pkcs11_fetch_x509_pubkey(p, slotidx, &obj);
506 */ 1001 break;
507 if (attribs[1].ulValueLen == 0 || 1002 default:
508 attribs[2].ulValueLen == 0) { 1003 /* XXX print key type? */
1004 error("skipping unsupported certificate type");
1005 }
1006
1007 if (key == NULL) {
1008 error("failed to fetch key");
509 continue; 1009 continue;
510 } 1010 }
511 /* allocate buffers for attributes */ 1011
512 for (i = 0; i < 3; i++) { 1012 if (pkcs11_key_included(keysp, nkeys, key)) {
513 if (attribs[i].ulValueLen > 0) { 1013 sshkey_free(key);
514 attribs[i].pValue = xmalloc( 1014 } else {
515 attribs[i].ulValueLen); 1015 /* expand key array and add key */
516 } 1016 *keysp = xrecallocarray(*keysp, *nkeys,
1017 *nkeys + 1, sizeof(struct sshkey *));
1018 (*keysp)[*nkeys] = key;
1019 *nkeys = *nkeys + 1;
1020 debug("have %d keys", *nkeys);
517 } 1021 }
1022 }
518 1023
519 /* 1024 ret = 0;
520 * retrieve ID, modulus and public exponent of RSA key, 1025fail:
521 * or ID, subject and value for certificates. 1026 rv = f->C_FindObjectsFinal(session);
522 */ 1027 if (rv != CKR_OK) {
523 rsa = NULL; 1028 error("C_FindObjectsFinal failed: %lu", rv);
524 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) 1029 ret = -1;
525 != CKR_OK) { 1030 }
1031
1032 return (ret);
1033}
1034
1035/*
1036 * lookup public keys for token in slot identified by slotidx,
1037 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1038 * keysp points to an (possibly empty) array with *nkeys keys.
1039 */
1040static int
1041pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1042 struct sshkey ***keysp, int *nkeys)
1043{
1044 struct sshkey *key = NULL;
1045 CK_OBJECT_CLASS key_class;
1046 CK_ATTRIBUTE key_attr[1];
1047 CK_SESSION_HANDLE session;
1048 CK_FUNCTION_LIST *f = NULL;
1049 CK_RV rv;
1050 CK_OBJECT_HANDLE obj;
1051 CK_ULONG n = 0;
1052 int ret = -1;
1053
1054 memset(&key_attr, 0, sizeof(key_attr));
1055 memset(&obj, 0, sizeof(obj));
1056
1057 key_class = CKO_PUBLIC_KEY;
1058 key_attr[0].type = CKA_CLASS;
1059 key_attr[0].pValue = &key_class;
1060 key_attr[0].ulValueLen = sizeof(key_class);
1061
1062 session = p->slotinfo[slotidx].session;
1063 f = p->function_list;
1064
1065 rv = f->C_FindObjectsInit(session, key_attr, 1);
1066 if (rv != CKR_OK) {
1067 error("C_FindObjectsInit failed: %lu", rv);
1068 goto fail;
1069 }
1070
1071 while (1) {
1072 CK_KEY_TYPE ck_key_type;
1073
1074 rv = f->C_FindObjects(session, &obj, 1, &n);
1075 if (rv != CKR_OK) {
1076 error("C_FindObjects failed: %lu", rv);
1077 goto fail;
1078 }
1079 if (n == 0)
1080 break;
1081
1082 memset(&ck_key_type, 0, sizeof(ck_key_type));
1083 memset(&key_attr, 0, sizeof(key_attr));
1084 key_attr[0].type = CKA_KEY_TYPE;
1085 key_attr[0].pValue = &ck_key_type;
1086 key_attr[0].ulValueLen = sizeof(ck_key_type);
1087
1088 rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1089 if (rv != CKR_OK) {
526 error("C_GetAttributeValue failed: %lu", rv); 1090 error("C_GetAttributeValue failed: %lu", rv);
527 } else if (attribs[1].type == CKA_MODULUS ) { 1091 goto fail;
528 if ((rsa = RSA_new()) == NULL) { 1092 }
529 error("RSA_new failed"); 1093
530 } else { 1094 switch (ck_key_type) {
531 BIGNUM *rsa_n, *rsa_e; 1095 case CKK_RSA:
532 1096 key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
533 rsa_n = BN_bin2bn(attribs[1].pValue, 1097 break;
534 attribs[1].ulValueLen, NULL); 1098 case CKK_ECDSA:
535 rsa_e = BN_bin2bn(attribs[2].pValue, 1099 key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
536 attribs[2].ulValueLen, NULL); 1100 break;
537 if (rsa_n != NULL && rsa_e != NULL) { 1101 default:
538 if (!RSA_set0_key(rsa, 1102 /* XXX print key type? */
539 rsa_n, rsa_e, NULL)) 1103 error("skipping unsupported key type");
540 fatal("%s: set key", __func__); 1104 }
541 rsa_n = rsa_e = NULL; /* transferred */ 1105
542 } 1106 if (key == NULL) {
543 BN_free(rsa_n); 1107 error("failed to fetch key");
544 BN_free(rsa_e); 1108 continue;
545 } 1109 }
1110
1111 if (pkcs11_key_included(keysp, nkeys, key)) {
1112 sshkey_free(key);
546 } else { 1113 } else {
547 cp = attribs[2].pValue; 1114 /* expand key array and add key */
548 if ((x509 = X509_new()) == NULL) { 1115 *keysp = xrecallocarray(*keysp, *nkeys,
549 error("X509_new failed"); 1116 *nkeys + 1, sizeof(struct sshkey *));
550 } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen) 1117 (*keysp)[*nkeys] = key;
551 == NULL) { 1118 *nkeys = *nkeys + 1;
552 error("d2i_X509 failed"); 1119 debug("have %d keys", *nkeys);
553 } else if ((evp = X509_get_pubkey(x509)) == NULL || 1120 }
554 EVP_PKEY_base_id(evp) != EVP_PKEY_RSA ||
555 EVP_PKEY_get0_RSA(evp) == NULL) {
556 debug("X509_get_pubkey failed or no rsa");
557 } else if ((rsa = RSAPublicKey_dup(
558 EVP_PKEY_get0_RSA(evp))) == NULL) {
559 error("RSAPublicKey_dup");
560 }
561 X509_free(x509);
562 }
563 if (rsa && have_rsa_key(rsa) &&
564 pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
565 if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
566 fatal("sshkey_new failed");
567 key->rsa = rsa;
568 key->type = KEY_RSA;
569 key->flags |= SSHKEY_FLAG_EXT;
570 if (pkcs11_key_included(keysp, nkeys, key)) {
571 sshkey_free(key);
572 } else {
573 /* expand key array and add key */
574 *keysp = xrecallocarray(*keysp, *nkeys,
575 *nkeys + 1, sizeof(struct sshkey *));
576 (*keysp)[*nkeys] = key;
577 *nkeys = *nkeys + 1;
578 debug("have %d keys", *nkeys);
579 }
580 } else if (rsa) {
581 RSA_free(rsa);
582 }
583 for (i = 0; i < 3; i++)
584 free(attribs[i].pValue);
585 } 1121 }
586 if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) 1122
1123 ret = 0;
1124fail:
1125 rv = f->C_FindObjectsFinal(session);
1126 if (rv != CKR_OK) {
587 error("C_FindObjectsFinal failed: %lu", rv); 1127 error("C_FindObjectsFinal failed: %lu", rv);
588 return (0); 1128 ret = -1;
1129 }
1130
1131 return (ret);
589} 1132}
590 1133
591/* register a new provider, fails if provider already exists */ 1134#ifdef WITH_PKCS11_KEYGEN
592int 1135#define FILL_ATTR(attr, idx, typ, val, len) \
593pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) 1136 { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1137
1138static struct sshkey *
1139pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1140 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1141{
1142 struct pkcs11_slotinfo *si;
1143 char *plabel = label ? label : "";
1144 int npub = 0, npriv = 0;
1145 CK_RV rv;
1146 CK_FUNCTION_LIST *f;
1147 CK_SESSION_HANDLE session;
1148 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1149 CK_OBJECT_HANDLE pubKey, privKey;
1150 CK_ATTRIBUTE tpub[16], tpriv[16];
1151 CK_MECHANISM mech = {
1152 CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1153 };
1154 CK_BYTE pubExponent[] = {
1155 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1156 };
1157 pubkey_filter[0].pValue = &pubkey_class;
1158 cert_filter[0].pValue = &cert_class;
1159
1160 *err = 0;
1161
1162 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1163 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1164 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1165 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1166 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1167 sizeof(false_val));
1168 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1169 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1170 FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1171 FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1172 sizeof(pubExponent));
1173 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1174
1175 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1176 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1177 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1178 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1179 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1180 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1181 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1182 sizeof(false_val));
1183 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1184 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1185 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1186
1187 f = p->function_list;
1188 si = &p->slotinfo[slotidx];
1189 session = si->session;
1190
1191 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1192 &pubKey, &privKey)) != CKR_OK) {
1193 error("%s: key generation failed: error 0x%lx", __func__, rv);
1194 *err = rv;
1195 return NULL;
1196 }
1197
1198 return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1199}
1200
1201static int
1202pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1203{
1204 size_t i, len;
1205 char ptr[3];
1206
1207 if (dest)
1208 *dest = NULL;
1209 if (rlen)
1210 *rlen = 0;
1211
1212 if ((len = strlen(hex)) % 2)
1213 return -1;
1214 len /= 2;
1215
1216 *dest = xmalloc(len);
1217
1218 ptr[2] = '\0';
1219 for (i = 0; i < len; i++) {
1220 ptr[0] = hex[2 * i];
1221 ptr[1] = hex[(2 * i) + 1];
1222 if (!isxdigit(ptr[0]) || !isxdigit(ptr[1]))
1223 return -1;
1224 (*dest)[i] = (unsigned char)strtoul(ptr, NULL, 16);
1225 }
1226
1227 if (rlen)
1228 *rlen = len;
1229
1230 return 0;
1231}
1232
1233static struct ec_curve_info {
1234 const char *name;
1235 const char *oid;
1236 const char *oid_encoded;
1237 size_t size;
1238} ec_curve_infos[] = {
1239 {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1240 {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1241 {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1242 {NULL, NULL, NULL, 0},
1243};
1244
1245static struct sshkey *
1246pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1247 char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1248{
1249 struct pkcs11_slotinfo *si;
1250 char *plabel = label ? label : "";
1251 int i;
1252 size_t ecparams_size;
1253 unsigned char *ecparams = NULL;
1254 int npub = 0, npriv = 0;
1255 CK_RV rv;
1256 CK_FUNCTION_LIST *f;
1257 CK_SESSION_HANDLE session;
1258 CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1259 CK_OBJECT_HANDLE pubKey, privKey;
1260 CK_MECHANISM mech = {
1261 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1262 };
1263 CK_ATTRIBUTE tpub[16], tpriv[16];
1264
1265 *err = 0;
1266
1267 for (i = 0; ec_curve_infos[i].name; i++) {
1268 if (ec_curve_infos[i].size == bits)
1269 break;
1270 }
1271 if (!ec_curve_infos[i].name) {
1272 error("%s: invalid key size %lu", __func__, bits);
1273 return NULL;
1274 }
1275 if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1276 &ecparams_size) == -1) {
1277 error("%s: invalid oid", __func__);
1278 return NULL;
1279 }
1280
1281 FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1282 FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1283 FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1284 FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1285 FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1286 sizeof(false_val));
1287 FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1288 FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1289 FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1290 FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1291
1292 FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1293 FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1294 FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1295 FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1296 FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1297 FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1298 FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1299 sizeof(false_val));
1300 FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1301 FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1302 FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1303
1304 f = p->function_list;
1305 si = &p->slotinfo[slotidx];
1306 session = si->session;
1307
1308 if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1309 &pubKey, &privKey)) != CKR_OK) {
1310 error("%s: key generation failed: error 0x%lx", __func__, rv);
1311 *err = rv;
1312 return NULL;
1313 }
1314
1315 return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1316}
1317#endif /* WITH_PKCS11_KEYGEN */
1318
1319/*
1320 * register a new provider, fails if provider already exists. if
1321 * keyp is provided, fetch keys.
1322 */
1323static int
1324pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1325 struct pkcs11_provider **providerp, CK_ULONG user)
594{ 1326{
595 int nkeys, need_finalize = 0; 1327 int nkeys, need_finalize = 0;
1328 int ret = -1;
596 struct pkcs11_provider *p = NULL; 1329 struct pkcs11_provider *p = NULL;
597 void *handle = NULL; 1330 void *handle = NULL;
598 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **); 1331 CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
@@ -601,13 +1334,19 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
601 CK_TOKEN_INFO *token; 1334 CK_TOKEN_INFO *token;
602 CK_ULONG i; 1335 CK_ULONG i;
603 1336
604 *keyp = NULL; 1337 if (providerp == NULL)
1338 goto fail;
1339 *providerp = NULL;
1340
1341 if (keyp != NULL)
1342 *keyp = NULL;
1343
605 if (pkcs11_provider_lookup(provider_id) != NULL) { 1344 if (pkcs11_provider_lookup(provider_id) != NULL) {
606 debug("%s: provider already registered: %s", 1345 debug("%s: provider already registered: %s",
607 __func__, provider_id); 1346 __func__, provider_id);
608 goto fail; 1347 goto fail;
609 } 1348 }
610 /* open shared pkcs11-libarary */ 1349 /* open shared pkcs11-library */
611 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { 1350 if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
612 error("dlopen %s failed: %s", provider_id, dlerror()); 1351 error("dlopen %s failed: %s", provider_id, dlerror());
613 goto fail; 1352 goto fail;
@@ -653,8 +1392,9 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
653 goto fail; 1392 goto fail;
654 } 1393 }
655 if (p->nslots == 0) { 1394 if (p->nslots == 0) {
656 debug("%s: provider %s returned no slots", __func__, 1395 error("%s: provider %s returned no slots", __func__,
657 provider_id); 1396 provider_id);
1397 ret = -SSH_PKCS11_ERR_NO_SLOTS;
658 goto fail; 1398 goto fail;
659 } 1399 }
660 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); 1400 p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
@@ -690,43 +1430,251 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
690 provider_id, (unsigned long)i, 1430 provider_id, (unsigned long)i,
691 token->label, token->manufacturerID, token->model, 1431 token->label, token->manufacturerID, token->model,
692 token->serialNumber, token->flags); 1432 token->serialNumber, token->flags);
693 /* open session, login with pin and retrieve public keys */ 1433 /*
694 if (pkcs11_open_session(p, i, pin) == 0) 1434 * open session, login with pin and retrieve public
1435 * keys (if keyp is provided)
1436 */
1437 if ((ret = pkcs11_open_session(p, i, pin, user)) == 0) {
1438 if (keyp == NULL)
1439 continue;
695 pkcs11_fetch_keys(p, i, keyp, &nkeys); 1440 pkcs11_fetch_keys(p, i, keyp, &nkeys);
1441 pkcs11_fetch_certs(p, i, keyp, &nkeys);
1442 }
696 } 1443 }
697 if (nkeys > 0) { 1444
698 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); 1445 /* now owned by caller */
699 p->refcount++; /* add to provider list */ 1446 *providerp = p;
700 return (nkeys); 1447
701 } 1448 TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
702 debug("%s: provider %s returned no keys", __func__, provider_id); 1449 p->refcount++; /* add to provider list */
703 /* don't add the provider, since it does not have any keys */ 1450
1451 return (nkeys);
704fail: 1452fail:
705 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) 1453 if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
706 error("C_Finalize for provider %s failed: %lu", 1454 error("C_Finalize for provider %s failed: %lu",
707 provider_id, rv); 1455 provider_id, rv);
708 if (p) { 1456 if (p) {
1457 free(p->name);
709 free(p->slotlist); 1458 free(p->slotlist);
710 free(p->slotinfo); 1459 free(p->slotinfo);
711 free(p); 1460 free(p);
712 } 1461 }
713 if (handle) 1462 if (handle)
714 dlclose(handle); 1463 dlclose(handle);
715 return (-1); 1464 return (ret);
716} 1465}
717 1466
718#else 1467/*
1468 * register a new provider and get number of keys hold by the token,
1469 * fails if provider already exists
1470 */
1471int
1472pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1473{
1474 struct pkcs11_provider *p = NULL;
1475 int nkeys;
1476
1477 nkeys = pkcs11_register_provider(provider_id, pin, keyp, &p, CKU_USER);
719 1478
1479 /* no keys found or some other error, de-register provider */
1480 if (nkeys <= 0 && p != NULL) {
1481 TAILQ_REMOVE(&pkcs11_providers, p, next);
1482 pkcs11_provider_finalize(p);
1483 pkcs11_provider_unref(p);
1484 }
1485 if (nkeys == 0)
1486 debug("%s: provider %s returned no keys", __func__,
1487 provider_id);
1488
1489 return (nkeys);
1490}
1491
1492#ifdef WITH_PKCS11_KEYGEN
1493struct sshkey *
1494pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1495 unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1496{
1497 struct pkcs11_provider *p = NULL;
1498 struct pkcs11_slotinfo *si;
1499 CK_FUNCTION_LIST *f;
1500 CK_SESSION_HANDLE session;
1501 struct sshkey *k = NULL;
1502 int ret = -1, reset_pin = 0, reset_provider = 0;
1503 CK_RV rv;
1504
1505 *err = 0;
1506
1507 if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1508 debug("%s: provider \"%s\" available", __func__, provider_id);
1509 else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, &p,
1510 CKU_SO)) < 0) {
1511 debug("%s: could not register provider %s", __func__,
1512 provider_id);
1513 goto out;
1514 } else
1515 reset_provider = 1;
1516
1517 f = p->function_list;
1518 si = &p->slotinfo[slotidx];
1519 session = si->session;
1520
1521 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1522 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1523 debug("%s: could not supply SO pin: %lu", __func__, rv);
1524 reset_pin = 0;
1525 } else
1526 reset_pin = 1;
1527
1528 switch (type) {
1529 case KEY_RSA:
1530 if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1531 bits, keyid, err)) == NULL) {
1532 debug("%s: failed to generate RSA key", __func__);
1533 goto out;
1534 }
1535 break;
1536 case KEY_ECDSA:
1537 if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1538 bits, keyid, err)) == NULL) {
1539 debug("%s: failed to generate ECDSA key", __func__);
1540 goto out;
1541 }
1542 break;
1543 default:
1544 *err = SSH_PKCS11_ERR_GENERIC;
1545 debug("%s: unknown type %d", __func__, type);
1546 goto out;
1547 }
1548
1549out:
1550 if (reset_pin)
1551 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1552 CK_INVALID_HANDLE);
1553
1554 if (reset_provider)
1555 pkcs11_del_provider(provider_id);
1556
1557 return (k);
1558}
1559
1560struct sshkey *
1561pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1562 unsigned char keyid, u_int32_t *err)
1563{
1564 struct pkcs11_provider *p = NULL;
1565 struct pkcs11_slotinfo *si;
1566 struct sshkey *k = NULL;
1567 int reset_pin = 0, reset_provider = 0;
1568 CK_ULONG nattrs;
1569 CK_FUNCTION_LIST *f;
1570 CK_SESSION_HANDLE session;
1571 CK_ATTRIBUTE attrs[16];
1572 CK_OBJECT_CLASS key_class;
1573 CK_KEY_TYPE key_type;
1574 CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1575 CK_RV rv;
1576
1577 *err = 0;
1578
1579 if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1580 debug("%s: using provider \"%s\"", __func__, provider_id);
1581 } else if (pkcs11_register_provider(provider_id, pin, NULL, &p,
1582 CKU_SO) < 0) {
1583 debug("%s: could not register provider %s", __func__,
1584 provider_id);
1585 goto out;
1586 } else
1587 reset_provider = 1;
1588
1589 f = p->function_list;
1590 si = &p->slotinfo[slotidx];
1591 session = si->session;
1592
1593 if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1594 CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1595 debug("%s: could not supply SO pin: %lu", __func__, rv);
1596 reset_pin = 0;
1597 } else
1598 reset_pin = 1;
1599
1600 /* private key */
1601 nattrs = 0;
1602 key_class = CKO_PRIVATE_KEY;
1603 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1604 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1605
1606 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1607 obj != CK_INVALID_HANDLE) {
1608 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1609 debug("%s: could not destroy private key 0x%hhx",
1610 __func__, keyid);
1611 *err = rv;
1612 goto out;
1613 }
1614 }
1615
1616 /* public key */
1617 nattrs = 0;
1618 key_class = CKO_PUBLIC_KEY;
1619 FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1620 FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1621
1622 if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1623 obj != CK_INVALID_HANDLE) {
1624
1625 /* get key type */
1626 nattrs = 0;
1627 FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1628 sizeof(key_type));
1629 rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1630 if (rv != CKR_OK) {
1631 debug("%s: could not get key type of public key 0x%hhx",
1632 __func__, keyid);
1633 *err = rv;
1634 key_type = -1;
1635 }
1636 if (key_type == CKK_RSA)
1637 k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1638 else if (key_type == CKK_ECDSA)
1639 k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1640
1641 if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1642 debug("%s: could not destroy public key 0x%hhx",
1643 __func__, keyid);
1644 *err = rv;
1645 goto out;
1646 }
1647 }
1648
1649out:
1650 if (reset_pin)
1651 f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1652 CK_INVALID_HANDLE);
1653
1654 if (reset_provider)
1655 pkcs11_del_provider(provider_id);
1656
1657 return (k);
1658}
1659#endif /* WITH_PKCS11_KEYGEN */
1660#else /* HAVE_DLOPEN */
720int 1661int
721pkcs11_init(int interactive) 1662pkcs11_init(int interactive)
722{ 1663{
723 return (0); 1664 error("%s: dlopen() not supported", __func__);
1665 return (-1);
1666}
1667
1668int
1669pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1670{
1671 error("%s: dlopen() not supported", __func__);
1672 return (-1);
724} 1673}
725 1674
726void 1675void
727pkcs11_terminate(void) 1676pkcs11_terminate(void)
728{ 1677{
729 return; 1678 error("%s: dlopen() not supported", __func__);
730} 1679}
731 1680#endif /* HAVE_DLOPEN */
732#endif /* ENABLE_PKCS11 */
diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h
index 0ced74f29..b9038450d 100644
--- a/ssh-pkcs11.h
+++ b/ssh-pkcs11.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-pkcs11.h,v 1.4 2015/01/15 09:40:00 djm Exp $ */ 1/* $OpenBSD: ssh-pkcs11.h,v 1.5 2019/01/20 22:51:37 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * 4 *
@@ -14,10 +14,26 @@
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */ 16 */
17
18/* Errors for pkcs11_add_provider() */
19#define SSH_PKCS11_ERR_GENERIC 1
20#define SSH_PKCS11_ERR_LOGIN_FAIL 2
21#define SSH_PKCS11_ERR_NO_SLOTS 3
22#define SSH_PKCS11_ERR_PIN_REQUIRED 4
23#define SSH_PKCS11_ERR_PIN_LOCKED 5
24
17int pkcs11_init(int); 25int pkcs11_init(int);
18void pkcs11_terminate(void); 26void pkcs11_terminate(void);
19int pkcs11_add_provider(char *, char *, struct sshkey ***); 27int pkcs11_add_provider(char *, char *, struct sshkey ***);
20int pkcs11_del_provider(char *); 28int pkcs11_del_provider(char *);
29#ifdef WITH_PKCS11_KEYGEN
30struct sshkey *
31 pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int,
32 unsigned int, unsigned char, u_int32_t *);
33struct sshkey *
34 pkcs11_destroy_keypair(char *, char *, unsigned long, unsigned char,
35 u_int32_t *);
36#endif
21 37
22#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) 38#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
23#undef ENABLE_PKCS11 39#undef ENABLE_PKCS11
diff --git a/sshkey.h b/sshkey.h
index f6a007fdf..a91e60436 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshkey.h,v 1.30 2018/09/14 04:17:44 djm Exp $ */ 1/* $OpenBSD: sshkey.h,v 1.31 2019/01/20 22:51:37 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -33,6 +33,7 @@
33#include <openssl/dsa.h> 33#include <openssl/dsa.h>
34# ifdef OPENSSL_HAS_ECC 34# ifdef OPENSSL_HAS_ECC
35# include <openssl/ec.h> 35# include <openssl/ec.h>
36# include <openssl/ecdsa.h>
36# else /* OPENSSL_HAS_ECC */ 37# else /* OPENSSL_HAS_ECC */
37# define EC_KEY void 38# define EC_KEY void
38# define EC_GROUP void 39# define EC_GROUP void