summaryrefslogtreecommitdiff
path: root/ssh-pkcs11.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh-pkcs11.c')
-rw-r--r--ssh-pkcs11.c136
1 files changed, 101 insertions, 35 deletions
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index 618c07526..c49cbf42b 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.11 2013/11/13 13:48:20 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,7 +227,7 @@ 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
@@ -238,8 +240,6 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
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; 243 key_filter[0].pValue = &private_key_class;
244 key_filter[2].pValue = &true_val; 244 key_filter[2].pValue = &true_val;
245 245
@@ -384,36 +384,75 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin)
384 * add 'wrapped' public keys to the 'keysp' array and increment nkeys. 384 * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
385 * keysp points to an (possibly empty) array with *nkeys keys. 385 * keysp points to an (possibly empty) array with *nkeys keys.
386 */ 386 */
387static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG,
388 CK_ATTRIBUTE [], CK_ATTRIBUTE [3], Key ***, int *)
389 __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE))));
390
387static int 391static int
388pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, 392pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
389 int *nkeys) 393 Key ***keysp, int *nkeys)
390{ 394{
391 Key *key; 395 CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
392 RSA *rsa; 396 CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
393 int i;
394 CK_RV rv;
395 CK_OBJECT_HANDLE obj;
396 CK_ULONG nfound;
397 CK_SESSION_HANDLE session;
398 CK_FUNCTION_LIST *f;
399 CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
400 CK_ATTRIBUTE pubkey_filter[] = { 397 CK_ATTRIBUTE pubkey_filter[] = {
401 { CKA_CLASS, NULL, sizeof(pubkey_class) } 398 { CKA_CLASS, NULL, sizeof(pubkey_class) }
402 }; 399 };
403 CK_ATTRIBUTE attribs[] = { 400 CK_ATTRIBUTE cert_filter[] = {
401 { CKA_CLASS, NULL, sizeof(cert_class) }
402 };
403 CK_ATTRIBUTE pubkey_attribs[] = {
404 { CKA_ID, NULL, 0 }, 404 { CKA_ID, NULL, 0 },
405 { CKA_MODULUS, NULL, 0 }, 405 { CKA_MODULUS, NULL, 0 },
406 { CKA_PUBLIC_EXPONENT, NULL, 0 } 406 { CKA_PUBLIC_EXPONENT, NULL, 0 }
407 }; 407 };
408 408 CK_ATTRIBUTE cert_attribs[] = {
409 /* some compilers complain about non-constant initializer so we 409 { CKA_ID, NULL, 0 },
410 use NULL in CK_ATTRIBUTE above and set the value here */ 410 { CKA_SUBJECT, NULL, 0 },
411 { CKA_VALUE, NULL, 0 }
412 };
411 pubkey_filter[0].pValue = &pubkey_class; 413 pubkey_filter[0].pValue = &pubkey_class;
414 cert_filter[0].pValue = &cert_class;
415
416 if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs,
417 keysp, nkeys) < 0 ||
418 pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs,
419 keysp, nkeys) < 0)
420 return (-1);
421 return (0);
422}
423
424static int
425pkcs11_key_included(Key ***keysp, int *nkeys, Key *key)
426{
427 int i;
428
429 for (i = 0; i < *nkeys; i++)
430 if (key_equal(key, (*keysp)[i]))
431 return (1);
432 return (0);
433}
434
435static int
436pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
437 CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3],
438 Key ***keysp, int *nkeys)
439{
440 Key *key;
441 RSA *rsa;
442 X509 *x509;
443 EVP_PKEY *evp;
444 int i;
445 const u_char *cp;
446 CK_RV rv;
447 CK_OBJECT_HANDLE obj;
448 CK_ULONG nfound;
449 CK_SESSION_HANDLE session;
450 CK_FUNCTION_LIST *f;
412 451
413 f = p->function_list; 452 f = p->function_list;
414 session = p->slotinfo[slotidx].session; 453 session = p->slotinfo[slotidx].session;
415 /* setup a filter the looks for public keys */ 454 /* setup a filter the looks for public keys */
416 if ((rv = f->C_FindObjectsInit(session, pubkey_filter, 1)) != CKR_OK) { 455 if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) {
417 error("C_FindObjectsInit failed: %lu", rv); 456 error("C_FindObjectsInit failed: %lu", rv);
418 return (-1); 457 return (-1);
419 } 458 }
@@ -441,32 +480,59 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp,
441 /* allocate buffers for attributes */ 480 /* allocate buffers for attributes */
442 for (i = 0; i < 3; i++) 481 for (i = 0; i < 3; i++)
443 attribs[i].pValue = xmalloc(attribs[i].ulValueLen); 482 attribs[i].pValue = xmalloc(attribs[i].ulValueLen);
444 /* retrieve ID, modulus and public exponent of RSA key */ 483 /*
484 * retrieve ID, modulus and public exponent of RSA key,
485 * or ID, subject and value for certificates.
486 */
487 rsa = NULL;
445 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) 488 if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
446 != CKR_OK) { 489 != CKR_OK) {
447 error("C_GetAttributeValue failed: %lu", rv); 490 error("C_GetAttributeValue failed: %lu", rv);
448 } else if ((rsa = RSA_new()) == NULL) { 491 } else if (attribs[1].type == CKA_MODULUS ) {
449 error("RSA_new failed"); 492 if ((rsa = RSA_new()) == NULL) {
493 error("RSA_new failed");
494 } else {
495 rsa->n = BN_bin2bn(attribs[1].pValue,
496 attribs[1].ulValueLen, NULL);
497 rsa->e = BN_bin2bn(attribs[2].pValue,
498 attribs[2].ulValueLen, NULL);
499 }
450 } else { 500 } else {
451 rsa->n = BN_bin2bn(attribs[1].pValue, 501 cp = attribs[2].pValue;
452 attribs[1].ulValueLen, NULL); 502 if ((x509 = X509_new()) == NULL) {
453 rsa->e = BN_bin2bn(attribs[2].pValue, 503 error("X509_new failed");
454 attribs[2].ulValueLen, NULL); 504 } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen)
455 if (rsa->n && rsa->e && 505 == NULL) {
456 pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { 506 error("d2i_X509 failed");
457 key = key_new(KEY_UNSPEC); 507 } else if ((evp = X509_get_pubkey(x509)) == NULL ||
458 key->rsa = rsa; 508 evp->type != EVP_PKEY_RSA ||
459 key->type = KEY_RSA; 509 evp->pkey.rsa == NULL) {
460 key->flags |= KEY_FLAG_EXT; 510 debug("X509_get_pubkey failed or no rsa");
511 } else if ((rsa = RSAPublicKey_dup(evp->pkey.rsa))
512 == NULL) {
513 error("RSAPublicKey_dup");
514 }
515 if (x509)
516 X509_free(x509);
517 }
518 if (rsa && rsa->n && rsa->e &&
519 pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
520 key = key_new(KEY_UNSPEC);
521 key->rsa = rsa;
522 key->type = KEY_RSA;
523 key->flags |= KEY_FLAG_EXT;
524 if (pkcs11_key_included(keysp, nkeys, key)) {
525 key_free(key);
526 } else {
461 /* expand key array and add key */ 527 /* expand key array and add key */
462 *keysp = xrealloc(*keysp, *nkeys + 1, 528 *keysp = xrealloc(*keysp, *nkeys + 1,
463 sizeof(Key *)); 529 sizeof(Key *));
464 (*keysp)[*nkeys] = key; 530 (*keysp)[*nkeys] = key;
465 *nkeys = *nkeys + 1; 531 *nkeys = *nkeys + 1;
466 debug("have %d keys", *nkeys); 532 debug("have %d keys", *nkeys);
467 } else {
468 RSA_free(rsa);
469 } 533 }
534 } else if (rsa) {
535 RSA_free(rsa);
470 } 536 }
471 for (i = 0; i < 3; i++) 537 for (i = 0; i < 3; i++)
472 free(attribs[i].pValue); 538 free(attribs[i].pValue);