summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2013-11-04 07:41:48 +1100
committerDamien Miller <djm@mindrot.org>2013-11-04 07:41:48 +1100
commitd2252c79191d069372ed6effce7c7a2de93448cd (patch)
tree1ad93b65aeed04d17b510975beeff6e475241cf7
parent007e3b357e880caa974d5adf9669298ba0751c78 (diff)
- markus@cvs.openbsd.org 2013/11/02 20:03:54
[ssh-pkcs11.c] support pkcs#11 tokes that only provide x509 zerts instead of raw pubkeys; fixes bz#1908; based on patch from Laurent Barbe; ok djm
-rw-r--r--ChangeLog7
-rw-r--r--ssh-pkcs11.c141
2 files changed, 108 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 69541297c..75a300584 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
120131104
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
120131103 820131103
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 */
384static 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
388static int
389pkcs11_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
387static int 419static int
388pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, 420pkcs11_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
430static int
431pkcs11_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);