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