diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | ssh-pkcs11.c | 141 |
2 files changed, 108 insertions, 40 deletions
@@ -1,3 +1,10 @@ | |||
1 | 20131104 | ||
2 | - (djm) OpenBSD CVS Sync | ||
3 | - markus@cvs.openbsd.org 2013/11/02 20:03:54 | ||
4 | [ssh-pkcs11.c] | ||
5 | support pkcs#11 tokes that only provide x509 zerts instead of raw pubkeys; | ||
6 | fixes bz#1908; based on patch from Laurent Barbe; ok djm | ||
7 | |||
1 | 20131103 | 8 | 20131103 |
2 | - (dtucker) [openbsd-compat/bsd-misc.c] Include time.h for nanosleep. | 9 | - (dtucker) [openbsd-compat/bsd-misc.c] Include time.h for nanosleep. |
3 | From OpenSMTPD where it prevents "implicit declaration" warnings (it's | 10 | From OpenSMTPD where it prevents "implicit declaration" warnings (it's |
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 618c07526..6e8d2db36 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-pkcs11.c,v 1.8 2013/07/12 00:20:00 djm Exp $ */ | 1 | /* $OpenBSD: ssh-pkcs11.c,v 1.9 2013/11/02 20:03:54 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -31,6 +31,8 @@ | |||
31 | 31 | ||
32 | #include "openbsd-compat/sys-queue.h" | 32 | #include "openbsd-compat/sys-queue.h" |
33 | 33 | ||
34 | #include <openssl/x509.h> | ||
35 | |||
34 | #define CRYPTOKI_COMPAT | 36 | #define CRYPTOKI_COMPAT |
35 | #include "pkcs11.h" | 37 | #include "pkcs11.h" |
36 | 38 | ||
@@ -225,24 +227,19 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, | |||
225 | CK_OBJECT_HANDLE obj; | 227 | CK_OBJECT_HANDLE obj; |
226 | CK_ULONG tlen = 0; | 228 | CK_ULONG tlen = 0; |
227 | CK_RV rv; | 229 | CK_RV rv; |
228 | CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY; | 230 | CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY; |
229 | CK_BBOOL true_val = CK_TRUE; | 231 | CK_BBOOL true_val = CK_TRUE; |
230 | CK_MECHANISM mech = { | 232 | CK_MECHANISM mech = { |
231 | CKM_RSA_PKCS, NULL_PTR, 0 | 233 | CKM_RSA_PKCS, NULL_PTR, 0 |
232 | }; | 234 | }; |
233 | CK_ATTRIBUTE key_filter[] = { | 235 | CK_ATTRIBUTE key_filter[] = { |
234 | {CKA_CLASS, NULL, sizeof(private_key_class) }, | 236 | {CKA_CLASS, &private_key_class, sizeof(private_key_class) }, |
235 | {CKA_ID, NULL, 0}, | 237 | {CKA_ID, NULL, 0}, |
236 | {CKA_SIGN, NULL, sizeof(true_val) } | 238 | {CKA_SIGN, &true_val, sizeof(true_val) } |
237 | }; | 239 | }; |
238 | char *pin, prompt[1024]; | 240 | char *pin, prompt[1024]; |
239 | int rval = -1; | 241 | int rval = -1; |
240 | 242 | ||
241 | /* some compilers complain about non-constant initializer so we | ||
242 | use NULL in CK_ATTRIBUTE above and set the values here */ | ||
243 | key_filter[0].pValue = &private_key_class; | ||
244 | key_filter[2].pValue = &true_val; | ||
245 | |||
246 | if ((k11 = RSA_get_app_data(rsa)) == NULL) { | 243 | if ((k11 = RSA_get_app_data(rsa)) == NULL) { |
247 | error("RSA_get_app_data failed for rsa %p", rsa); | 244 | error("RSA_get_app_data failed for rsa %p", rsa); |
248 | return (-1); | 245 | return (-1); |
@@ -384,36 +381,73 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) | |||
384 | * add 'wrapped' public keys to the 'keysp' array and increment nkeys. | 381 | * add 'wrapped' public keys to the 'keysp' array and increment nkeys. |
385 | * keysp points to an (possibly empty) array with *nkeys keys. | 382 | * keysp points to an (possibly empty) array with *nkeys keys. |
386 | */ | 383 | */ |
384 | static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG, | ||
385 | CK_ATTRIBUTE [], CK_ATTRIBUTE [3], Key ***, int *) | ||
386 | __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE)))); | ||
387 | |||
388 | static int | ||
389 | pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, | ||
390 | Key ***keysp, int *nkeys) | ||
391 | { | ||
392 | CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; | ||
393 | CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; | ||
394 | CK_ATTRIBUTE pubkey_filter[] = { | ||
395 | { CKA_CLASS, &pubkey_class, sizeof(pubkey_class) } | ||
396 | }; | ||
397 | CK_ATTRIBUTE cert_filter[] = { | ||
398 | { CKA_CLASS, &cert_class, sizeof(cert_class) } | ||
399 | }; | ||
400 | CK_ATTRIBUTE pubkey_attribs[] = { | ||
401 | { CKA_ID, NULL, 0 }, | ||
402 | { CKA_MODULUS, NULL, 0 }, | ||
403 | { CKA_PUBLIC_EXPONENT, NULL, 0 } | ||
404 | }; | ||
405 | CK_ATTRIBUTE cert_attribs[] = { | ||
406 | { CKA_ID, NULL, 0 }, | ||
407 | { CKA_SUBJECT, NULL, 0 }, | ||
408 | { CKA_VALUE, NULL, 0 } | ||
409 | }; | ||
410 | |||
411 | if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs, | ||
412 | keysp, nkeys) < 0 || | ||
413 | pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs, | ||
414 | keysp, nkeys) < 0) | ||
415 | return (-1); | ||
416 | return (0); | ||
417 | } | ||
418 | |||
387 | static int | 419 | static int |
388 | pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, | 420 | pkcs11_key_included(Key ***keysp, int *nkeys, Key *key) |
389 | int *nkeys) | 421 | { |
422 | int i; | ||
423 | |||
424 | for (i = 0; i < *nkeys; i++) | ||
425 | if (key_equal(key, *keysp[i])) | ||
426 | return (1); | ||
427 | return (0); | ||
428 | } | ||
429 | |||
430 | static int | ||
431 | pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, | ||
432 | CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3], | ||
433 | Key ***keysp, int *nkeys) | ||
390 | { | 434 | { |
391 | Key *key; | 435 | Key *key; |
392 | RSA *rsa; | 436 | RSA *rsa; |
437 | X509 *x509; | ||
438 | EVP_PKEY *evp; | ||
393 | int i; | 439 | int i; |
440 | const u_char *cp; | ||
394 | CK_RV rv; | 441 | CK_RV rv; |
395 | CK_OBJECT_HANDLE obj; | 442 | CK_OBJECT_HANDLE obj; |
396 | CK_ULONG nfound; | 443 | CK_ULONG nfound; |
397 | CK_SESSION_HANDLE session; | 444 | CK_SESSION_HANDLE session; |
398 | CK_FUNCTION_LIST *f; | 445 | CK_FUNCTION_LIST *f; |
399 | CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; | ||
400 | CK_ATTRIBUTE pubkey_filter[] = { | ||
401 | { CKA_CLASS, NULL, sizeof(pubkey_class) } | ||
402 | }; | ||
403 | CK_ATTRIBUTE attribs[] = { | ||
404 | { CKA_ID, NULL, 0 }, | ||
405 | { CKA_MODULUS, NULL, 0 }, | ||
406 | { CKA_PUBLIC_EXPONENT, NULL, 0 } | ||
407 | }; | ||
408 | |||
409 | /* some compilers complain about non-constant initializer so we | ||
410 | use NULL in CK_ATTRIBUTE above and set the value here */ | ||
411 | pubkey_filter[0].pValue = &pubkey_class; | ||
412 | 446 | ||
413 | f = p->function_list; | 447 | f = p->function_list; |
414 | session = p->slotinfo[slotidx].session; | 448 | session = p->slotinfo[slotidx].session; |
415 | /* setup a filter the looks for public keys */ | 449 | /* setup a filter the looks for public keys */ |
416 | if ((rv = f->C_FindObjectsInit(session, pubkey_filter, 1)) != CKR_OK) { | 450 | if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) { |
417 | error("C_FindObjectsInit failed: %lu", rv); | 451 | error("C_FindObjectsInit failed: %lu", rv); |
418 | return (-1); | 452 | return (-1); |
419 | } | 453 | } |
@@ -441,32 +475,59 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, | |||
441 | /* allocate buffers for attributes */ | 475 | /* allocate buffers for attributes */ |
442 | for (i = 0; i < 3; i++) | 476 | for (i = 0; i < 3; i++) |
443 | attribs[i].pValue = xmalloc(attribs[i].ulValueLen); | 477 | attribs[i].pValue = xmalloc(attribs[i].ulValueLen); |
444 | /* retrieve ID, modulus and public exponent of RSA key */ | 478 | /* |
479 | * retrieve ID, modulus and public exponent of RSA key, | ||
480 | * or ID, subject and value for certificates. | ||
481 | */ | ||
482 | rsa = NULL; | ||
445 | if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) | 483 | if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) |
446 | != CKR_OK) { | 484 | != CKR_OK) { |
447 | error("C_GetAttributeValue failed: %lu", rv); | 485 | error("C_GetAttributeValue failed: %lu", rv); |
448 | } else if ((rsa = RSA_new()) == NULL) { | 486 | } else if (attribs[1].type == CKA_MODULUS ) { |
449 | error("RSA_new failed"); | 487 | if ((rsa = RSA_new()) == NULL) { |
488 | error("RSA_new failed"); | ||
489 | } else { | ||
490 | rsa->n = BN_bin2bn(attribs[1].pValue, | ||
491 | attribs[1].ulValueLen, NULL); | ||
492 | rsa->e = BN_bin2bn(attribs[2].pValue, | ||
493 | attribs[2].ulValueLen, NULL); | ||
494 | } | ||
450 | } else { | 495 | } else { |
451 | rsa->n = BN_bin2bn(attribs[1].pValue, | 496 | cp = attribs[2].pValue; |
452 | attribs[1].ulValueLen, NULL); | 497 | if ((x509 = X509_new()) == NULL) { |
453 | rsa->e = BN_bin2bn(attribs[2].pValue, | 498 | error("X509_new failed"); |
454 | attribs[2].ulValueLen, NULL); | 499 | } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen) |
455 | if (rsa->n && rsa->e && | 500 | == NULL) { |
456 | pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { | 501 | error("d2i_X509 failed"); |
457 | key = key_new(KEY_UNSPEC); | 502 | } else if ((evp = X509_get_pubkey(x509)) == NULL || |
458 | key->rsa = rsa; | 503 | evp->type != EVP_PKEY_RSA || |
459 | key->type = KEY_RSA; | 504 | evp->pkey.rsa == NULL) { |
460 | key->flags |= KEY_FLAG_EXT; | 505 | debug("X509_get_pubkey failed or no rsa"); |
506 | } else if ((rsa = RSAPublicKey_dup(evp->pkey.rsa)) | ||
507 | == NULL) { | ||
508 | error("RSAPublicKey_dup"); | ||
509 | } | ||
510 | if (x509) | ||
511 | X509_free(x509); | ||
512 | } | ||
513 | if (rsa && rsa->n && rsa->e && | ||
514 | pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { | ||
515 | key = key_new(KEY_UNSPEC); | ||
516 | key->rsa = rsa; | ||
517 | key->type = KEY_RSA; | ||
518 | key->flags |= KEY_FLAG_EXT; | ||
519 | if (pkcs11_key_included(keysp, nkeys, key)) { | ||
520 | key_free(key); | ||
521 | } else { | ||
461 | /* expand key array and add key */ | 522 | /* expand key array and add key */ |
462 | *keysp = xrealloc(*keysp, *nkeys + 1, | 523 | *keysp = xrealloc(*keysp, *nkeys + 1, |
463 | sizeof(Key *)); | 524 | sizeof(Key *)); |
464 | (*keysp)[*nkeys] = key; | 525 | (*keysp)[*nkeys] = key; |
465 | *nkeys = *nkeys + 1; | 526 | *nkeys = *nkeys + 1; |
466 | debug("have %d keys", *nkeys); | 527 | debug("have %d keys", *nkeys); |
467 | } else { | ||
468 | RSA_free(rsa); | ||
469 | } | 528 | } |
529 | } else if (rsa) { | ||
530 | RSA_free(rsa); | ||
470 | } | 531 | } |
471 | for (i = 0; i < 3; i++) | 532 | for (i = 0; i < 3; i++) |
472 | free(attribs[i].pValue); | 533 | free(attribs[i].pValue); |