1*ba1276acSMatthew Dillon /* $OpenBSD: ssh-pkcs11.c,v 1.62 2024/04/02 12:22:38 deraadt Exp $ */
2*ba1276acSMatthew Dillon /*
3*ba1276acSMatthew Dillon * Copyright (c) 2010 Markus Friedl. All rights reserved.
4*ba1276acSMatthew Dillon * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
5*ba1276acSMatthew Dillon *
6*ba1276acSMatthew Dillon * Permission to use, copy, modify, and distribute this software for any
7*ba1276acSMatthew Dillon * purpose with or without fee is hereby granted, provided that the above
8*ba1276acSMatthew Dillon * copyright notice and this permission notice appear in all copies.
9*ba1276acSMatthew Dillon *
10*ba1276acSMatthew Dillon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*ba1276acSMatthew Dillon * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*ba1276acSMatthew Dillon * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*ba1276acSMatthew Dillon * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*ba1276acSMatthew Dillon * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*ba1276acSMatthew Dillon * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*ba1276acSMatthew Dillon * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*ba1276acSMatthew Dillon */
18*ba1276acSMatthew Dillon
19*ba1276acSMatthew Dillon #include "includes.h"
20*ba1276acSMatthew Dillon
21*ba1276acSMatthew Dillon #ifdef ENABLE_PKCS11
22*ba1276acSMatthew Dillon
23*ba1276acSMatthew Dillon #ifdef HAVE_SYS_TIME_H
24*ba1276acSMatthew Dillon # include <sys/time.h>
25*ba1276acSMatthew Dillon #endif
26*ba1276acSMatthew Dillon
27*ba1276acSMatthew Dillon #include <sys/types.h>
28*ba1276acSMatthew Dillon #include <stdarg.h>
29*ba1276acSMatthew Dillon #include <stdio.h>
30*ba1276acSMatthew Dillon
31*ba1276acSMatthew Dillon #include <ctype.h>
32*ba1276acSMatthew Dillon #include <string.h>
33*ba1276acSMatthew Dillon #include <dlfcn.h>
34*ba1276acSMatthew Dillon
35*ba1276acSMatthew Dillon #include "openbsd-compat/sys-queue.h"
36*ba1276acSMatthew Dillon #include "openbsd-compat/openssl-compat.h"
37*ba1276acSMatthew Dillon
38*ba1276acSMatthew Dillon #include <openssl/ecdsa.h>
39*ba1276acSMatthew Dillon #include <openssl/x509.h>
40*ba1276acSMatthew Dillon #include <openssl/err.h>
41*ba1276acSMatthew Dillon
42*ba1276acSMatthew Dillon #define CRYPTOKI_COMPAT
43*ba1276acSMatthew Dillon #include "pkcs11.h"
44*ba1276acSMatthew Dillon
45*ba1276acSMatthew Dillon #include "log.h"
46*ba1276acSMatthew Dillon #include "misc.h"
47*ba1276acSMatthew Dillon #include "sshkey.h"
48*ba1276acSMatthew Dillon #include "ssh-pkcs11.h"
49*ba1276acSMatthew Dillon #include "digest.h"
50*ba1276acSMatthew Dillon #include "xmalloc.h"
51*ba1276acSMatthew Dillon
52*ba1276acSMatthew Dillon struct pkcs11_slotinfo {
53*ba1276acSMatthew Dillon CK_TOKEN_INFO token;
54*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
55*ba1276acSMatthew Dillon int logged_in;
56*ba1276acSMatthew Dillon };
57*ba1276acSMatthew Dillon
58*ba1276acSMatthew Dillon struct pkcs11_provider {
59*ba1276acSMatthew Dillon char *name;
60*ba1276acSMatthew Dillon void *handle;
61*ba1276acSMatthew Dillon CK_FUNCTION_LIST *function_list;
62*ba1276acSMatthew Dillon CK_INFO info;
63*ba1276acSMatthew Dillon CK_ULONG nslots;
64*ba1276acSMatthew Dillon CK_SLOT_ID *slotlist;
65*ba1276acSMatthew Dillon struct pkcs11_slotinfo *slotinfo;
66*ba1276acSMatthew Dillon int valid;
67*ba1276acSMatthew Dillon int refcount;
68*ba1276acSMatthew Dillon TAILQ_ENTRY(pkcs11_provider) next;
69*ba1276acSMatthew Dillon };
70*ba1276acSMatthew Dillon
71*ba1276acSMatthew Dillon TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
72*ba1276acSMatthew Dillon
73*ba1276acSMatthew Dillon struct pkcs11_key {
74*ba1276acSMatthew Dillon struct pkcs11_provider *provider;
75*ba1276acSMatthew Dillon CK_ULONG slotidx;
76*ba1276acSMatthew Dillon char *keyid;
77*ba1276acSMatthew Dillon int keyid_len;
78*ba1276acSMatthew Dillon };
79*ba1276acSMatthew Dillon
80*ba1276acSMatthew Dillon int pkcs11_interactive = 0;
81*ba1276acSMatthew Dillon
82*ba1276acSMatthew Dillon #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
83*ba1276acSMatthew Dillon static void
ossl_error(const char * msg)84*ba1276acSMatthew Dillon ossl_error(const char *msg)
85*ba1276acSMatthew Dillon {
86*ba1276acSMatthew Dillon unsigned long e;
87*ba1276acSMatthew Dillon
88*ba1276acSMatthew Dillon error_f("%s", msg);
89*ba1276acSMatthew Dillon while ((e = ERR_get_error()) != 0)
90*ba1276acSMatthew Dillon error_f("libcrypto error: %s", ERR_error_string(e, NULL));
91*ba1276acSMatthew Dillon }
92*ba1276acSMatthew Dillon #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
93*ba1276acSMatthew Dillon
94*ba1276acSMatthew Dillon int
pkcs11_init(int interactive)95*ba1276acSMatthew Dillon pkcs11_init(int interactive)
96*ba1276acSMatthew Dillon {
97*ba1276acSMatthew Dillon pkcs11_interactive = interactive;
98*ba1276acSMatthew Dillon TAILQ_INIT(&pkcs11_providers);
99*ba1276acSMatthew Dillon return (0);
100*ba1276acSMatthew Dillon }
101*ba1276acSMatthew Dillon
102*ba1276acSMatthew Dillon /*
103*ba1276acSMatthew Dillon * finalize a provider shared library, it's no longer usable.
104*ba1276acSMatthew Dillon * however, there might still be keys referencing this provider,
105*ba1276acSMatthew Dillon * so the actual freeing of memory is handled by pkcs11_provider_unref().
106*ba1276acSMatthew Dillon * this is called when a provider gets unregistered.
107*ba1276acSMatthew Dillon */
108*ba1276acSMatthew Dillon static void
pkcs11_provider_finalize(struct pkcs11_provider * p)109*ba1276acSMatthew Dillon pkcs11_provider_finalize(struct pkcs11_provider *p)
110*ba1276acSMatthew Dillon {
111*ba1276acSMatthew Dillon CK_RV rv;
112*ba1276acSMatthew Dillon CK_ULONG i;
113*ba1276acSMatthew Dillon
114*ba1276acSMatthew Dillon debug_f("provider \"%s\" refcount %d valid %d",
115*ba1276acSMatthew Dillon p->name, p->refcount, p->valid);
116*ba1276acSMatthew Dillon if (!p->valid)
117*ba1276acSMatthew Dillon return;
118*ba1276acSMatthew Dillon for (i = 0; i < p->nslots; i++) {
119*ba1276acSMatthew Dillon if (p->slotinfo[i].session &&
120*ba1276acSMatthew Dillon (rv = p->function_list->C_CloseSession(
121*ba1276acSMatthew Dillon p->slotinfo[i].session)) != CKR_OK)
122*ba1276acSMatthew Dillon error("C_CloseSession failed: %lu", rv);
123*ba1276acSMatthew Dillon }
124*ba1276acSMatthew Dillon if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
125*ba1276acSMatthew Dillon error("C_Finalize failed: %lu", rv);
126*ba1276acSMatthew Dillon p->valid = 0;
127*ba1276acSMatthew Dillon p->function_list = NULL;
128*ba1276acSMatthew Dillon dlclose(p->handle);
129*ba1276acSMatthew Dillon }
130*ba1276acSMatthew Dillon
131*ba1276acSMatthew Dillon /*
132*ba1276acSMatthew Dillon * remove a reference to the provider.
133*ba1276acSMatthew Dillon * called when a key gets destroyed or when the provider is unregistered.
134*ba1276acSMatthew Dillon */
135*ba1276acSMatthew Dillon static void
pkcs11_provider_unref(struct pkcs11_provider * p)136*ba1276acSMatthew Dillon pkcs11_provider_unref(struct pkcs11_provider *p)
137*ba1276acSMatthew Dillon {
138*ba1276acSMatthew Dillon debug_f("provider \"%s\" refcount %d", p->name, p->refcount);
139*ba1276acSMatthew Dillon if (--p->refcount <= 0) {
140*ba1276acSMatthew Dillon if (p->valid)
141*ba1276acSMatthew Dillon error_f("provider \"%s\" still valid", p->name);
142*ba1276acSMatthew Dillon free(p->name);
143*ba1276acSMatthew Dillon free(p->slotlist);
144*ba1276acSMatthew Dillon free(p->slotinfo);
145*ba1276acSMatthew Dillon free(p);
146*ba1276acSMatthew Dillon }
147*ba1276acSMatthew Dillon }
148*ba1276acSMatthew Dillon
149*ba1276acSMatthew Dillon /* unregister all providers, keys might still point to the providers */
150*ba1276acSMatthew Dillon void
pkcs11_terminate(void)151*ba1276acSMatthew Dillon pkcs11_terminate(void)
152*ba1276acSMatthew Dillon {
153*ba1276acSMatthew Dillon struct pkcs11_provider *p;
154*ba1276acSMatthew Dillon
155*ba1276acSMatthew Dillon while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
156*ba1276acSMatthew Dillon TAILQ_REMOVE(&pkcs11_providers, p, next);
157*ba1276acSMatthew Dillon pkcs11_provider_finalize(p);
158*ba1276acSMatthew Dillon pkcs11_provider_unref(p);
159*ba1276acSMatthew Dillon }
160*ba1276acSMatthew Dillon }
161*ba1276acSMatthew Dillon
162*ba1276acSMatthew Dillon /* lookup provider by name */
163*ba1276acSMatthew Dillon static struct pkcs11_provider *
pkcs11_provider_lookup(char * provider_id)164*ba1276acSMatthew Dillon pkcs11_provider_lookup(char *provider_id)
165*ba1276acSMatthew Dillon {
166*ba1276acSMatthew Dillon struct pkcs11_provider *p;
167*ba1276acSMatthew Dillon
168*ba1276acSMatthew Dillon TAILQ_FOREACH(p, &pkcs11_providers, next) {
169*ba1276acSMatthew Dillon debug("check provider \"%s\"", p->name);
170*ba1276acSMatthew Dillon if (!strcmp(provider_id, p->name))
171*ba1276acSMatthew Dillon return (p);
172*ba1276acSMatthew Dillon }
173*ba1276acSMatthew Dillon return (NULL);
174*ba1276acSMatthew Dillon }
175*ba1276acSMatthew Dillon
176*ba1276acSMatthew Dillon /* unregister provider by name */
177*ba1276acSMatthew Dillon int
pkcs11_del_provider(char * provider_id)178*ba1276acSMatthew Dillon pkcs11_del_provider(char *provider_id)
179*ba1276acSMatthew Dillon {
180*ba1276acSMatthew Dillon struct pkcs11_provider *p;
181*ba1276acSMatthew Dillon
182*ba1276acSMatthew Dillon if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
183*ba1276acSMatthew Dillon TAILQ_REMOVE(&pkcs11_providers, p, next);
184*ba1276acSMatthew Dillon pkcs11_provider_finalize(p);
185*ba1276acSMatthew Dillon pkcs11_provider_unref(p);
186*ba1276acSMatthew Dillon return (0);
187*ba1276acSMatthew Dillon }
188*ba1276acSMatthew Dillon return (-1);
189*ba1276acSMatthew Dillon }
190*ba1276acSMatthew Dillon
191*ba1276acSMatthew Dillon static RSA_METHOD *rsa_method;
192*ba1276acSMatthew Dillon static int rsa_idx = 0;
193*ba1276acSMatthew Dillon #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
194*ba1276acSMatthew Dillon static EC_KEY_METHOD *ec_key_method;
195*ba1276acSMatthew Dillon static int ec_key_idx = 0;
196*ba1276acSMatthew Dillon #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
197*ba1276acSMatthew Dillon
198*ba1276acSMatthew Dillon /* release a wrapped object */
199*ba1276acSMatthew Dillon static void
pkcs11_k11_free(void * parent,void * ptr,CRYPTO_EX_DATA * ad,int idx,long argl,void * argp)200*ba1276acSMatthew Dillon pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
201*ba1276acSMatthew Dillon long argl, void *argp)
202*ba1276acSMatthew Dillon {
203*ba1276acSMatthew Dillon struct pkcs11_key *k11 = ptr;
204*ba1276acSMatthew Dillon
205*ba1276acSMatthew Dillon debug_f("parent %p ptr %p idx %d", parent, ptr, idx);
206*ba1276acSMatthew Dillon if (k11 == NULL)
207*ba1276acSMatthew Dillon return;
208*ba1276acSMatthew Dillon if (k11->provider)
209*ba1276acSMatthew Dillon pkcs11_provider_unref(k11->provider);
210*ba1276acSMatthew Dillon free(k11->keyid);
211*ba1276acSMatthew Dillon free(k11);
212*ba1276acSMatthew Dillon }
213*ba1276acSMatthew Dillon
214*ba1276acSMatthew Dillon /* find a single 'obj' for given attributes */
215*ba1276acSMatthew Dillon static int
pkcs11_find(struct pkcs11_provider * p,CK_ULONG slotidx,CK_ATTRIBUTE * attr,CK_ULONG nattr,CK_OBJECT_HANDLE * obj)216*ba1276acSMatthew Dillon pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
217*ba1276acSMatthew Dillon CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
218*ba1276acSMatthew Dillon {
219*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
220*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
221*ba1276acSMatthew Dillon CK_ULONG nfound = 0;
222*ba1276acSMatthew Dillon CK_RV rv;
223*ba1276acSMatthew Dillon int ret = -1;
224*ba1276acSMatthew Dillon
225*ba1276acSMatthew Dillon f = p->function_list;
226*ba1276acSMatthew Dillon session = p->slotinfo[slotidx].session;
227*ba1276acSMatthew Dillon if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
228*ba1276acSMatthew Dillon error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
229*ba1276acSMatthew Dillon return (-1);
230*ba1276acSMatthew Dillon }
231*ba1276acSMatthew Dillon if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
232*ba1276acSMatthew Dillon nfound != 1) {
233*ba1276acSMatthew Dillon debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
234*ba1276acSMatthew Dillon nfound, nattr, rv);
235*ba1276acSMatthew Dillon } else
236*ba1276acSMatthew Dillon ret = 0;
237*ba1276acSMatthew Dillon if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
238*ba1276acSMatthew Dillon error("C_FindObjectsFinal failed: %lu", rv);
239*ba1276acSMatthew Dillon return (ret);
240*ba1276acSMatthew Dillon }
241*ba1276acSMatthew Dillon
242*ba1276acSMatthew Dillon static int
pkcs11_login_slot(struct pkcs11_provider * provider,struct pkcs11_slotinfo * si,CK_USER_TYPE type)243*ba1276acSMatthew Dillon pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si,
244*ba1276acSMatthew Dillon CK_USER_TYPE type)
245*ba1276acSMatthew Dillon {
246*ba1276acSMatthew Dillon char *pin = NULL, prompt[1024];
247*ba1276acSMatthew Dillon CK_RV rv;
248*ba1276acSMatthew Dillon
249*ba1276acSMatthew Dillon if (provider == NULL || si == NULL || !provider->valid) {
250*ba1276acSMatthew Dillon error("no pkcs11 (valid) provider found");
251*ba1276acSMatthew Dillon return (-1);
252*ba1276acSMatthew Dillon }
253*ba1276acSMatthew Dillon
254*ba1276acSMatthew Dillon if (!pkcs11_interactive) {
255*ba1276acSMatthew Dillon error("need pin entry%s",
256*ba1276acSMatthew Dillon (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ?
257*ba1276acSMatthew Dillon " on reader keypad" : "");
258*ba1276acSMatthew Dillon return (-1);
259*ba1276acSMatthew Dillon }
260*ba1276acSMatthew Dillon if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
261*ba1276acSMatthew Dillon verbose("Deferring PIN entry to reader keypad.");
262*ba1276acSMatthew Dillon else {
263*ba1276acSMatthew Dillon snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
264*ba1276acSMatthew Dillon si->token.label);
265*ba1276acSMatthew Dillon if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) {
266*ba1276acSMatthew Dillon debug_f("no pin specified");
267*ba1276acSMatthew Dillon return (-1); /* bail out */
268*ba1276acSMatthew Dillon }
269*ba1276acSMatthew Dillon }
270*ba1276acSMatthew Dillon rv = provider->function_list->C_Login(si->session, type, (u_char *)pin,
271*ba1276acSMatthew Dillon (pin != NULL) ? strlen(pin) : 0);
272*ba1276acSMatthew Dillon if (pin != NULL)
273*ba1276acSMatthew Dillon freezero(pin, strlen(pin));
274*ba1276acSMatthew Dillon
275*ba1276acSMatthew Dillon switch (rv) {
276*ba1276acSMatthew Dillon case CKR_OK:
277*ba1276acSMatthew Dillon case CKR_USER_ALREADY_LOGGED_IN:
278*ba1276acSMatthew Dillon /* success */
279*ba1276acSMatthew Dillon break;
280*ba1276acSMatthew Dillon case CKR_PIN_LEN_RANGE:
281*ba1276acSMatthew Dillon error("PKCS#11 login failed: PIN length out of range");
282*ba1276acSMatthew Dillon return -1;
283*ba1276acSMatthew Dillon case CKR_PIN_INCORRECT:
284*ba1276acSMatthew Dillon error("PKCS#11 login failed: PIN incorrect");
285*ba1276acSMatthew Dillon return -1;
286*ba1276acSMatthew Dillon case CKR_PIN_LOCKED:
287*ba1276acSMatthew Dillon error("PKCS#11 login failed: PIN locked");
288*ba1276acSMatthew Dillon return -1;
289*ba1276acSMatthew Dillon default:
290*ba1276acSMatthew Dillon error("PKCS#11 login failed: error %lu", rv);
291*ba1276acSMatthew Dillon return -1;
292*ba1276acSMatthew Dillon }
293*ba1276acSMatthew Dillon si->logged_in = 1;
294*ba1276acSMatthew Dillon return (0);
295*ba1276acSMatthew Dillon }
296*ba1276acSMatthew Dillon
297*ba1276acSMatthew Dillon static int
pkcs11_login(struct pkcs11_key * k11,CK_USER_TYPE type)298*ba1276acSMatthew Dillon pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type)
299*ba1276acSMatthew Dillon {
300*ba1276acSMatthew Dillon if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) {
301*ba1276acSMatthew Dillon error("no pkcs11 (valid) provider found");
302*ba1276acSMatthew Dillon return (-1);
303*ba1276acSMatthew Dillon }
304*ba1276acSMatthew Dillon
305*ba1276acSMatthew Dillon return pkcs11_login_slot(k11->provider,
306*ba1276acSMatthew Dillon &k11->provider->slotinfo[k11->slotidx], type);
307*ba1276acSMatthew Dillon }
308*ba1276acSMatthew Dillon
309*ba1276acSMatthew Dillon
310*ba1276acSMatthew Dillon static int
pkcs11_check_obj_bool_attrib(struct pkcs11_key * k11,CK_OBJECT_HANDLE obj,CK_ATTRIBUTE_TYPE type,int * val)311*ba1276acSMatthew Dillon pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj,
312*ba1276acSMatthew Dillon CK_ATTRIBUTE_TYPE type, int *val)
313*ba1276acSMatthew Dillon {
314*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
315*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
316*ba1276acSMatthew Dillon CK_BBOOL flag = 0;
317*ba1276acSMatthew Dillon CK_ATTRIBUTE attr;
318*ba1276acSMatthew Dillon CK_RV rv;
319*ba1276acSMatthew Dillon
320*ba1276acSMatthew Dillon *val = 0;
321*ba1276acSMatthew Dillon
322*ba1276acSMatthew Dillon if (!k11->provider || !k11->provider->valid) {
323*ba1276acSMatthew Dillon error("no pkcs11 (valid) provider found");
324*ba1276acSMatthew Dillon return (-1);
325*ba1276acSMatthew Dillon }
326*ba1276acSMatthew Dillon
327*ba1276acSMatthew Dillon f = k11->provider->function_list;
328*ba1276acSMatthew Dillon si = &k11->provider->slotinfo[k11->slotidx];
329*ba1276acSMatthew Dillon
330*ba1276acSMatthew Dillon attr.type = type;
331*ba1276acSMatthew Dillon attr.pValue = &flag;
332*ba1276acSMatthew Dillon attr.ulValueLen = sizeof(flag);
333*ba1276acSMatthew Dillon
334*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(si->session, obj, &attr, 1);
335*ba1276acSMatthew Dillon if (rv != CKR_OK) {
336*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
337*ba1276acSMatthew Dillon return (-1);
338*ba1276acSMatthew Dillon }
339*ba1276acSMatthew Dillon *val = flag != 0;
340*ba1276acSMatthew Dillon debug_f("provider \"%s\" slot %lu object %lu: attrib %lu = %d",
341*ba1276acSMatthew Dillon k11->provider->name, k11->slotidx, obj, type, *val);
342*ba1276acSMatthew Dillon return (0);
343*ba1276acSMatthew Dillon }
344*ba1276acSMatthew Dillon
345*ba1276acSMatthew Dillon static int
pkcs11_get_key(struct pkcs11_key * k11,CK_MECHANISM_TYPE mech_type)346*ba1276acSMatthew Dillon pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
347*ba1276acSMatthew Dillon {
348*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
349*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
350*ba1276acSMatthew Dillon CK_OBJECT_HANDLE obj;
351*ba1276acSMatthew Dillon CK_RV rv;
352*ba1276acSMatthew Dillon CK_OBJECT_CLASS private_key_class;
353*ba1276acSMatthew Dillon CK_BBOOL true_val;
354*ba1276acSMatthew Dillon CK_MECHANISM mech;
355*ba1276acSMatthew Dillon CK_ATTRIBUTE key_filter[3];
356*ba1276acSMatthew Dillon int always_auth = 0;
357*ba1276acSMatthew Dillon int did_login = 0;
358*ba1276acSMatthew Dillon
359*ba1276acSMatthew Dillon if (!k11->provider || !k11->provider->valid) {
360*ba1276acSMatthew Dillon error("no pkcs11 (valid) provider found");
361*ba1276acSMatthew Dillon return (-1);
362*ba1276acSMatthew Dillon }
363*ba1276acSMatthew Dillon
364*ba1276acSMatthew Dillon f = k11->provider->function_list;
365*ba1276acSMatthew Dillon si = &k11->provider->slotinfo[k11->slotidx];
366*ba1276acSMatthew Dillon
367*ba1276acSMatthew Dillon if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
368*ba1276acSMatthew Dillon if (pkcs11_login(k11, CKU_USER) < 0) {
369*ba1276acSMatthew Dillon error("login failed");
370*ba1276acSMatthew Dillon return (-1);
371*ba1276acSMatthew Dillon }
372*ba1276acSMatthew Dillon did_login = 1;
373*ba1276acSMatthew Dillon }
374*ba1276acSMatthew Dillon
375*ba1276acSMatthew Dillon memset(&key_filter, 0, sizeof(key_filter));
376*ba1276acSMatthew Dillon private_key_class = CKO_PRIVATE_KEY;
377*ba1276acSMatthew Dillon key_filter[0].type = CKA_CLASS;
378*ba1276acSMatthew Dillon key_filter[0].pValue = &private_key_class;
379*ba1276acSMatthew Dillon key_filter[0].ulValueLen = sizeof(private_key_class);
380*ba1276acSMatthew Dillon
381*ba1276acSMatthew Dillon key_filter[1].type = CKA_ID;
382*ba1276acSMatthew Dillon key_filter[1].pValue = k11->keyid;
383*ba1276acSMatthew Dillon key_filter[1].ulValueLen = k11->keyid_len;
384*ba1276acSMatthew Dillon
385*ba1276acSMatthew Dillon true_val = CK_TRUE;
386*ba1276acSMatthew Dillon key_filter[2].type = CKA_SIGN;
387*ba1276acSMatthew Dillon key_filter[2].pValue = &true_val;
388*ba1276acSMatthew Dillon key_filter[2].ulValueLen = sizeof(true_val);
389*ba1276acSMatthew Dillon
390*ba1276acSMatthew Dillon /* try to find object w/CKA_SIGN first, retry w/o */
391*ba1276acSMatthew Dillon if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
392*ba1276acSMatthew Dillon pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
393*ba1276acSMatthew Dillon error("cannot find private key");
394*ba1276acSMatthew Dillon return (-1);
395*ba1276acSMatthew Dillon }
396*ba1276acSMatthew Dillon
397*ba1276acSMatthew Dillon memset(&mech, 0, sizeof(mech));
398*ba1276acSMatthew Dillon mech.mechanism = mech_type;
399*ba1276acSMatthew Dillon mech.pParameter = NULL_PTR;
400*ba1276acSMatthew Dillon mech.ulParameterLen = 0;
401*ba1276acSMatthew Dillon
402*ba1276acSMatthew Dillon if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
403*ba1276acSMatthew Dillon error("C_SignInit failed: %lu", rv);
404*ba1276acSMatthew Dillon return (-1);
405*ba1276acSMatthew Dillon }
406*ba1276acSMatthew Dillon
407*ba1276acSMatthew Dillon pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE,
408*ba1276acSMatthew Dillon &always_auth); /* ignore errors here */
409*ba1276acSMatthew Dillon if (always_auth && !did_login) {
410*ba1276acSMatthew Dillon debug_f("always-auth key");
411*ba1276acSMatthew Dillon if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) {
412*ba1276acSMatthew Dillon error("login failed for always-auth key");
413*ba1276acSMatthew Dillon return (-1);
414*ba1276acSMatthew Dillon }
415*ba1276acSMatthew Dillon }
416*ba1276acSMatthew Dillon
417*ba1276acSMatthew Dillon return (0);
418*ba1276acSMatthew Dillon }
419*ba1276acSMatthew Dillon
420*ba1276acSMatthew Dillon /* openssl callback doing the actual signing operation */
421*ba1276acSMatthew Dillon static int
pkcs11_rsa_private_encrypt(int flen,const u_char * from,u_char * to,RSA * rsa,int padding)422*ba1276acSMatthew Dillon pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
423*ba1276acSMatthew Dillon int padding)
424*ba1276acSMatthew Dillon {
425*ba1276acSMatthew Dillon struct pkcs11_key *k11;
426*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
427*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
428*ba1276acSMatthew Dillon CK_ULONG tlen = 0;
429*ba1276acSMatthew Dillon CK_RV rv;
430*ba1276acSMatthew Dillon int rval = -1;
431*ba1276acSMatthew Dillon
432*ba1276acSMatthew Dillon if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
433*ba1276acSMatthew Dillon error("RSA_get_ex_data failed");
434*ba1276acSMatthew Dillon return (-1);
435*ba1276acSMatthew Dillon }
436*ba1276acSMatthew Dillon
437*ba1276acSMatthew Dillon if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
438*ba1276acSMatthew Dillon error("pkcs11_get_key failed");
439*ba1276acSMatthew Dillon return (-1);
440*ba1276acSMatthew Dillon }
441*ba1276acSMatthew Dillon
442*ba1276acSMatthew Dillon f = k11->provider->function_list;
443*ba1276acSMatthew Dillon si = &k11->provider->slotinfo[k11->slotidx];
444*ba1276acSMatthew Dillon tlen = RSA_size(rsa);
445*ba1276acSMatthew Dillon
446*ba1276acSMatthew Dillon /* XXX handle CKR_BUFFER_TOO_SMALL */
447*ba1276acSMatthew Dillon rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
448*ba1276acSMatthew Dillon if (rv == CKR_OK)
449*ba1276acSMatthew Dillon rval = tlen;
450*ba1276acSMatthew Dillon else
451*ba1276acSMatthew Dillon error("C_Sign failed: %lu", rv);
452*ba1276acSMatthew Dillon
453*ba1276acSMatthew Dillon return (rval);
454*ba1276acSMatthew Dillon }
455*ba1276acSMatthew Dillon
456*ba1276acSMatthew Dillon static int
pkcs11_rsa_private_decrypt(int flen,const u_char * from,u_char * to,RSA * rsa,int padding)457*ba1276acSMatthew Dillon pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
458*ba1276acSMatthew Dillon int padding)
459*ba1276acSMatthew Dillon {
460*ba1276acSMatthew Dillon return (-1);
461*ba1276acSMatthew Dillon }
462*ba1276acSMatthew Dillon
463*ba1276acSMatthew Dillon static int
pkcs11_rsa_start_wrapper(void)464*ba1276acSMatthew Dillon pkcs11_rsa_start_wrapper(void)
465*ba1276acSMatthew Dillon {
466*ba1276acSMatthew Dillon if (rsa_method != NULL)
467*ba1276acSMatthew Dillon return (0);
468*ba1276acSMatthew Dillon rsa_method = RSA_meth_dup(RSA_get_default_method());
469*ba1276acSMatthew Dillon if (rsa_method == NULL)
470*ba1276acSMatthew Dillon return (-1);
471*ba1276acSMatthew Dillon rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa",
472*ba1276acSMatthew Dillon NULL, NULL, pkcs11_k11_free);
473*ba1276acSMatthew Dillon if (rsa_idx == -1)
474*ba1276acSMatthew Dillon return (-1);
475*ba1276acSMatthew Dillon if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
476*ba1276acSMatthew Dillon !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
477*ba1276acSMatthew Dillon !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) {
478*ba1276acSMatthew Dillon error_f("setup pkcs11 method failed");
479*ba1276acSMatthew Dillon return (-1);
480*ba1276acSMatthew Dillon }
481*ba1276acSMatthew Dillon return (0);
482*ba1276acSMatthew Dillon }
483*ba1276acSMatthew Dillon
484*ba1276acSMatthew Dillon /* redirect private key operations for rsa key to pkcs11 token */
485*ba1276acSMatthew Dillon static int
pkcs11_rsa_wrap(struct pkcs11_provider * provider,CK_ULONG slotidx,CK_ATTRIBUTE * keyid_attrib,RSA * rsa)486*ba1276acSMatthew Dillon pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
487*ba1276acSMatthew Dillon CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
488*ba1276acSMatthew Dillon {
489*ba1276acSMatthew Dillon struct pkcs11_key *k11;
490*ba1276acSMatthew Dillon
491*ba1276acSMatthew Dillon if (pkcs11_rsa_start_wrapper() == -1)
492*ba1276acSMatthew Dillon return (-1);
493*ba1276acSMatthew Dillon
494*ba1276acSMatthew Dillon k11 = xcalloc(1, sizeof(*k11));
495*ba1276acSMatthew Dillon k11->provider = provider;
496*ba1276acSMatthew Dillon provider->refcount++; /* provider referenced by RSA key */
497*ba1276acSMatthew Dillon k11->slotidx = slotidx;
498*ba1276acSMatthew Dillon /* identify key object on smartcard */
499*ba1276acSMatthew Dillon k11->keyid_len = keyid_attrib->ulValueLen;
500*ba1276acSMatthew Dillon if (k11->keyid_len > 0) {
501*ba1276acSMatthew Dillon k11->keyid = xmalloc(k11->keyid_len);
502*ba1276acSMatthew Dillon memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
503*ba1276acSMatthew Dillon }
504*ba1276acSMatthew Dillon
505*ba1276acSMatthew Dillon RSA_set_method(rsa, rsa_method);
506*ba1276acSMatthew Dillon RSA_set_ex_data(rsa, rsa_idx, k11);
507*ba1276acSMatthew Dillon return (0);
508*ba1276acSMatthew Dillon }
509*ba1276acSMatthew Dillon
510*ba1276acSMatthew Dillon #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
511*ba1276acSMatthew Dillon /* openssl callback doing the actual signing operation */
512*ba1276acSMatthew Dillon static ECDSA_SIG *
ecdsa_do_sign(const unsigned char * dgst,int dgst_len,const BIGNUM * inv,const BIGNUM * rp,EC_KEY * ec)513*ba1276acSMatthew Dillon ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
514*ba1276acSMatthew Dillon const BIGNUM *rp, EC_KEY *ec)
515*ba1276acSMatthew Dillon {
516*ba1276acSMatthew Dillon struct pkcs11_key *k11;
517*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
518*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
519*ba1276acSMatthew Dillon CK_ULONG siglen = 0, bnlen;
520*ba1276acSMatthew Dillon CK_RV rv;
521*ba1276acSMatthew Dillon ECDSA_SIG *ret = NULL;
522*ba1276acSMatthew Dillon u_char *sig;
523*ba1276acSMatthew Dillon BIGNUM *r = NULL, *s = NULL;
524*ba1276acSMatthew Dillon
525*ba1276acSMatthew Dillon if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
526*ba1276acSMatthew Dillon ossl_error("EC_KEY_get_ex_data failed for ec");
527*ba1276acSMatthew Dillon return (NULL);
528*ba1276acSMatthew Dillon }
529*ba1276acSMatthew Dillon
530*ba1276acSMatthew Dillon if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
531*ba1276acSMatthew Dillon error("pkcs11_get_key failed");
532*ba1276acSMatthew Dillon return (NULL);
533*ba1276acSMatthew Dillon }
534*ba1276acSMatthew Dillon
535*ba1276acSMatthew Dillon f = k11->provider->function_list;
536*ba1276acSMatthew Dillon si = &k11->provider->slotinfo[k11->slotidx];
537*ba1276acSMatthew Dillon
538*ba1276acSMatthew Dillon siglen = ECDSA_size(ec);
539*ba1276acSMatthew Dillon sig = xmalloc(siglen);
540*ba1276acSMatthew Dillon
541*ba1276acSMatthew Dillon /* XXX handle CKR_BUFFER_TOO_SMALL */
542*ba1276acSMatthew Dillon rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
543*ba1276acSMatthew Dillon if (rv != CKR_OK) {
544*ba1276acSMatthew Dillon error("C_Sign failed: %lu", rv);
545*ba1276acSMatthew Dillon goto done;
546*ba1276acSMatthew Dillon }
547*ba1276acSMatthew Dillon if (siglen < 64 || siglen > 132 || siglen % 2) {
548*ba1276acSMatthew Dillon error_f("bad signature length: %lu", (u_long)siglen);
549*ba1276acSMatthew Dillon goto done;
550*ba1276acSMatthew Dillon }
551*ba1276acSMatthew Dillon bnlen = siglen/2;
552*ba1276acSMatthew Dillon if ((ret = ECDSA_SIG_new()) == NULL) {
553*ba1276acSMatthew Dillon error("ECDSA_SIG_new failed");
554*ba1276acSMatthew Dillon goto done;
555*ba1276acSMatthew Dillon }
556*ba1276acSMatthew Dillon if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
557*ba1276acSMatthew Dillon (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
558*ba1276acSMatthew Dillon ossl_error("BN_bin2bn failed");
559*ba1276acSMatthew Dillon ECDSA_SIG_free(ret);
560*ba1276acSMatthew Dillon ret = NULL;
561*ba1276acSMatthew Dillon goto done;
562*ba1276acSMatthew Dillon }
563*ba1276acSMatthew Dillon if (!ECDSA_SIG_set0(ret, r, s)) {
564*ba1276acSMatthew Dillon error_f("ECDSA_SIG_set0 failed");
565*ba1276acSMatthew Dillon ECDSA_SIG_free(ret);
566*ba1276acSMatthew Dillon ret = NULL;
567*ba1276acSMatthew Dillon goto done;
568*ba1276acSMatthew Dillon }
569*ba1276acSMatthew Dillon r = s = NULL; /* now owned by ret */
570*ba1276acSMatthew Dillon /* success */
571*ba1276acSMatthew Dillon done:
572*ba1276acSMatthew Dillon BN_free(r);
573*ba1276acSMatthew Dillon BN_free(s);
574*ba1276acSMatthew Dillon free(sig);
575*ba1276acSMatthew Dillon
576*ba1276acSMatthew Dillon return (ret);
577*ba1276acSMatthew Dillon }
578*ba1276acSMatthew Dillon
579*ba1276acSMatthew Dillon static int
pkcs11_ecdsa_start_wrapper(void)580*ba1276acSMatthew Dillon pkcs11_ecdsa_start_wrapper(void)
581*ba1276acSMatthew Dillon {
582*ba1276acSMatthew Dillon int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
583*ba1276acSMatthew Dillon unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
584*ba1276acSMatthew Dillon
585*ba1276acSMatthew Dillon if (ec_key_method != NULL)
586*ba1276acSMatthew Dillon return (0);
587*ba1276acSMatthew Dillon ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
588*ba1276acSMatthew Dillon NULL, NULL, pkcs11_k11_free);
589*ba1276acSMatthew Dillon if (ec_key_idx == -1)
590*ba1276acSMatthew Dillon return (-1);
591*ba1276acSMatthew Dillon ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
592*ba1276acSMatthew Dillon if (ec_key_method == NULL)
593*ba1276acSMatthew Dillon return (-1);
594*ba1276acSMatthew Dillon EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
595*ba1276acSMatthew Dillon EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
596*ba1276acSMatthew Dillon return (0);
597*ba1276acSMatthew Dillon }
598*ba1276acSMatthew Dillon
599*ba1276acSMatthew Dillon static int
pkcs11_ecdsa_wrap(struct pkcs11_provider * provider,CK_ULONG slotidx,CK_ATTRIBUTE * keyid_attrib,EC_KEY * ec)600*ba1276acSMatthew Dillon pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
601*ba1276acSMatthew Dillon CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
602*ba1276acSMatthew Dillon {
603*ba1276acSMatthew Dillon struct pkcs11_key *k11;
604*ba1276acSMatthew Dillon
605*ba1276acSMatthew Dillon if (pkcs11_ecdsa_start_wrapper() == -1)
606*ba1276acSMatthew Dillon return (-1);
607*ba1276acSMatthew Dillon
608*ba1276acSMatthew Dillon k11 = xcalloc(1, sizeof(*k11));
609*ba1276acSMatthew Dillon k11->provider = provider;
610*ba1276acSMatthew Dillon provider->refcount++; /* provider referenced by ECDSA key */
611*ba1276acSMatthew Dillon k11->slotidx = slotidx;
612*ba1276acSMatthew Dillon /* identify key object on smartcard */
613*ba1276acSMatthew Dillon k11->keyid_len = keyid_attrib->ulValueLen;
614*ba1276acSMatthew Dillon if (k11->keyid_len > 0) {
615*ba1276acSMatthew Dillon k11->keyid = xmalloc(k11->keyid_len);
616*ba1276acSMatthew Dillon memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
617*ba1276acSMatthew Dillon }
618*ba1276acSMatthew Dillon EC_KEY_set_method(ec, ec_key_method);
619*ba1276acSMatthew Dillon EC_KEY_set_ex_data(ec, ec_key_idx, k11);
620*ba1276acSMatthew Dillon
621*ba1276acSMatthew Dillon return (0);
622*ba1276acSMatthew Dillon }
623*ba1276acSMatthew Dillon #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
624*ba1276acSMatthew Dillon
625*ba1276acSMatthew Dillon /* remove trailing spaces */
626*ba1276acSMatthew Dillon static char *
rmspace(u_char * buf,size_t len)627*ba1276acSMatthew Dillon rmspace(u_char *buf, size_t len)
628*ba1276acSMatthew Dillon {
629*ba1276acSMatthew Dillon size_t i;
630*ba1276acSMatthew Dillon
631*ba1276acSMatthew Dillon if (len == 0)
632*ba1276acSMatthew Dillon return buf;
633*ba1276acSMatthew Dillon for (i = len - 1; i > 0; i--)
634*ba1276acSMatthew Dillon if (buf[i] == ' ')
635*ba1276acSMatthew Dillon buf[i] = '\0';
636*ba1276acSMatthew Dillon else
637*ba1276acSMatthew Dillon break;
638*ba1276acSMatthew Dillon return buf;
639*ba1276acSMatthew Dillon }
640*ba1276acSMatthew Dillon /* Used to printf fixed-width, space-padded, unterminated strings using %.*s */
641*ba1276acSMatthew Dillon #define RMSPACE(s) (int)sizeof(s), rmspace(s, sizeof(s))
642*ba1276acSMatthew Dillon
643*ba1276acSMatthew Dillon /*
644*ba1276acSMatthew Dillon * open a pkcs11 session and login if required.
645*ba1276acSMatthew Dillon * if pin == NULL we delay login until key use
646*ba1276acSMatthew Dillon */
647*ba1276acSMatthew Dillon static int
pkcs11_open_session(struct pkcs11_provider * p,CK_ULONG slotidx,char * pin,CK_ULONG user)648*ba1276acSMatthew Dillon pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin,
649*ba1276acSMatthew Dillon CK_ULONG user)
650*ba1276acSMatthew Dillon {
651*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
652*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
653*ba1276acSMatthew Dillon CK_RV rv;
654*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
655*ba1276acSMatthew Dillon int login_required, ret;
656*ba1276acSMatthew Dillon
657*ba1276acSMatthew Dillon f = p->function_list;
658*ba1276acSMatthew Dillon si = &p->slotinfo[slotidx];
659*ba1276acSMatthew Dillon
660*ba1276acSMatthew Dillon login_required = si->token.flags & CKF_LOGIN_REQUIRED;
661*ba1276acSMatthew Dillon
662*ba1276acSMatthew Dillon /* fail early before opening session */
663*ba1276acSMatthew Dillon if (login_required && !pkcs11_interactive &&
664*ba1276acSMatthew Dillon (pin == NULL || strlen(pin) == 0)) {
665*ba1276acSMatthew Dillon error("pin required");
666*ba1276acSMatthew Dillon return (-SSH_PKCS11_ERR_PIN_REQUIRED);
667*ba1276acSMatthew Dillon }
668*ba1276acSMatthew Dillon if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
669*ba1276acSMatthew Dillon CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
670*ba1276acSMatthew Dillon error("C_OpenSession failed: %lu", rv);
671*ba1276acSMatthew Dillon return (-1);
672*ba1276acSMatthew Dillon }
673*ba1276acSMatthew Dillon if (login_required && pin != NULL && strlen(pin) != 0) {
674*ba1276acSMatthew Dillon rv = f->C_Login(session, user, (u_char *)pin, strlen(pin));
675*ba1276acSMatthew Dillon if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
676*ba1276acSMatthew Dillon error("C_Login failed: %lu", rv);
677*ba1276acSMatthew Dillon ret = (rv == CKR_PIN_LOCKED) ?
678*ba1276acSMatthew Dillon -SSH_PKCS11_ERR_PIN_LOCKED :
679*ba1276acSMatthew Dillon -SSH_PKCS11_ERR_LOGIN_FAIL;
680*ba1276acSMatthew Dillon if ((rv = f->C_CloseSession(session)) != CKR_OK)
681*ba1276acSMatthew Dillon error("C_CloseSession failed: %lu", rv);
682*ba1276acSMatthew Dillon return (ret);
683*ba1276acSMatthew Dillon }
684*ba1276acSMatthew Dillon si->logged_in = 1;
685*ba1276acSMatthew Dillon }
686*ba1276acSMatthew Dillon si->session = session;
687*ba1276acSMatthew Dillon return (0);
688*ba1276acSMatthew Dillon }
689*ba1276acSMatthew Dillon
690*ba1276acSMatthew Dillon static int
pkcs11_key_included(struct sshkey *** keysp,int * nkeys,struct sshkey * key)691*ba1276acSMatthew Dillon pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
692*ba1276acSMatthew Dillon {
693*ba1276acSMatthew Dillon int i;
694*ba1276acSMatthew Dillon
695*ba1276acSMatthew Dillon for (i = 0; i < *nkeys; i++)
696*ba1276acSMatthew Dillon if (sshkey_equal(key, (*keysp)[i]))
697*ba1276acSMatthew Dillon return (1);
698*ba1276acSMatthew Dillon return (0);
699*ba1276acSMatthew Dillon }
700*ba1276acSMatthew Dillon
701*ba1276acSMatthew Dillon #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
702*ba1276acSMatthew Dillon static struct sshkey *
pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider * p,CK_ULONG slotidx,CK_OBJECT_HANDLE * obj)703*ba1276acSMatthew Dillon pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
704*ba1276acSMatthew Dillon CK_OBJECT_HANDLE *obj)
705*ba1276acSMatthew Dillon {
706*ba1276acSMatthew Dillon CK_ATTRIBUTE key_attr[3];
707*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
708*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f = NULL;
709*ba1276acSMatthew Dillon CK_RV rv;
710*ba1276acSMatthew Dillon ASN1_OCTET_STRING *octet = NULL;
711*ba1276acSMatthew Dillon EC_KEY *ec = NULL;
712*ba1276acSMatthew Dillon EC_GROUP *group = NULL;
713*ba1276acSMatthew Dillon struct sshkey *key = NULL;
714*ba1276acSMatthew Dillon const unsigned char *attrp = NULL;
715*ba1276acSMatthew Dillon int i;
716*ba1276acSMatthew Dillon int nid;
717*ba1276acSMatthew Dillon
718*ba1276acSMatthew Dillon memset(&key_attr, 0, sizeof(key_attr));
719*ba1276acSMatthew Dillon key_attr[0].type = CKA_ID;
720*ba1276acSMatthew Dillon key_attr[1].type = CKA_EC_POINT;
721*ba1276acSMatthew Dillon key_attr[2].type = CKA_EC_PARAMS;
722*ba1276acSMatthew Dillon
723*ba1276acSMatthew Dillon session = p->slotinfo[slotidx].session;
724*ba1276acSMatthew Dillon f = p->function_list;
725*ba1276acSMatthew Dillon
726*ba1276acSMatthew Dillon /* figure out size of the attributes */
727*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
728*ba1276acSMatthew Dillon if (rv != CKR_OK) {
729*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
730*ba1276acSMatthew Dillon return (NULL);
731*ba1276acSMatthew Dillon }
732*ba1276acSMatthew Dillon
733*ba1276acSMatthew Dillon /*
734*ba1276acSMatthew Dillon * Allow CKA_ID (always first attribute) to be empty, but
735*ba1276acSMatthew Dillon * ensure that none of the others are zero length.
736*ba1276acSMatthew Dillon * XXX assumes CKA_ID is always first.
737*ba1276acSMatthew Dillon */
738*ba1276acSMatthew Dillon if (key_attr[1].ulValueLen == 0 ||
739*ba1276acSMatthew Dillon key_attr[2].ulValueLen == 0) {
740*ba1276acSMatthew Dillon error("invalid attribute length");
741*ba1276acSMatthew Dillon return (NULL);
742*ba1276acSMatthew Dillon }
743*ba1276acSMatthew Dillon
744*ba1276acSMatthew Dillon /* allocate buffers for attributes */
745*ba1276acSMatthew Dillon for (i = 0; i < 3; i++)
746*ba1276acSMatthew Dillon if (key_attr[i].ulValueLen > 0)
747*ba1276acSMatthew Dillon key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
748*ba1276acSMatthew Dillon
749*ba1276acSMatthew Dillon /* retrieve ID, public point and curve parameters of EC key */
750*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
751*ba1276acSMatthew Dillon if (rv != CKR_OK) {
752*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
753*ba1276acSMatthew Dillon goto fail;
754*ba1276acSMatthew Dillon }
755*ba1276acSMatthew Dillon
756*ba1276acSMatthew Dillon ec = EC_KEY_new();
757*ba1276acSMatthew Dillon if (ec == NULL) {
758*ba1276acSMatthew Dillon error("EC_KEY_new failed");
759*ba1276acSMatthew Dillon goto fail;
760*ba1276acSMatthew Dillon }
761*ba1276acSMatthew Dillon
762*ba1276acSMatthew Dillon attrp = key_attr[2].pValue;
763*ba1276acSMatthew Dillon group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
764*ba1276acSMatthew Dillon if (group == NULL) {
765*ba1276acSMatthew Dillon ossl_error("d2i_ECPKParameters failed");
766*ba1276acSMatthew Dillon goto fail;
767*ba1276acSMatthew Dillon }
768*ba1276acSMatthew Dillon
769*ba1276acSMatthew Dillon if (EC_KEY_set_group(ec, group) == 0) {
770*ba1276acSMatthew Dillon ossl_error("EC_KEY_set_group failed");
771*ba1276acSMatthew Dillon goto fail;
772*ba1276acSMatthew Dillon }
773*ba1276acSMatthew Dillon
774*ba1276acSMatthew Dillon if (key_attr[1].ulValueLen <= 2) {
775*ba1276acSMatthew Dillon error("CKA_EC_POINT too small");
776*ba1276acSMatthew Dillon goto fail;
777*ba1276acSMatthew Dillon }
778*ba1276acSMatthew Dillon
779*ba1276acSMatthew Dillon attrp = key_attr[1].pValue;
780*ba1276acSMatthew Dillon octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
781*ba1276acSMatthew Dillon if (octet == NULL) {
782*ba1276acSMatthew Dillon ossl_error("d2i_ASN1_OCTET_STRING failed");
783*ba1276acSMatthew Dillon goto fail;
784*ba1276acSMatthew Dillon }
785*ba1276acSMatthew Dillon attrp = octet->data;
786*ba1276acSMatthew Dillon if (o2i_ECPublicKey(&ec, &attrp, octet->length) == NULL) {
787*ba1276acSMatthew Dillon ossl_error("o2i_ECPublicKey failed");
788*ba1276acSMatthew Dillon goto fail;
789*ba1276acSMatthew Dillon }
790*ba1276acSMatthew Dillon
791*ba1276acSMatthew Dillon nid = sshkey_ecdsa_key_to_nid(ec);
792*ba1276acSMatthew Dillon if (nid < 0) {
793*ba1276acSMatthew Dillon error("couldn't get curve nid");
794*ba1276acSMatthew Dillon goto fail;
795*ba1276acSMatthew Dillon }
796*ba1276acSMatthew Dillon
797*ba1276acSMatthew Dillon if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
798*ba1276acSMatthew Dillon goto fail;
799*ba1276acSMatthew Dillon
800*ba1276acSMatthew Dillon key = sshkey_new(KEY_UNSPEC);
801*ba1276acSMatthew Dillon if (key == NULL) {
802*ba1276acSMatthew Dillon error("sshkey_new failed");
803*ba1276acSMatthew Dillon goto fail;
804*ba1276acSMatthew Dillon }
805*ba1276acSMatthew Dillon
806*ba1276acSMatthew Dillon key->ecdsa = ec;
807*ba1276acSMatthew Dillon key->ecdsa_nid = nid;
808*ba1276acSMatthew Dillon key->type = KEY_ECDSA;
809*ba1276acSMatthew Dillon key->flags |= SSHKEY_FLAG_EXT;
810*ba1276acSMatthew Dillon ec = NULL; /* now owned by key */
811*ba1276acSMatthew Dillon
812*ba1276acSMatthew Dillon fail:
813*ba1276acSMatthew Dillon for (i = 0; i < 3; i++)
814*ba1276acSMatthew Dillon free(key_attr[i].pValue);
815*ba1276acSMatthew Dillon if (ec)
816*ba1276acSMatthew Dillon EC_KEY_free(ec);
817*ba1276acSMatthew Dillon if (group)
818*ba1276acSMatthew Dillon EC_GROUP_free(group);
819*ba1276acSMatthew Dillon if (octet)
820*ba1276acSMatthew Dillon ASN1_OCTET_STRING_free(octet);
821*ba1276acSMatthew Dillon
822*ba1276acSMatthew Dillon return (key);
823*ba1276acSMatthew Dillon }
824*ba1276acSMatthew Dillon #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
825*ba1276acSMatthew Dillon
826*ba1276acSMatthew Dillon static struct sshkey *
pkcs11_fetch_rsa_pubkey(struct pkcs11_provider * p,CK_ULONG slotidx,CK_OBJECT_HANDLE * obj)827*ba1276acSMatthew Dillon pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
828*ba1276acSMatthew Dillon CK_OBJECT_HANDLE *obj)
829*ba1276acSMatthew Dillon {
830*ba1276acSMatthew Dillon CK_ATTRIBUTE key_attr[3];
831*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
832*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f = NULL;
833*ba1276acSMatthew Dillon CK_RV rv;
834*ba1276acSMatthew Dillon RSA *rsa = NULL;
835*ba1276acSMatthew Dillon BIGNUM *rsa_n, *rsa_e;
836*ba1276acSMatthew Dillon struct sshkey *key = NULL;
837*ba1276acSMatthew Dillon int i;
838*ba1276acSMatthew Dillon
839*ba1276acSMatthew Dillon memset(&key_attr, 0, sizeof(key_attr));
840*ba1276acSMatthew Dillon key_attr[0].type = CKA_ID;
841*ba1276acSMatthew Dillon key_attr[1].type = CKA_MODULUS;
842*ba1276acSMatthew Dillon key_attr[2].type = CKA_PUBLIC_EXPONENT;
843*ba1276acSMatthew Dillon
844*ba1276acSMatthew Dillon session = p->slotinfo[slotidx].session;
845*ba1276acSMatthew Dillon f = p->function_list;
846*ba1276acSMatthew Dillon
847*ba1276acSMatthew Dillon /* figure out size of the attributes */
848*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
849*ba1276acSMatthew Dillon if (rv != CKR_OK) {
850*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
851*ba1276acSMatthew Dillon return (NULL);
852*ba1276acSMatthew Dillon }
853*ba1276acSMatthew Dillon
854*ba1276acSMatthew Dillon /*
855*ba1276acSMatthew Dillon * Allow CKA_ID (always first attribute) to be empty, but
856*ba1276acSMatthew Dillon * ensure that none of the others are zero length.
857*ba1276acSMatthew Dillon * XXX assumes CKA_ID is always first.
858*ba1276acSMatthew Dillon */
859*ba1276acSMatthew Dillon if (key_attr[1].ulValueLen == 0 ||
860*ba1276acSMatthew Dillon key_attr[2].ulValueLen == 0) {
861*ba1276acSMatthew Dillon error("invalid attribute length");
862*ba1276acSMatthew Dillon return (NULL);
863*ba1276acSMatthew Dillon }
864*ba1276acSMatthew Dillon
865*ba1276acSMatthew Dillon /* allocate buffers for attributes */
866*ba1276acSMatthew Dillon for (i = 0; i < 3; i++)
867*ba1276acSMatthew Dillon if (key_attr[i].ulValueLen > 0)
868*ba1276acSMatthew Dillon key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
869*ba1276acSMatthew Dillon
870*ba1276acSMatthew Dillon /* retrieve ID, modulus and public exponent of RSA key */
871*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
872*ba1276acSMatthew Dillon if (rv != CKR_OK) {
873*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
874*ba1276acSMatthew Dillon goto fail;
875*ba1276acSMatthew Dillon }
876*ba1276acSMatthew Dillon
877*ba1276acSMatthew Dillon rsa = RSA_new();
878*ba1276acSMatthew Dillon if (rsa == NULL) {
879*ba1276acSMatthew Dillon error("RSA_new failed");
880*ba1276acSMatthew Dillon goto fail;
881*ba1276acSMatthew Dillon }
882*ba1276acSMatthew Dillon
883*ba1276acSMatthew Dillon rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
884*ba1276acSMatthew Dillon rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
885*ba1276acSMatthew Dillon if (rsa_n == NULL || rsa_e == NULL) {
886*ba1276acSMatthew Dillon error("BN_bin2bn failed");
887*ba1276acSMatthew Dillon goto fail;
888*ba1276acSMatthew Dillon }
889*ba1276acSMatthew Dillon if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
890*ba1276acSMatthew Dillon fatal_f("set key");
891*ba1276acSMatthew Dillon rsa_n = rsa_e = NULL; /* transferred */
892*ba1276acSMatthew Dillon
893*ba1276acSMatthew Dillon if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
894*ba1276acSMatthew Dillon goto fail;
895*ba1276acSMatthew Dillon
896*ba1276acSMatthew Dillon key = sshkey_new(KEY_UNSPEC);
897*ba1276acSMatthew Dillon if (key == NULL) {
898*ba1276acSMatthew Dillon error("sshkey_new failed");
899*ba1276acSMatthew Dillon goto fail;
900*ba1276acSMatthew Dillon }
901*ba1276acSMatthew Dillon
902*ba1276acSMatthew Dillon key->rsa = rsa;
903*ba1276acSMatthew Dillon key->type = KEY_RSA;
904*ba1276acSMatthew Dillon key->flags |= SSHKEY_FLAG_EXT;
905*ba1276acSMatthew Dillon rsa = NULL; /* now owned by key */
906*ba1276acSMatthew Dillon
907*ba1276acSMatthew Dillon fail:
908*ba1276acSMatthew Dillon for (i = 0; i < 3; i++)
909*ba1276acSMatthew Dillon free(key_attr[i].pValue);
910*ba1276acSMatthew Dillon RSA_free(rsa);
911*ba1276acSMatthew Dillon
912*ba1276acSMatthew Dillon return (key);
913*ba1276acSMatthew Dillon }
914*ba1276acSMatthew Dillon
915*ba1276acSMatthew Dillon static int
pkcs11_fetch_x509_pubkey(struct pkcs11_provider * p,CK_ULONG slotidx,CK_OBJECT_HANDLE * obj,struct sshkey ** keyp,char ** labelp)916*ba1276acSMatthew Dillon pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
917*ba1276acSMatthew Dillon CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
918*ba1276acSMatthew Dillon {
919*ba1276acSMatthew Dillon CK_ATTRIBUTE cert_attr[3];
920*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
921*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f = NULL;
922*ba1276acSMatthew Dillon CK_RV rv;
923*ba1276acSMatthew Dillon X509 *x509 = NULL;
924*ba1276acSMatthew Dillon X509_NAME *x509_name = NULL;
925*ba1276acSMatthew Dillon EVP_PKEY *evp;
926*ba1276acSMatthew Dillon RSA *rsa = NULL;
927*ba1276acSMatthew Dillon #ifdef OPENSSL_HAS_ECC
928*ba1276acSMatthew Dillon EC_KEY *ec = NULL;
929*ba1276acSMatthew Dillon #endif
930*ba1276acSMatthew Dillon struct sshkey *key = NULL;
931*ba1276acSMatthew Dillon int i;
932*ba1276acSMatthew Dillon #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
933*ba1276acSMatthew Dillon int nid;
934*ba1276acSMatthew Dillon #endif
935*ba1276acSMatthew Dillon const u_char *cp;
936*ba1276acSMatthew Dillon char *subject = NULL;
937*ba1276acSMatthew Dillon
938*ba1276acSMatthew Dillon *keyp = NULL;
939*ba1276acSMatthew Dillon *labelp = NULL;
940*ba1276acSMatthew Dillon
941*ba1276acSMatthew Dillon memset(&cert_attr, 0, sizeof(cert_attr));
942*ba1276acSMatthew Dillon cert_attr[0].type = CKA_ID;
943*ba1276acSMatthew Dillon cert_attr[1].type = CKA_SUBJECT;
944*ba1276acSMatthew Dillon cert_attr[2].type = CKA_VALUE;
945*ba1276acSMatthew Dillon
946*ba1276acSMatthew Dillon session = p->slotinfo[slotidx].session;
947*ba1276acSMatthew Dillon f = p->function_list;
948*ba1276acSMatthew Dillon
949*ba1276acSMatthew Dillon /* figure out size of the attributes */
950*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
951*ba1276acSMatthew Dillon if (rv != CKR_OK) {
952*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
953*ba1276acSMatthew Dillon return -1;
954*ba1276acSMatthew Dillon }
955*ba1276acSMatthew Dillon
956*ba1276acSMatthew Dillon /*
957*ba1276acSMatthew Dillon * Allow CKA_ID (always first attribute) to be empty, but
958*ba1276acSMatthew Dillon * ensure that none of the others are zero length.
959*ba1276acSMatthew Dillon * XXX assumes CKA_ID is always first.
960*ba1276acSMatthew Dillon */
961*ba1276acSMatthew Dillon if (cert_attr[1].ulValueLen == 0 ||
962*ba1276acSMatthew Dillon cert_attr[2].ulValueLen == 0) {
963*ba1276acSMatthew Dillon error("invalid attribute length");
964*ba1276acSMatthew Dillon return -1;
965*ba1276acSMatthew Dillon }
966*ba1276acSMatthew Dillon
967*ba1276acSMatthew Dillon /* allocate buffers for attributes */
968*ba1276acSMatthew Dillon for (i = 0; i < 3; i++)
969*ba1276acSMatthew Dillon if (cert_attr[i].ulValueLen > 0)
970*ba1276acSMatthew Dillon cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
971*ba1276acSMatthew Dillon
972*ba1276acSMatthew Dillon /* retrieve ID, subject and value of certificate */
973*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
974*ba1276acSMatthew Dillon if (rv != CKR_OK) {
975*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
976*ba1276acSMatthew Dillon goto out;
977*ba1276acSMatthew Dillon }
978*ba1276acSMatthew Dillon
979*ba1276acSMatthew Dillon /* Decode DER-encoded cert subject */
980*ba1276acSMatthew Dillon cp = cert_attr[1].pValue;
981*ba1276acSMatthew Dillon if ((x509_name = d2i_X509_NAME(NULL, &cp,
982*ba1276acSMatthew Dillon cert_attr[1].ulValueLen)) == NULL ||
983*ba1276acSMatthew Dillon (subject = X509_NAME_oneline(x509_name, NULL, 0)) == NULL)
984*ba1276acSMatthew Dillon subject = xstrdup("invalid subject");
985*ba1276acSMatthew Dillon X509_NAME_free(x509_name);
986*ba1276acSMatthew Dillon
987*ba1276acSMatthew Dillon cp = cert_attr[2].pValue;
988*ba1276acSMatthew Dillon if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
989*ba1276acSMatthew Dillon error("d2i_x509 failed");
990*ba1276acSMatthew Dillon goto out;
991*ba1276acSMatthew Dillon }
992*ba1276acSMatthew Dillon
993*ba1276acSMatthew Dillon if ((evp = X509_get_pubkey(x509)) == NULL) {
994*ba1276acSMatthew Dillon error("X509_get_pubkey failed");
995*ba1276acSMatthew Dillon goto out;
996*ba1276acSMatthew Dillon }
997*ba1276acSMatthew Dillon
998*ba1276acSMatthew Dillon if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
999*ba1276acSMatthew Dillon if (EVP_PKEY_get0_RSA(evp) == NULL) {
1000*ba1276acSMatthew Dillon error("invalid x509; no rsa key");
1001*ba1276acSMatthew Dillon goto out;
1002*ba1276acSMatthew Dillon }
1003*ba1276acSMatthew Dillon if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) == NULL) {
1004*ba1276acSMatthew Dillon error("RSAPublicKey_dup failed");
1005*ba1276acSMatthew Dillon goto out;
1006*ba1276acSMatthew Dillon }
1007*ba1276acSMatthew Dillon
1008*ba1276acSMatthew Dillon if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
1009*ba1276acSMatthew Dillon goto out;
1010*ba1276acSMatthew Dillon
1011*ba1276acSMatthew Dillon key = sshkey_new(KEY_UNSPEC);
1012*ba1276acSMatthew Dillon if (key == NULL) {
1013*ba1276acSMatthew Dillon error("sshkey_new failed");
1014*ba1276acSMatthew Dillon goto out;
1015*ba1276acSMatthew Dillon }
1016*ba1276acSMatthew Dillon
1017*ba1276acSMatthew Dillon key->rsa = rsa;
1018*ba1276acSMatthew Dillon key->type = KEY_RSA;
1019*ba1276acSMatthew Dillon key->flags |= SSHKEY_FLAG_EXT;
1020*ba1276acSMatthew Dillon rsa = NULL; /* now owned by key */
1021*ba1276acSMatthew Dillon #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
1022*ba1276acSMatthew Dillon } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
1023*ba1276acSMatthew Dillon if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
1024*ba1276acSMatthew Dillon error("invalid x509; no ec key");
1025*ba1276acSMatthew Dillon goto out;
1026*ba1276acSMatthew Dillon }
1027*ba1276acSMatthew Dillon if ((ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(evp))) == NULL) {
1028*ba1276acSMatthew Dillon error("EC_KEY_dup failed");
1029*ba1276acSMatthew Dillon goto out;
1030*ba1276acSMatthew Dillon }
1031*ba1276acSMatthew Dillon
1032*ba1276acSMatthew Dillon nid = sshkey_ecdsa_key_to_nid(ec);
1033*ba1276acSMatthew Dillon if (nid < 0) {
1034*ba1276acSMatthew Dillon error("couldn't get curve nid");
1035*ba1276acSMatthew Dillon goto out;
1036*ba1276acSMatthew Dillon }
1037*ba1276acSMatthew Dillon
1038*ba1276acSMatthew Dillon if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
1039*ba1276acSMatthew Dillon goto out;
1040*ba1276acSMatthew Dillon
1041*ba1276acSMatthew Dillon key = sshkey_new(KEY_UNSPEC);
1042*ba1276acSMatthew Dillon if (key == NULL) {
1043*ba1276acSMatthew Dillon error("sshkey_new failed");
1044*ba1276acSMatthew Dillon goto out;
1045*ba1276acSMatthew Dillon }
1046*ba1276acSMatthew Dillon
1047*ba1276acSMatthew Dillon key->ecdsa = ec;
1048*ba1276acSMatthew Dillon key->ecdsa_nid = nid;
1049*ba1276acSMatthew Dillon key->type = KEY_ECDSA;
1050*ba1276acSMatthew Dillon key->flags |= SSHKEY_FLAG_EXT;
1051*ba1276acSMatthew Dillon ec = NULL; /* now owned by key */
1052*ba1276acSMatthew Dillon #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
1053*ba1276acSMatthew Dillon } else {
1054*ba1276acSMatthew Dillon error("unknown certificate key type");
1055*ba1276acSMatthew Dillon goto out;
1056*ba1276acSMatthew Dillon }
1057*ba1276acSMatthew Dillon out:
1058*ba1276acSMatthew Dillon for (i = 0; i < 3; i++)
1059*ba1276acSMatthew Dillon free(cert_attr[i].pValue);
1060*ba1276acSMatthew Dillon X509_free(x509);
1061*ba1276acSMatthew Dillon RSA_free(rsa);
1062*ba1276acSMatthew Dillon #ifdef OPENSSL_HAS_ECC
1063*ba1276acSMatthew Dillon EC_KEY_free(ec);
1064*ba1276acSMatthew Dillon #endif
1065*ba1276acSMatthew Dillon if (key == NULL) {
1066*ba1276acSMatthew Dillon free(subject);
1067*ba1276acSMatthew Dillon return -1;
1068*ba1276acSMatthew Dillon }
1069*ba1276acSMatthew Dillon /* success */
1070*ba1276acSMatthew Dillon *keyp = key;
1071*ba1276acSMatthew Dillon *labelp = subject;
1072*ba1276acSMatthew Dillon return 0;
1073*ba1276acSMatthew Dillon }
1074*ba1276acSMatthew Dillon
1075*ba1276acSMatthew Dillon #if 0
1076*ba1276acSMatthew Dillon static int
1077*ba1276acSMatthew Dillon have_rsa_key(const RSA *rsa)
1078*ba1276acSMatthew Dillon {
1079*ba1276acSMatthew Dillon const BIGNUM *rsa_n, *rsa_e;
1080*ba1276acSMatthew Dillon
1081*ba1276acSMatthew Dillon RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
1082*ba1276acSMatthew Dillon return rsa_n != NULL && rsa_e != NULL;
1083*ba1276acSMatthew Dillon }
1084*ba1276acSMatthew Dillon #endif
1085*ba1276acSMatthew Dillon
1086*ba1276acSMatthew Dillon static void
note_key(struct pkcs11_provider * p,CK_ULONG slotidx,const char * context,struct sshkey * key)1087*ba1276acSMatthew Dillon note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
1088*ba1276acSMatthew Dillon struct sshkey *key)
1089*ba1276acSMatthew Dillon {
1090*ba1276acSMatthew Dillon char *fp;
1091*ba1276acSMatthew Dillon
1092*ba1276acSMatthew Dillon if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
1093*ba1276acSMatthew Dillon SSH_FP_DEFAULT)) == NULL) {
1094*ba1276acSMatthew Dillon error_f("sshkey_fingerprint failed");
1095*ba1276acSMatthew Dillon return;
1096*ba1276acSMatthew Dillon }
1097*ba1276acSMatthew Dillon debug2("%s: provider %s slot %lu: %s %s", context, p->name,
1098*ba1276acSMatthew Dillon (u_long)slotidx, sshkey_type(key), fp);
1099*ba1276acSMatthew Dillon free(fp);
1100*ba1276acSMatthew Dillon }
1101*ba1276acSMatthew Dillon
1102*ba1276acSMatthew Dillon /*
1103*ba1276acSMatthew Dillon * lookup certificates for token in slot identified by slotidx,
1104*ba1276acSMatthew Dillon * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1105*ba1276acSMatthew Dillon * keysp points to an (possibly empty) array with *nkeys keys.
1106*ba1276acSMatthew Dillon */
1107*ba1276acSMatthew Dillon static int
pkcs11_fetch_certs(struct pkcs11_provider * p,CK_ULONG slotidx,struct sshkey *** keysp,char *** labelsp,int * nkeys)1108*ba1276acSMatthew Dillon pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
1109*ba1276acSMatthew Dillon struct sshkey ***keysp, char ***labelsp, int *nkeys)
1110*ba1276acSMatthew Dillon {
1111*ba1276acSMatthew Dillon struct sshkey *key = NULL;
1112*ba1276acSMatthew Dillon CK_OBJECT_CLASS key_class;
1113*ba1276acSMatthew Dillon CK_ATTRIBUTE key_attr[1];
1114*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
1115*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f = NULL;
1116*ba1276acSMatthew Dillon CK_RV rv;
1117*ba1276acSMatthew Dillon CK_OBJECT_HANDLE obj;
1118*ba1276acSMatthew Dillon CK_ULONG n = 0;
1119*ba1276acSMatthew Dillon int ret = -1;
1120*ba1276acSMatthew Dillon char *label;
1121*ba1276acSMatthew Dillon
1122*ba1276acSMatthew Dillon memset(&key_attr, 0, sizeof(key_attr));
1123*ba1276acSMatthew Dillon memset(&obj, 0, sizeof(obj));
1124*ba1276acSMatthew Dillon
1125*ba1276acSMatthew Dillon key_class = CKO_CERTIFICATE;
1126*ba1276acSMatthew Dillon key_attr[0].type = CKA_CLASS;
1127*ba1276acSMatthew Dillon key_attr[0].pValue = &key_class;
1128*ba1276acSMatthew Dillon key_attr[0].ulValueLen = sizeof(key_class);
1129*ba1276acSMatthew Dillon
1130*ba1276acSMatthew Dillon session = p->slotinfo[slotidx].session;
1131*ba1276acSMatthew Dillon f = p->function_list;
1132*ba1276acSMatthew Dillon
1133*ba1276acSMatthew Dillon rv = f->C_FindObjectsInit(session, key_attr, 1);
1134*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1135*ba1276acSMatthew Dillon error("C_FindObjectsInit failed: %lu", rv);
1136*ba1276acSMatthew Dillon goto fail;
1137*ba1276acSMatthew Dillon }
1138*ba1276acSMatthew Dillon
1139*ba1276acSMatthew Dillon while (1) {
1140*ba1276acSMatthew Dillon CK_CERTIFICATE_TYPE ck_cert_type;
1141*ba1276acSMatthew Dillon
1142*ba1276acSMatthew Dillon rv = f->C_FindObjects(session, &obj, 1, &n);
1143*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1144*ba1276acSMatthew Dillon error("C_FindObjects failed: %lu", rv);
1145*ba1276acSMatthew Dillon goto fail;
1146*ba1276acSMatthew Dillon }
1147*ba1276acSMatthew Dillon if (n == 0)
1148*ba1276acSMatthew Dillon break;
1149*ba1276acSMatthew Dillon
1150*ba1276acSMatthew Dillon memset(&ck_cert_type, 0, sizeof(ck_cert_type));
1151*ba1276acSMatthew Dillon memset(&key_attr, 0, sizeof(key_attr));
1152*ba1276acSMatthew Dillon key_attr[0].type = CKA_CERTIFICATE_TYPE;
1153*ba1276acSMatthew Dillon key_attr[0].pValue = &ck_cert_type;
1154*ba1276acSMatthew Dillon key_attr[0].ulValueLen = sizeof(ck_cert_type);
1155*ba1276acSMatthew Dillon
1156*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, obj, key_attr, 1);
1157*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1158*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
1159*ba1276acSMatthew Dillon goto fail;
1160*ba1276acSMatthew Dillon }
1161*ba1276acSMatthew Dillon
1162*ba1276acSMatthew Dillon key = NULL;
1163*ba1276acSMatthew Dillon label = NULL;
1164*ba1276acSMatthew Dillon switch (ck_cert_type) {
1165*ba1276acSMatthew Dillon case CKC_X_509:
1166*ba1276acSMatthew Dillon if (pkcs11_fetch_x509_pubkey(p, slotidx, &obj,
1167*ba1276acSMatthew Dillon &key, &label) != 0) {
1168*ba1276acSMatthew Dillon error("failed to fetch key");
1169*ba1276acSMatthew Dillon continue;
1170*ba1276acSMatthew Dillon }
1171*ba1276acSMatthew Dillon break;
1172*ba1276acSMatthew Dillon default:
1173*ba1276acSMatthew Dillon error("skipping unsupported certificate type %lu",
1174*ba1276acSMatthew Dillon ck_cert_type);
1175*ba1276acSMatthew Dillon continue;
1176*ba1276acSMatthew Dillon }
1177*ba1276acSMatthew Dillon note_key(p, slotidx, __func__, key);
1178*ba1276acSMatthew Dillon if (pkcs11_key_included(keysp, nkeys, key)) {
1179*ba1276acSMatthew Dillon debug2_f("key already included");;
1180*ba1276acSMatthew Dillon sshkey_free(key);
1181*ba1276acSMatthew Dillon } else {
1182*ba1276acSMatthew Dillon /* expand key array and add key */
1183*ba1276acSMatthew Dillon *keysp = xrecallocarray(*keysp, *nkeys,
1184*ba1276acSMatthew Dillon *nkeys + 1, sizeof(struct sshkey *));
1185*ba1276acSMatthew Dillon (*keysp)[*nkeys] = key;
1186*ba1276acSMatthew Dillon if (labelsp != NULL) {
1187*ba1276acSMatthew Dillon *labelsp = xrecallocarray(*labelsp, *nkeys,
1188*ba1276acSMatthew Dillon *nkeys + 1, sizeof(char *));
1189*ba1276acSMatthew Dillon (*labelsp)[*nkeys] = xstrdup((char *)label);
1190*ba1276acSMatthew Dillon }
1191*ba1276acSMatthew Dillon *nkeys = *nkeys + 1;
1192*ba1276acSMatthew Dillon debug("have %d keys", *nkeys);
1193*ba1276acSMatthew Dillon }
1194*ba1276acSMatthew Dillon }
1195*ba1276acSMatthew Dillon
1196*ba1276acSMatthew Dillon ret = 0;
1197*ba1276acSMatthew Dillon fail:
1198*ba1276acSMatthew Dillon rv = f->C_FindObjectsFinal(session);
1199*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1200*ba1276acSMatthew Dillon error("C_FindObjectsFinal failed: %lu", rv);
1201*ba1276acSMatthew Dillon ret = -1;
1202*ba1276acSMatthew Dillon }
1203*ba1276acSMatthew Dillon
1204*ba1276acSMatthew Dillon return (ret);
1205*ba1276acSMatthew Dillon }
1206*ba1276acSMatthew Dillon
1207*ba1276acSMatthew Dillon /*
1208*ba1276acSMatthew Dillon * lookup public keys for token in slot identified by slotidx,
1209*ba1276acSMatthew Dillon * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
1210*ba1276acSMatthew Dillon * keysp points to an (possibly empty) array with *nkeys keys.
1211*ba1276acSMatthew Dillon */
1212*ba1276acSMatthew Dillon static int
pkcs11_fetch_keys(struct pkcs11_provider * p,CK_ULONG slotidx,struct sshkey *** keysp,char *** labelsp,int * nkeys)1213*ba1276acSMatthew Dillon pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1214*ba1276acSMatthew Dillon struct sshkey ***keysp, char ***labelsp, int *nkeys)
1215*ba1276acSMatthew Dillon {
1216*ba1276acSMatthew Dillon struct sshkey *key = NULL;
1217*ba1276acSMatthew Dillon CK_OBJECT_CLASS key_class;
1218*ba1276acSMatthew Dillon CK_ATTRIBUTE key_attr[2];
1219*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
1220*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f = NULL;
1221*ba1276acSMatthew Dillon CK_RV rv;
1222*ba1276acSMatthew Dillon CK_OBJECT_HANDLE obj;
1223*ba1276acSMatthew Dillon CK_ULONG n = 0;
1224*ba1276acSMatthew Dillon int ret = -1;
1225*ba1276acSMatthew Dillon
1226*ba1276acSMatthew Dillon memset(&key_attr, 0, sizeof(key_attr));
1227*ba1276acSMatthew Dillon memset(&obj, 0, sizeof(obj));
1228*ba1276acSMatthew Dillon
1229*ba1276acSMatthew Dillon key_class = CKO_PUBLIC_KEY;
1230*ba1276acSMatthew Dillon key_attr[0].type = CKA_CLASS;
1231*ba1276acSMatthew Dillon key_attr[0].pValue = &key_class;
1232*ba1276acSMatthew Dillon key_attr[0].ulValueLen = sizeof(key_class);
1233*ba1276acSMatthew Dillon
1234*ba1276acSMatthew Dillon session = p->slotinfo[slotidx].session;
1235*ba1276acSMatthew Dillon f = p->function_list;
1236*ba1276acSMatthew Dillon
1237*ba1276acSMatthew Dillon rv = f->C_FindObjectsInit(session, key_attr, 1);
1238*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1239*ba1276acSMatthew Dillon error("C_FindObjectsInit failed: %lu", rv);
1240*ba1276acSMatthew Dillon goto fail;
1241*ba1276acSMatthew Dillon }
1242*ba1276acSMatthew Dillon
1243*ba1276acSMatthew Dillon while (1) {
1244*ba1276acSMatthew Dillon CK_KEY_TYPE ck_key_type;
1245*ba1276acSMatthew Dillon CK_UTF8CHAR label[256];
1246*ba1276acSMatthew Dillon
1247*ba1276acSMatthew Dillon rv = f->C_FindObjects(session, &obj, 1, &n);
1248*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1249*ba1276acSMatthew Dillon error("C_FindObjects failed: %lu", rv);
1250*ba1276acSMatthew Dillon goto fail;
1251*ba1276acSMatthew Dillon }
1252*ba1276acSMatthew Dillon if (n == 0)
1253*ba1276acSMatthew Dillon break;
1254*ba1276acSMatthew Dillon
1255*ba1276acSMatthew Dillon memset(&ck_key_type, 0, sizeof(ck_key_type));
1256*ba1276acSMatthew Dillon memset(&key_attr, 0, sizeof(key_attr));
1257*ba1276acSMatthew Dillon key_attr[0].type = CKA_KEY_TYPE;
1258*ba1276acSMatthew Dillon key_attr[0].pValue = &ck_key_type;
1259*ba1276acSMatthew Dillon key_attr[0].ulValueLen = sizeof(ck_key_type);
1260*ba1276acSMatthew Dillon key_attr[1].type = CKA_LABEL;
1261*ba1276acSMatthew Dillon key_attr[1].pValue = &label;
1262*ba1276acSMatthew Dillon key_attr[1].ulValueLen = sizeof(label) - 1;
1263*ba1276acSMatthew Dillon
1264*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, obj, key_attr, 2);
1265*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1266*ba1276acSMatthew Dillon error("C_GetAttributeValue failed: %lu", rv);
1267*ba1276acSMatthew Dillon goto fail;
1268*ba1276acSMatthew Dillon }
1269*ba1276acSMatthew Dillon
1270*ba1276acSMatthew Dillon label[key_attr[1].ulValueLen] = '\0';
1271*ba1276acSMatthew Dillon
1272*ba1276acSMatthew Dillon switch (ck_key_type) {
1273*ba1276acSMatthew Dillon case CKK_RSA:
1274*ba1276acSMatthew Dillon key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1275*ba1276acSMatthew Dillon break;
1276*ba1276acSMatthew Dillon #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
1277*ba1276acSMatthew Dillon case CKK_ECDSA:
1278*ba1276acSMatthew Dillon key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1279*ba1276acSMatthew Dillon break;
1280*ba1276acSMatthew Dillon #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
1281*ba1276acSMatthew Dillon default:
1282*ba1276acSMatthew Dillon /* XXX print key type? */
1283*ba1276acSMatthew Dillon key = NULL;
1284*ba1276acSMatthew Dillon error("skipping unsupported key type");
1285*ba1276acSMatthew Dillon }
1286*ba1276acSMatthew Dillon
1287*ba1276acSMatthew Dillon if (key == NULL) {
1288*ba1276acSMatthew Dillon error("failed to fetch key");
1289*ba1276acSMatthew Dillon continue;
1290*ba1276acSMatthew Dillon }
1291*ba1276acSMatthew Dillon note_key(p, slotidx, __func__, key);
1292*ba1276acSMatthew Dillon if (pkcs11_key_included(keysp, nkeys, key)) {
1293*ba1276acSMatthew Dillon debug2_f("key already included");;
1294*ba1276acSMatthew Dillon sshkey_free(key);
1295*ba1276acSMatthew Dillon } else {
1296*ba1276acSMatthew Dillon /* expand key array and add key */
1297*ba1276acSMatthew Dillon *keysp = xrecallocarray(*keysp, *nkeys,
1298*ba1276acSMatthew Dillon *nkeys + 1, sizeof(struct sshkey *));
1299*ba1276acSMatthew Dillon (*keysp)[*nkeys] = key;
1300*ba1276acSMatthew Dillon if (labelsp != NULL) {
1301*ba1276acSMatthew Dillon *labelsp = xrecallocarray(*labelsp, *nkeys,
1302*ba1276acSMatthew Dillon *nkeys + 1, sizeof(char *));
1303*ba1276acSMatthew Dillon (*labelsp)[*nkeys] = xstrdup((char *)label);
1304*ba1276acSMatthew Dillon }
1305*ba1276acSMatthew Dillon *nkeys = *nkeys + 1;
1306*ba1276acSMatthew Dillon debug("have %d keys", *nkeys);
1307*ba1276acSMatthew Dillon }
1308*ba1276acSMatthew Dillon }
1309*ba1276acSMatthew Dillon
1310*ba1276acSMatthew Dillon ret = 0;
1311*ba1276acSMatthew Dillon fail:
1312*ba1276acSMatthew Dillon rv = f->C_FindObjectsFinal(session);
1313*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1314*ba1276acSMatthew Dillon error("C_FindObjectsFinal failed: %lu", rv);
1315*ba1276acSMatthew Dillon ret = -1;
1316*ba1276acSMatthew Dillon }
1317*ba1276acSMatthew Dillon
1318*ba1276acSMatthew Dillon return (ret);
1319*ba1276acSMatthew Dillon }
1320*ba1276acSMatthew Dillon
1321*ba1276acSMatthew Dillon #ifdef WITH_PKCS11_KEYGEN
1322*ba1276acSMatthew Dillon #define FILL_ATTR(attr, idx, typ, val, len) \
1323*ba1276acSMatthew Dillon { (attr[idx]).type=(typ); (attr[idx]).pValue=(val); (attr[idx]).ulValueLen=len; idx++; }
1324*ba1276acSMatthew Dillon
1325*ba1276acSMatthew Dillon static struct sshkey *
pkcs11_rsa_generate_private_key(struct pkcs11_provider * p,CK_ULONG slotidx,char * label,CK_ULONG bits,CK_BYTE keyid,u_int32_t * err)1326*ba1276acSMatthew Dillon pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1327*ba1276acSMatthew Dillon char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1328*ba1276acSMatthew Dillon {
1329*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
1330*ba1276acSMatthew Dillon char *plabel = label ? label : "";
1331*ba1276acSMatthew Dillon int npub = 0, npriv = 0;
1332*ba1276acSMatthew Dillon CK_RV rv;
1333*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
1334*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
1335*ba1276acSMatthew Dillon CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1336*ba1276acSMatthew Dillon CK_OBJECT_HANDLE pubKey, privKey;
1337*ba1276acSMatthew Dillon CK_ATTRIBUTE tpub[16], tpriv[16];
1338*ba1276acSMatthew Dillon CK_MECHANISM mech = {
1339*ba1276acSMatthew Dillon CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
1340*ba1276acSMatthew Dillon };
1341*ba1276acSMatthew Dillon CK_BYTE pubExponent[] = {
1342*ba1276acSMatthew Dillon 0x01, 0x00, 0x01 /* RSA_F4 in bytes */
1343*ba1276acSMatthew Dillon };
1344*ba1276acSMatthew Dillon pubkey_filter[0].pValue = &pubkey_class;
1345*ba1276acSMatthew Dillon cert_filter[0].pValue = &cert_class;
1346*ba1276acSMatthew Dillon
1347*ba1276acSMatthew Dillon *err = 0;
1348*ba1276acSMatthew Dillon
1349*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1350*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1351*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1352*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1353*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1354*ba1276acSMatthew Dillon sizeof(false_val));
1355*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1356*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1357*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_MODULUS_BITS, &bits, sizeof(bits));
1358*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_PUBLIC_EXPONENT, pubExponent,
1359*ba1276acSMatthew Dillon sizeof(pubExponent));
1360*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1361*ba1276acSMatthew Dillon
1362*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1363*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1364*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1365*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1366*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1367*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1368*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1369*ba1276acSMatthew Dillon sizeof(false_val));
1370*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1371*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1372*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1373*ba1276acSMatthew Dillon
1374*ba1276acSMatthew Dillon f = p->function_list;
1375*ba1276acSMatthew Dillon si = &p->slotinfo[slotidx];
1376*ba1276acSMatthew Dillon session = si->session;
1377*ba1276acSMatthew Dillon
1378*ba1276acSMatthew Dillon if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1379*ba1276acSMatthew Dillon &pubKey, &privKey)) != CKR_OK) {
1380*ba1276acSMatthew Dillon error_f("key generation failed: error 0x%lx", rv);
1381*ba1276acSMatthew Dillon *err = rv;
1382*ba1276acSMatthew Dillon return NULL;
1383*ba1276acSMatthew Dillon }
1384*ba1276acSMatthew Dillon
1385*ba1276acSMatthew Dillon return pkcs11_fetch_rsa_pubkey(p, slotidx, &pubKey);
1386*ba1276acSMatthew Dillon }
1387*ba1276acSMatthew Dillon
1388*ba1276acSMatthew Dillon static int
h2i(char c)1389*ba1276acSMatthew Dillon h2i(char c)
1390*ba1276acSMatthew Dillon {
1391*ba1276acSMatthew Dillon if (c >= '0' && c <= '9')
1392*ba1276acSMatthew Dillon return c - '0';
1393*ba1276acSMatthew Dillon else if (c >= 'a' && c <= 'f')
1394*ba1276acSMatthew Dillon return c - 'a' + 10;
1395*ba1276acSMatthew Dillon else if (c >= 'A' && c <= 'F')
1396*ba1276acSMatthew Dillon return c - 'A' + 10;
1397*ba1276acSMatthew Dillon else
1398*ba1276acSMatthew Dillon return -1;
1399*ba1276acSMatthew Dillon }
1400*ba1276acSMatthew Dillon
1401*ba1276acSMatthew Dillon static int
pkcs11_decode_hex(const char * hex,unsigned char ** dest,size_t * rlen)1402*ba1276acSMatthew Dillon pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen)
1403*ba1276acSMatthew Dillon {
1404*ba1276acSMatthew Dillon size_t i, len;
1405*ba1276acSMatthew Dillon
1406*ba1276acSMatthew Dillon if (dest)
1407*ba1276acSMatthew Dillon *dest = NULL;
1408*ba1276acSMatthew Dillon if (rlen)
1409*ba1276acSMatthew Dillon *rlen = 0;
1410*ba1276acSMatthew Dillon
1411*ba1276acSMatthew Dillon if ((len = strlen(hex)) % 2)
1412*ba1276acSMatthew Dillon return -1;
1413*ba1276acSMatthew Dillon len /= 2;
1414*ba1276acSMatthew Dillon
1415*ba1276acSMatthew Dillon *dest = xmalloc(len);
1416*ba1276acSMatthew Dillon
1417*ba1276acSMatthew Dillon for (i = 0; i < len; i++) {
1418*ba1276acSMatthew Dillon int hi, low;
1419*ba1276acSMatthew Dillon
1420*ba1276acSMatthew Dillon hi = h2i(hex[2 * i]);
1421*ba1276acSMatthew Dillon lo = h2i(hex[(2 * i) + 1]);
1422*ba1276acSMatthew Dillon if (hi == -1 || lo == -1)
1423*ba1276acSMatthew Dillon return -1;
1424*ba1276acSMatthew Dillon (*dest)[i] = (hi << 4) | lo;
1425*ba1276acSMatthew Dillon }
1426*ba1276acSMatthew Dillon
1427*ba1276acSMatthew Dillon if (rlen)
1428*ba1276acSMatthew Dillon *rlen = len;
1429*ba1276acSMatthew Dillon
1430*ba1276acSMatthew Dillon return 0;
1431*ba1276acSMatthew Dillon }
1432*ba1276acSMatthew Dillon
1433*ba1276acSMatthew Dillon static struct ec_curve_info {
1434*ba1276acSMatthew Dillon const char *name;
1435*ba1276acSMatthew Dillon const char *oid;
1436*ba1276acSMatthew Dillon const char *oid_encoded;
1437*ba1276acSMatthew Dillon size_t size;
1438*ba1276acSMatthew Dillon } ec_curve_infos[] = {
1439*ba1276acSMatthew Dillon {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
1440*ba1276acSMatthew Dillon {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
1441*ba1276acSMatthew Dillon {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
1442*ba1276acSMatthew Dillon {NULL, NULL, NULL, 0},
1443*ba1276acSMatthew Dillon };
1444*ba1276acSMatthew Dillon
1445*ba1276acSMatthew Dillon static struct sshkey *
pkcs11_ecdsa_generate_private_key(struct pkcs11_provider * p,CK_ULONG slotidx,char * label,CK_ULONG bits,CK_BYTE keyid,u_int32_t * err)1446*ba1276acSMatthew Dillon pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx,
1447*ba1276acSMatthew Dillon char *label, CK_ULONG bits, CK_BYTE keyid, u_int32_t *err)
1448*ba1276acSMatthew Dillon {
1449*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
1450*ba1276acSMatthew Dillon char *plabel = label ? label : "";
1451*ba1276acSMatthew Dillon int i;
1452*ba1276acSMatthew Dillon size_t ecparams_size;
1453*ba1276acSMatthew Dillon unsigned char *ecparams = NULL;
1454*ba1276acSMatthew Dillon int npub = 0, npriv = 0;
1455*ba1276acSMatthew Dillon CK_RV rv;
1456*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
1457*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
1458*ba1276acSMatthew Dillon CK_BBOOL true_val = CK_TRUE, false_val = CK_FALSE;
1459*ba1276acSMatthew Dillon CK_OBJECT_HANDLE pubKey, privKey;
1460*ba1276acSMatthew Dillon CK_MECHANISM mech = {
1461*ba1276acSMatthew Dillon CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
1462*ba1276acSMatthew Dillon };
1463*ba1276acSMatthew Dillon CK_ATTRIBUTE tpub[16], tpriv[16];
1464*ba1276acSMatthew Dillon
1465*ba1276acSMatthew Dillon *err = 0;
1466*ba1276acSMatthew Dillon
1467*ba1276acSMatthew Dillon for (i = 0; ec_curve_infos[i].name; i++) {
1468*ba1276acSMatthew Dillon if (ec_curve_infos[i].size == bits)
1469*ba1276acSMatthew Dillon break;
1470*ba1276acSMatthew Dillon }
1471*ba1276acSMatthew Dillon if (!ec_curve_infos[i].name) {
1472*ba1276acSMatthew Dillon error_f("invalid key size %lu", bits);
1473*ba1276acSMatthew Dillon return NULL;
1474*ba1276acSMatthew Dillon }
1475*ba1276acSMatthew Dillon if (pkcs11_decode_hex(ec_curve_infos[i].oid_encoded, &ecparams,
1476*ba1276acSMatthew Dillon &ecparams_size) == -1) {
1477*ba1276acSMatthew Dillon error_f("invalid oid");
1478*ba1276acSMatthew Dillon return NULL;
1479*ba1276acSMatthew Dillon }
1480*ba1276acSMatthew Dillon
1481*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_TOKEN, &true_val, sizeof(true_val));
1482*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_LABEL, plabel, strlen(plabel));
1483*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_ENCRYPT, &false_val, sizeof(false_val));
1484*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_VERIFY, &true_val, sizeof(true_val));
1485*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_VERIFY_RECOVER, &false_val,
1486*ba1276acSMatthew Dillon sizeof(false_val));
1487*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_WRAP, &false_val, sizeof(false_val));
1488*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_DERIVE, &false_val, sizeof(false_val));
1489*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_EC_PARAMS, ecparams, ecparams_size);
1490*ba1276acSMatthew Dillon FILL_ATTR(tpub, npub, CKA_ID, &keyid, sizeof(keyid));
1491*ba1276acSMatthew Dillon
1492*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_TOKEN, &true_val, sizeof(true_val));
1493*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_LABEL, plabel, strlen(plabel));
1494*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_PRIVATE, &true_val, sizeof(true_val));
1495*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_SENSITIVE, &true_val, sizeof(true_val));
1496*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_DECRYPT, &false_val, sizeof(false_val));
1497*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_SIGN, &true_val, sizeof(true_val));
1498*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_SIGN_RECOVER, &false_val,
1499*ba1276acSMatthew Dillon sizeof(false_val));
1500*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_UNWRAP, &false_val, sizeof(false_val));
1501*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_DERIVE, &false_val, sizeof(false_val));
1502*ba1276acSMatthew Dillon FILL_ATTR(tpriv, npriv, CKA_ID, &keyid, sizeof(keyid));
1503*ba1276acSMatthew Dillon
1504*ba1276acSMatthew Dillon f = p->function_list;
1505*ba1276acSMatthew Dillon si = &p->slotinfo[slotidx];
1506*ba1276acSMatthew Dillon session = si->session;
1507*ba1276acSMatthew Dillon
1508*ba1276acSMatthew Dillon if ((rv = f->C_GenerateKeyPair(session, &mech, tpub, npub, tpriv, npriv,
1509*ba1276acSMatthew Dillon &pubKey, &privKey)) != CKR_OK) {
1510*ba1276acSMatthew Dillon error_f("key generation failed: error 0x%lx", rv);
1511*ba1276acSMatthew Dillon *err = rv;
1512*ba1276acSMatthew Dillon return NULL;
1513*ba1276acSMatthew Dillon }
1514*ba1276acSMatthew Dillon
1515*ba1276acSMatthew Dillon return pkcs11_fetch_ecdsa_pubkey(p, slotidx, &pubKey);
1516*ba1276acSMatthew Dillon }
1517*ba1276acSMatthew Dillon #endif /* WITH_PKCS11_KEYGEN */
1518*ba1276acSMatthew Dillon
1519*ba1276acSMatthew Dillon /*
1520*ba1276acSMatthew Dillon * register a new provider, fails if provider already exists. if
1521*ba1276acSMatthew Dillon * keyp is provided, fetch keys.
1522*ba1276acSMatthew Dillon */
1523*ba1276acSMatthew Dillon static int
pkcs11_register_provider(char * provider_id,char * pin,struct sshkey *** keyp,char *** labelsp,struct pkcs11_provider ** providerp,CK_ULONG user)1524*ba1276acSMatthew Dillon pkcs11_register_provider(char *provider_id, char *pin,
1525*ba1276acSMatthew Dillon struct sshkey ***keyp, char ***labelsp,
1526*ba1276acSMatthew Dillon struct pkcs11_provider **providerp, CK_ULONG user)
1527*ba1276acSMatthew Dillon {
1528*ba1276acSMatthew Dillon int nkeys, need_finalize = 0;
1529*ba1276acSMatthew Dillon int ret = -1;
1530*ba1276acSMatthew Dillon struct pkcs11_provider *p = NULL;
1531*ba1276acSMatthew Dillon void *handle = NULL;
1532*ba1276acSMatthew Dillon CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
1533*ba1276acSMatthew Dillon CK_RV rv;
1534*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f = NULL;
1535*ba1276acSMatthew Dillon CK_TOKEN_INFO *token;
1536*ba1276acSMatthew Dillon CK_ULONG i;
1537*ba1276acSMatthew Dillon
1538*ba1276acSMatthew Dillon if (providerp == NULL)
1539*ba1276acSMatthew Dillon goto fail;
1540*ba1276acSMatthew Dillon *providerp = NULL;
1541*ba1276acSMatthew Dillon
1542*ba1276acSMatthew Dillon if (keyp != NULL)
1543*ba1276acSMatthew Dillon *keyp = NULL;
1544*ba1276acSMatthew Dillon if (labelsp != NULL)
1545*ba1276acSMatthew Dillon *labelsp = NULL;
1546*ba1276acSMatthew Dillon
1547*ba1276acSMatthew Dillon if (pkcs11_provider_lookup(provider_id) != NULL) {
1548*ba1276acSMatthew Dillon debug_f("provider already registered: %s", provider_id);
1549*ba1276acSMatthew Dillon goto fail;
1550*ba1276acSMatthew Dillon }
1551*ba1276acSMatthew Dillon if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) {
1552*ba1276acSMatthew Dillon error("provider %s is not a PKCS11 library", provider_id);
1553*ba1276acSMatthew Dillon goto fail;
1554*ba1276acSMatthew Dillon }
1555*ba1276acSMatthew Dillon /* open shared pkcs11-library */
1556*ba1276acSMatthew Dillon if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
1557*ba1276acSMatthew Dillon error("dlopen %s failed: %s", provider_id, dlerror());
1558*ba1276acSMatthew Dillon goto fail;
1559*ba1276acSMatthew Dillon }
1560*ba1276acSMatthew Dillon if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
1561*ba1276acSMatthew Dillon fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
1562*ba1276acSMatthew Dillon p = xcalloc(1, sizeof(*p));
1563*ba1276acSMatthew Dillon p->name = xstrdup(provider_id);
1564*ba1276acSMatthew Dillon p->handle = handle;
1565*ba1276acSMatthew Dillon /* setup the pkcs11 callbacks */
1566*ba1276acSMatthew Dillon if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
1567*ba1276acSMatthew Dillon error("C_GetFunctionList for provider %s failed: %lu",
1568*ba1276acSMatthew Dillon provider_id, rv);
1569*ba1276acSMatthew Dillon goto fail;
1570*ba1276acSMatthew Dillon }
1571*ba1276acSMatthew Dillon p->function_list = f;
1572*ba1276acSMatthew Dillon if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
1573*ba1276acSMatthew Dillon error("C_Initialize for provider %s failed: %lu",
1574*ba1276acSMatthew Dillon provider_id, rv);
1575*ba1276acSMatthew Dillon goto fail;
1576*ba1276acSMatthew Dillon }
1577*ba1276acSMatthew Dillon need_finalize = 1;
1578*ba1276acSMatthew Dillon if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
1579*ba1276acSMatthew Dillon error("C_GetInfo for provider %s failed: %lu",
1580*ba1276acSMatthew Dillon provider_id, rv);
1581*ba1276acSMatthew Dillon goto fail;
1582*ba1276acSMatthew Dillon }
1583*ba1276acSMatthew Dillon debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d"
1584*ba1276acSMatthew Dillon " libraryDescription <%.*s> libraryVersion %d.%d",
1585*ba1276acSMatthew Dillon provider_id,
1586*ba1276acSMatthew Dillon RMSPACE(p->info.manufacturerID),
1587*ba1276acSMatthew Dillon p->info.cryptokiVersion.major,
1588*ba1276acSMatthew Dillon p->info.cryptokiVersion.minor,
1589*ba1276acSMatthew Dillon RMSPACE(p->info.libraryDescription),
1590*ba1276acSMatthew Dillon p->info.libraryVersion.major,
1591*ba1276acSMatthew Dillon p->info.libraryVersion.minor);
1592*ba1276acSMatthew Dillon if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
1593*ba1276acSMatthew Dillon error("C_GetSlotList failed: %lu", rv);
1594*ba1276acSMatthew Dillon goto fail;
1595*ba1276acSMatthew Dillon }
1596*ba1276acSMatthew Dillon if (p->nslots == 0) {
1597*ba1276acSMatthew Dillon debug_f("provider %s returned no slots", provider_id);
1598*ba1276acSMatthew Dillon ret = -SSH_PKCS11_ERR_NO_SLOTS;
1599*ba1276acSMatthew Dillon goto fail;
1600*ba1276acSMatthew Dillon }
1601*ba1276acSMatthew Dillon p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
1602*ba1276acSMatthew Dillon if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
1603*ba1276acSMatthew Dillon != CKR_OK) {
1604*ba1276acSMatthew Dillon error("C_GetSlotList for provider %s failed: %lu",
1605*ba1276acSMatthew Dillon provider_id, rv);
1606*ba1276acSMatthew Dillon goto fail;
1607*ba1276acSMatthew Dillon }
1608*ba1276acSMatthew Dillon p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
1609*ba1276acSMatthew Dillon p->valid = 1;
1610*ba1276acSMatthew Dillon nkeys = 0;
1611*ba1276acSMatthew Dillon for (i = 0; i < p->nslots; i++) {
1612*ba1276acSMatthew Dillon token = &p->slotinfo[i].token;
1613*ba1276acSMatthew Dillon if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
1614*ba1276acSMatthew Dillon != CKR_OK) {
1615*ba1276acSMatthew Dillon error("C_GetTokenInfo for provider %s slot %lu "
1616*ba1276acSMatthew Dillon "failed: %lu", provider_id, (u_long)i, rv);
1617*ba1276acSMatthew Dillon continue;
1618*ba1276acSMatthew Dillon }
1619*ba1276acSMatthew Dillon if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
1620*ba1276acSMatthew Dillon debug2_f("ignoring uninitialised token in "
1621*ba1276acSMatthew Dillon "provider %s slot %lu", provider_id, (u_long)i);
1622*ba1276acSMatthew Dillon continue;
1623*ba1276acSMatthew Dillon }
1624*ba1276acSMatthew Dillon debug("provider %s slot %lu: label <%.*s> "
1625*ba1276acSMatthew Dillon "manufacturerID <%.*s> model <%.*s> serial <%.*s> "
1626*ba1276acSMatthew Dillon "flags 0x%lx",
1627*ba1276acSMatthew Dillon provider_id, (unsigned long)i,
1628*ba1276acSMatthew Dillon RMSPACE(token->label), RMSPACE(token->manufacturerID),
1629*ba1276acSMatthew Dillon RMSPACE(token->model), RMSPACE(token->serialNumber),
1630*ba1276acSMatthew Dillon token->flags);
1631*ba1276acSMatthew Dillon /*
1632*ba1276acSMatthew Dillon * open session, login with pin and retrieve public
1633*ba1276acSMatthew Dillon * keys (if keyp is provided)
1634*ba1276acSMatthew Dillon */
1635*ba1276acSMatthew Dillon if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
1636*ba1276acSMatthew Dillon keyp == NULL)
1637*ba1276acSMatthew Dillon continue;
1638*ba1276acSMatthew Dillon pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1639*ba1276acSMatthew Dillon pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1640*ba1276acSMatthew Dillon if (nkeys == 0 && !p->slotinfo[i].logged_in &&
1641*ba1276acSMatthew Dillon pkcs11_interactive) {
1642*ba1276acSMatthew Dillon /*
1643*ba1276acSMatthew Dillon * Some tokens require login before they will
1644*ba1276acSMatthew Dillon * expose keys.
1645*ba1276acSMatthew Dillon */
1646*ba1276acSMatthew Dillon if (pkcs11_login_slot(p, &p->slotinfo[i],
1647*ba1276acSMatthew Dillon CKU_USER) < 0) {
1648*ba1276acSMatthew Dillon error("login failed");
1649*ba1276acSMatthew Dillon continue;
1650*ba1276acSMatthew Dillon }
1651*ba1276acSMatthew Dillon pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
1652*ba1276acSMatthew Dillon pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
1653*ba1276acSMatthew Dillon }
1654*ba1276acSMatthew Dillon }
1655*ba1276acSMatthew Dillon
1656*ba1276acSMatthew Dillon /* now owned by caller */
1657*ba1276acSMatthew Dillon *providerp = p;
1658*ba1276acSMatthew Dillon
1659*ba1276acSMatthew Dillon TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
1660*ba1276acSMatthew Dillon p->refcount++; /* add to provider list */
1661*ba1276acSMatthew Dillon
1662*ba1276acSMatthew Dillon return (nkeys);
1663*ba1276acSMatthew Dillon fail:
1664*ba1276acSMatthew Dillon if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
1665*ba1276acSMatthew Dillon error("C_Finalize for provider %s failed: %lu",
1666*ba1276acSMatthew Dillon provider_id, rv);
1667*ba1276acSMatthew Dillon if (p) {
1668*ba1276acSMatthew Dillon free(p->name);
1669*ba1276acSMatthew Dillon free(p->slotlist);
1670*ba1276acSMatthew Dillon free(p->slotinfo);
1671*ba1276acSMatthew Dillon free(p);
1672*ba1276acSMatthew Dillon }
1673*ba1276acSMatthew Dillon if (handle)
1674*ba1276acSMatthew Dillon dlclose(handle);
1675*ba1276acSMatthew Dillon if (ret > 0)
1676*ba1276acSMatthew Dillon ret = -1;
1677*ba1276acSMatthew Dillon return (ret);
1678*ba1276acSMatthew Dillon }
1679*ba1276acSMatthew Dillon
1680*ba1276acSMatthew Dillon /*
1681*ba1276acSMatthew Dillon * register a new provider and get number of keys hold by the token,
1682*ba1276acSMatthew Dillon * fails if provider already exists
1683*ba1276acSMatthew Dillon */
1684*ba1276acSMatthew Dillon int
pkcs11_add_provider(char * provider_id,char * pin,struct sshkey *** keyp,char *** labelsp)1685*ba1276acSMatthew Dillon pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1686*ba1276acSMatthew Dillon char ***labelsp)
1687*ba1276acSMatthew Dillon {
1688*ba1276acSMatthew Dillon struct pkcs11_provider *p = NULL;
1689*ba1276acSMatthew Dillon int nkeys;
1690*ba1276acSMatthew Dillon
1691*ba1276acSMatthew Dillon nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
1692*ba1276acSMatthew Dillon &p, CKU_USER);
1693*ba1276acSMatthew Dillon
1694*ba1276acSMatthew Dillon /* no keys found or some other error, de-register provider */
1695*ba1276acSMatthew Dillon if (nkeys <= 0 && p != NULL) {
1696*ba1276acSMatthew Dillon TAILQ_REMOVE(&pkcs11_providers, p, next);
1697*ba1276acSMatthew Dillon pkcs11_provider_finalize(p);
1698*ba1276acSMatthew Dillon pkcs11_provider_unref(p);
1699*ba1276acSMatthew Dillon }
1700*ba1276acSMatthew Dillon if (nkeys == 0)
1701*ba1276acSMatthew Dillon debug_f("provider %s returned no keys", provider_id);
1702*ba1276acSMatthew Dillon
1703*ba1276acSMatthew Dillon return (nkeys);
1704*ba1276acSMatthew Dillon }
1705*ba1276acSMatthew Dillon
1706*ba1276acSMatthew Dillon #ifdef WITH_PKCS11_KEYGEN
1707*ba1276acSMatthew Dillon struct sshkey *
pkcs11_gakp(char * provider_id,char * pin,unsigned int slotidx,char * label,unsigned int type,unsigned int bits,unsigned char keyid,u_int32_t * err)1708*ba1276acSMatthew Dillon pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
1709*ba1276acSMatthew Dillon unsigned int type, unsigned int bits, unsigned char keyid, u_int32_t *err)
1710*ba1276acSMatthew Dillon {
1711*ba1276acSMatthew Dillon struct pkcs11_provider *p = NULL;
1712*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
1713*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
1714*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
1715*ba1276acSMatthew Dillon struct sshkey *k = NULL;
1716*ba1276acSMatthew Dillon int ret = -1, reset_pin = 0, reset_provider = 0;
1717*ba1276acSMatthew Dillon CK_RV rv;
1718*ba1276acSMatthew Dillon
1719*ba1276acSMatthew Dillon *err = 0;
1720*ba1276acSMatthew Dillon
1721*ba1276acSMatthew Dillon if ((p = pkcs11_provider_lookup(provider_id)) != NULL)
1722*ba1276acSMatthew Dillon debug_f("provider \"%s\" available", provider_id);
1723*ba1276acSMatthew Dillon else if ((ret = pkcs11_register_provider(provider_id, pin, NULL, NULL,
1724*ba1276acSMatthew Dillon &p, CKU_SO)) < 0) {
1725*ba1276acSMatthew Dillon debug_f("could not register provider %s", provider_id);
1726*ba1276acSMatthew Dillon goto out;
1727*ba1276acSMatthew Dillon } else
1728*ba1276acSMatthew Dillon reset_provider = 1;
1729*ba1276acSMatthew Dillon
1730*ba1276acSMatthew Dillon f = p->function_list;
1731*ba1276acSMatthew Dillon si = &p->slotinfo[slotidx];
1732*ba1276acSMatthew Dillon session = si->session;
1733*ba1276acSMatthew Dillon
1734*ba1276acSMatthew Dillon if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1735*ba1276acSMatthew Dillon CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1736*ba1276acSMatthew Dillon debug_f("could not supply SO pin: %lu", rv);
1737*ba1276acSMatthew Dillon reset_pin = 0;
1738*ba1276acSMatthew Dillon } else
1739*ba1276acSMatthew Dillon reset_pin = 1;
1740*ba1276acSMatthew Dillon
1741*ba1276acSMatthew Dillon switch (type) {
1742*ba1276acSMatthew Dillon case KEY_RSA:
1743*ba1276acSMatthew Dillon if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label,
1744*ba1276acSMatthew Dillon bits, keyid, err)) == NULL) {
1745*ba1276acSMatthew Dillon debug_f("failed to generate RSA key");
1746*ba1276acSMatthew Dillon goto out;
1747*ba1276acSMatthew Dillon }
1748*ba1276acSMatthew Dillon break;
1749*ba1276acSMatthew Dillon case KEY_ECDSA:
1750*ba1276acSMatthew Dillon if ((k = pkcs11_ecdsa_generate_private_key(p, slotidx, label,
1751*ba1276acSMatthew Dillon bits, keyid, err)) == NULL) {
1752*ba1276acSMatthew Dillon debug_f("failed to generate ECDSA key");
1753*ba1276acSMatthew Dillon goto out;
1754*ba1276acSMatthew Dillon }
1755*ba1276acSMatthew Dillon break;
1756*ba1276acSMatthew Dillon default:
1757*ba1276acSMatthew Dillon *err = SSH_PKCS11_ERR_GENERIC;
1758*ba1276acSMatthew Dillon debug_f("unknown type %d", type);
1759*ba1276acSMatthew Dillon goto out;
1760*ba1276acSMatthew Dillon }
1761*ba1276acSMatthew Dillon
1762*ba1276acSMatthew Dillon out:
1763*ba1276acSMatthew Dillon if (reset_pin)
1764*ba1276acSMatthew Dillon f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1765*ba1276acSMatthew Dillon CK_INVALID_HANDLE);
1766*ba1276acSMatthew Dillon
1767*ba1276acSMatthew Dillon if (reset_provider)
1768*ba1276acSMatthew Dillon pkcs11_del_provider(provider_id);
1769*ba1276acSMatthew Dillon
1770*ba1276acSMatthew Dillon return (k);
1771*ba1276acSMatthew Dillon }
1772*ba1276acSMatthew Dillon
1773*ba1276acSMatthew Dillon struct sshkey *
pkcs11_destroy_keypair(char * provider_id,char * pin,unsigned long slotidx,unsigned char keyid,u_int32_t * err)1774*ba1276acSMatthew Dillon pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx,
1775*ba1276acSMatthew Dillon unsigned char keyid, u_int32_t *err)
1776*ba1276acSMatthew Dillon {
1777*ba1276acSMatthew Dillon struct pkcs11_provider *p = NULL;
1778*ba1276acSMatthew Dillon struct pkcs11_slotinfo *si;
1779*ba1276acSMatthew Dillon struct sshkey *k = NULL;
1780*ba1276acSMatthew Dillon int reset_pin = 0, reset_provider = 0;
1781*ba1276acSMatthew Dillon CK_ULONG nattrs;
1782*ba1276acSMatthew Dillon CK_FUNCTION_LIST *f;
1783*ba1276acSMatthew Dillon CK_SESSION_HANDLE session;
1784*ba1276acSMatthew Dillon CK_ATTRIBUTE attrs[16];
1785*ba1276acSMatthew Dillon CK_OBJECT_CLASS key_class;
1786*ba1276acSMatthew Dillon CK_KEY_TYPE key_type;
1787*ba1276acSMatthew Dillon CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
1788*ba1276acSMatthew Dillon CK_RV rv;
1789*ba1276acSMatthew Dillon
1790*ba1276acSMatthew Dillon *err = 0;
1791*ba1276acSMatthew Dillon
1792*ba1276acSMatthew Dillon if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
1793*ba1276acSMatthew Dillon debug_f("using provider \"%s\"", provider_id);
1794*ba1276acSMatthew Dillon } else if (pkcs11_register_provider(provider_id, pin, NULL, NULL, &p,
1795*ba1276acSMatthew Dillon CKU_SO) < 0) {
1796*ba1276acSMatthew Dillon debug_f("could not register provider %s",
1797*ba1276acSMatthew Dillon provider_id);
1798*ba1276acSMatthew Dillon goto out;
1799*ba1276acSMatthew Dillon } else
1800*ba1276acSMatthew Dillon reset_provider = 1;
1801*ba1276acSMatthew Dillon
1802*ba1276acSMatthew Dillon f = p->function_list;
1803*ba1276acSMatthew Dillon si = &p->slotinfo[slotidx];
1804*ba1276acSMatthew Dillon session = si->session;
1805*ba1276acSMatthew Dillon
1806*ba1276acSMatthew Dillon if ((rv = f->C_SetOperationState(session , pin, strlen(pin),
1807*ba1276acSMatthew Dillon CK_INVALID_HANDLE, CK_INVALID_HANDLE)) != CKR_OK) {
1808*ba1276acSMatthew Dillon debug_f("could not supply SO pin: %lu", rv);
1809*ba1276acSMatthew Dillon reset_pin = 0;
1810*ba1276acSMatthew Dillon } else
1811*ba1276acSMatthew Dillon reset_pin = 1;
1812*ba1276acSMatthew Dillon
1813*ba1276acSMatthew Dillon /* private key */
1814*ba1276acSMatthew Dillon nattrs = 0;
1815*ba1276acSMatthew Dillon key_class = CKO_PRIVATE_KEY;
1816*ba1276acSMatthew Dillon FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1817*ba1276acSMatthew Dillon FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1818*ba1276acSMatthew Dillon
1819*ba1276acSMatthew Dillon if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1820*ba1276acSMatthew Dillon obj != CK_INVALID_HANDLE) {
1821*ba1276acSMatthew Dillon if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1822*ba1276acSMatthew Dillon debug_f("could not destroy private key 0x%hhx",
1823*ba1276acSMatthew Dillon keyid);
1824*ba1276acSMatthew Dillon *err = rv;
1825*ba1276acSMatthew Dillon goto out;
1826*ba1276acSMatthew Dillon }
1827*ba1276acSMatthew Dillon }
1828*ba1276acSMatthew Dillon
1829*ba1276acSMatthew Dillon /* public key */
1830*ba1276acSMatthew Dillon nattrs = 0;
1831*ba1276acSMatthew Dillon key_class = CKO_PUBLIC_KEY;
1832*ba1276acSMatthew Dillon FILL_ATTR(attrs, nattrs, CKA_CLASS, &key_class, sizeof(key_class));
1833*ba1276acSMatthew Dillon FILL_ATTR(attrs, nattrs, CKA_ID, &keyid, sizeof(keyid));
1834*ba1276acSMatthew Dillon
1835*ba1276acSMatthew Dillon if (pkcs11_find(p, slotidx, attrs, nattrs, &obj) == 0 &&
1836*ba1276acSMatthew Dillon obj != CK_INVALID_HANDLE) {
1837*ba1276acSMatthew Dillon
1838*ba1276acSMatthew Dillon /* get key type */
1839*ba1276acSMatthew Dillon nattrs = 0;
1840*ba1276acSMatthew Dillon FILL_ATTR(attrs, nattrs, CKA_KEY_TYPE, &key_type,
1841*ba1276acSMatthew Dillon sizeof(key_type));
1842*ba1276acSMatthew Dillon rv = f->C_GetAttributeValue(session, obj, attrs, nattrs);
1843*ba1276acSMatthew Dillon if (rv != CKR_OK) {
1844*ba1276acSMatthew Dillon debug_f("could not get key type of public key 0x%hhx",
1845*ba1276acSMatthew Dillon keyid);
1846*ba1276acSMatthew Dillon *err = rv;
1847*ba1276acSMatthew Dillon key_type = -1;
1848*ba1276acSMatthew Dillon }
1849*ba1276acSMatthew Dillon if (key_type == CKK_RSA)
1850*ba1276acSMatthew Dillon k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
1851*ba1276acSMatthew Dillon else if (key_type == CKK_ECDSA)
1852*ba1276acSMatthew Dillon k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
1853*ba1276acSMatthew Dillon
1854*ba1276acSMatthew Dillon if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) {
1855*ba1276acSMatthew Dillon debug_f("could not destroy public key 0x%hhx", keyid);
1856*ba1276acSMatthew Dillon *err = rv;
1857*ba1276acSMatthew Dillon goto out;
1858*ba1276acSMatthew Dillon }
1859*ba1276acSMatthew Dillon }
1860*ba1276acSMatthew Dillon
1861*ba1276acSMatthew Dillon out:
1862*ba1276acSMatthew Dillon if (reset_pin)
1863*ba1276acSMatthew Dillon f->C_SetOperationState(session , NULL, 0, CK_INVALID_HANDLE,
1864*ba1276acSMatthew Dillon CK_INVALID_HANDLE);
1865*ba1276acSMatthew Dillon
1866*ba1276acSMatthew Dillon if (reset_provider)
1867*ba1276acSMatthew Dillon pkcs11_del_provider(provider_id);
1868*ba1276acSMatthew Dillon
1869*ba1276acSMatthew Dillon return (k);
1870*ba1276acSMatthew Dillon }
1871*ba1276acSMatthew Dillon #endif /* WITH_PKCS11_KEYGEN */
1872*ba1276acSMatthew Dillon #else /* ENABLE_PKCS11 */
1873*ba1276acSMatthew Dillon
1874*ba1276acSMatthew Dillon #include <sys/types.h>
1875*ba1276acSMatthew Dillon #include <stdarg.h>
1876*ba1276acSMatthew Dillon #include <stdio.h>
1877*ba1276acSMatthew Dillon
1878*ba1276acSMatthew Dillon #include "log.h"
1879*ba1276acSMatthew Dillon #include "sshkey.h"
1880*ba1276acSMatthew Dillon
1881*ba1276acSMatthew Dillon int
pkcs11_init(int interactive)1882*ba1276acSMatthew Dillon pkcs11_init(int interactive)
1883*ba1276acSMatthew Dillon {
1884*ba1276acSMatthew Dillon error("%s: dlopen() not supported", __func__);
1885*ba1276acSMatthew Dillon return (-1);
1886*ba1276acSMatthew Dillon }
1887*ba1276acSMatthew Dillon
1888*ba1276acSMatthew Dillon int
pkcs11_add_provider(char * provider_id,char * pin,struct sshkey *** keyp,char *** labelsp)1889*ba1276acSMatthew Dillon pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
1890*ba1276acSMatthew Dillon char ***labelsp)
1891*ba1276acSMatthew Dillon {
1892*ba1276acSMatthew Dillon error("%s: dlopen() not supported", __func__);
1893*ba1276acSMatthew Dillon return (-1);
1894*ba1276acSMatthew Dillon }
1895*ba1276acSMatthew Dillon
1896*ba1276acSMatthew Dillon void
pkcs11_terminate(void)1897*ba1276acSMatthew Dillon pkcs11_terminate(void)
1898*ba1276acSMatthew Dillon {
1899*ba1276acSMatthew Dillon error("%s: dlopen() not supported", __func__);
1900*ba1276acSMatthew Dillon }
1901*ba1276acSMatthew Dillon #endif /* ENABLE_PKCS11 */
1902