Bugzilla – Attachment 2225 Details for
Bug 2075
[PATCH] Enable key pair generation on a PCKS#11 device
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Pkcs11 key-pair generation patch
0001-Pkcs11-key-pair-generation.patch (text/plain), 28.79 KB, created by
Ross McIlroy
on 2013-03-07 06:01:29 AEDT
(
hide
)
Description:
Pkcs11 key-pair generation patch
Filename:
MIME Type:
Creator:
Ross McIlroy
Created:
2013-03-07 06:01:29 AEDT
Size:
28.79 KB
patch
obsolete
>From 08097cf5fcca36ee736e79445428ac58744d0295 Mon Sep 17 00:00:00 2001 >From: Ross McIlroy <rmcilroy@google.com> >Date: Wed, 6 Mar 2013 18:15:28 +0000 >Subject: [PATCH] Enable ssh-keygen to generate private /public RSA keys on a > PKCS#11 device. The public identity file is generated as normal, but a new > private key format is introduced to signal that the key needs to be loaded > from an external device > > >Signed-off-by: Ross McIlroy <rmcilroy@google.com> >--- > authfile.c | 56 ++++++++- > authfile.h | 2 +- > ssh-keygen.1 | 13 ++- > ssh-keygen.c | 73 +++++++++--- > ssh-pkcs11.c | 367 ++++++++++++++++++++++++++++++++++++++++++---------------- > ssh-pkcs11.h | 1 + > ssh.c | 8 +- > sshconnect1.c | 8 +- > sshconnect2.c | 11 +- > 9 files changed, 407 insertions(+), 132 deletions(-) > >diff --git a/authfile.c b/authfile.c >index 3544d17..7bc1433 100644 >--- a/authfile.c >+++ b/authfile.c >@@ -75,6 +75,10 @@ > static const char authfile_id_string[] = > "SSH PRIVATE KEY FILE FORMAT 1.1\n"; > >+/* Version identification string for external key identity files. */ >+static const char externalkey_id_string[] = >+ "SSH PRIVATE KEY EXTERNAL 1.0\n"; >+ > /* > * Serialises the authentication (private) key to a blob, encrypting it with > * passphrase. The identification of the blob (lowest 64 bits of n) will >@@ -214,6 +218,25 @@ key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, > return success; > } > >+static int >+key_private_external_to_blob(Key *key, Buffer *blob, const char *passphrase, >+ const char *comment) { >+ Buffer buffer; >+ int i; >+ >+ buffer_init(&buffer); >+ >+ /* Store an identifier to identify key as being external. */ >+ for (i = 0; externalkey_id_string[i]; i++) >+ buffer_put_char(&buffer, externalkey_id_string[i]); >+ buffer_put_char(&buffer, 0); >+ >+ buffer_append(blob, buffer_ptr(&buffer), buffer_len(&buffer)); >+ buffer_free(&buffer); >+ >+ return 1; >+} >+ > /* Save a key blob to a file */ > static int > key_save_private_blob(Buffer *keybuf, const char *filename) >@@ -241,6 +264,10 @@ static int > key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, > const char *comment) > { >+ if (key->flags & KEY_FLAG_EXT) { >+ return key_private_external_to_blob(key, blob, passphrase, comment); >+ } >+ > switch (key->type) { > case KEY_RSA1: > return key_private_rsa1_to_blob(key, blob, passphrase, comment); >@@ -609,6 +636,14 @@ key_load_private_pem(int fd, int type, const char *passphrase, > return prv; > } > >+static int >+key_parse_is_private_external(Buffer *blob) >+{ >+ return (buffer_len(blob) >= sizeof(externalkey_id_string) >+ && memcmp(buffer_ptr(blob), externalkey_id_string, >+ sizeof(externalkey_id_string)) == 0); >+} >+ > int > key_perm_ok(int fd, const char *filename) > { >@@ -639,8 +674,16 @@ key_perm_ok(int fd, const char *filename) > > static Key * > key_parse_private_type(Buffer *blob, int type, const char *passphrase, >- char **commentp) >+ char **commentp, int *is_external) > { >+ if (key_parse_is_private_external(blob)) { >+ // key must be loaded through other means (e.g., pkcs11 module). >+ if (is_external != NULL) { >+ *is_external = 1; >+ } >+ return NULL; >+ } >+ > switch (type) { > case KEY_RSA1: > return key_parse_private_rsa1(blob, passphrase, commentp); >@@ -658,7 +701,7 @@ key_parse_private_type(Buffer *blob, int type, const char *passphrase, > > Key * > key_load_private_type(int type, const char *filename, const char *passphrase, >- char **commentp, int *perm_ok) >+ char **commentp, int *perm_ok, int *is_external) > { > int fd; > Key *ret; >@@ -689,7 +732,8 @@ key_load_private_type(int type, const char *filename, const char *passphrase, > return NULL; > } > close(fd); >- ret = key_parse_private_type(&buffer, type, passphrase, commentp); >+ ret = key_parse_private_type(&buffer, type, passphrase, commentp, >+ is_external); > buffer_free(&buffer); > return ret; > } >@@ -704,7 +748,7 @@ key_parse_private(Buffer *buffer, const char *filename, > pub = key_parse_public_rsa1(buffer, commentp); > if (pub == NULL) { > prv = key_parse_private_type(buffer, KEY_UNSPEC, >- passphrase, NULL); >+ passphrase, NULL, NULL); > /* use the filename as a comment for PEM */ > if (commentp && prv) > *commentp = xstrdup(filename); >@@ -712,7 +756,7 @@ key_parse_private(Buffer *buffer, const char *filename, > key_free(pub); > /* key_parse_public_rsa1() has already loaded the comment */ > prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, >- NULL); >+ NULL, NULL); > } > return prv; > } >@@ -858,7 +902,7 @@ key_load_private_cert(int type, const char *filename, const char *passphrase, > } > > if ((key = key_load_private_type(type, filename, >- passphrase, NULL, perm_ok)) == NULL) >+ passphrase, NULL, perm_ok, NULL)) == NULL) > return NULL; > > if ((pub = key_load_cert(filename)) == NULL) { >diff --git a/authfile.h b/authfile.h >index 78349be..9de2ec0 100644 >--- a/authfile.h >+++ b/authfile.h >@@ -23,7 +23,7 @@ Key *key_load_public_type(int, const char *, char **); > Key *key_parse_private(Buffer *, const char *, const char *, char **); > Key *key_load_private(const char *, const char *, char **); > Key *key_load_private_cert(int, const char *, const char *, int *); >-Key *key_load_private_type(int, const char *, const char *, char **, int *); >+Key *key_load_private_type(int, const char *, const char *, char **, int *, int *); > Key *key_load_private_pem(int, int, const char *, char **); > int key_perm_ok(int, const char *); > int key_in_file(Key *, const char *, int); >diff --git a/ssh-keygen.1 b/ssh-keygen.1 >index 7da73e0..894c5b7 100644 >--- a/ssh-keygen.1 >+++ b/ssh-keygen.1 >@@ -35,7 +35,7 @@ > .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF > .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > .\" >-.Dd $Mdocdate: January 19 2013 $ >+.Dd $Mdocdate: March 6 2013 $ > .Dt SSH-KEYGEN 1 > .Os > .Sh NAME >@@ -80,6 +80,9 @@ > .Nm ssh-keygen > .Fl D Ar pkcs11 > .Nm ssh-keygen >+.Fl d Ar pkcs11 >+.Op Fl E Ar slot_index >+.Nm ssh-keygen > .Fl F Ar hostname > .Op Fl f Ar known_hosts_file > .Op Fl l >@@ -255,6 +258,14 @@ When used in combination with > this option indicates that a CA key resides in a PKCS#11 token (see the > .Sx CERTIFICATES > section for details). >+.It Fl d Ar pkcs11 >+Generate the public / private key pair using the PKCS#11 shared library >+.Ar pkcs11 . >+.It Fl E Ar slot_idx >+Specify the PKCS#11 slot index on which to generate the public / private key >+pair when used in combination with >+.Fl d . >+If not specified, default is 0. > .It Fl e > This option will read a private or public OpenSSH key file and > print to stdout the key in one of the formats specified by the >diff --git a/ssh-keygen.c b/ssh-keygen.c >index d1a205e..2a46dc6 100644 >--- a/ssh-keygen.c >+++ b/ssh-keygen.c >@@ -147,7 +147,7 @@ int print_generic = 0; > > char *key_type_name = NULL; > >-/* Load key from this PKCS#11 provider */ >+/* Load or insert keys from this PKCS#11 provider */ > char *pkcs11provider = NULL; > > /* argv0 */ >@@ -762,6 +762,26 @@ do_download(struct passwd *pw) > #endif /* ENABLE_PKCS11 */ > } > >+static Key * >+do_generate_key_pkcs11(unsigned long slot_idx, int type, u_int bits, >+ char* key_comment) >+{ >+#ifdef ENABLE_PKCS11 >+ Key *key; >+ char *label; >+ xasprintf(&label, "ssh-keygen:%s", key_comment); >+ >+ pkcs11_init(1); >+ key = pkcs11_key_generate(pkcs11provider, NULL, slot_idx, label, type, bits); >+ pkcs11_terminate(); >+ >+ xfree(label); >+ return key; >+#else >+ fatal("no pkcs11 support"); >+#endif /* ENABLE_PKCS11 */ >+} >+ > static void > do_fingerprint(struct passwd *pw) > { >@@ -2132,6 +2152,8 @@ usage(void) > fprintf(stderr, " -c Change comment in private and public key files.\n"); > #ifdef ENABLE_PKCS11 > fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); >+ fprintf(stderr, " -d pkcs11 Generate key using pkcs11 token.\n"); >+ fprintf(stderr, " -E slot_idx Pkcs11 slot index on which to generate key for -d (default '0').\n"); > #endif > fprintf(stderr, " -e Export OpenSSH to foreign format key file.\n"); > fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); >@@ -2188,8 +2210,9 @@ main(int argc, char **argv) > int opt, type, fd; > u_int32_t memory = 0, generator_wanted = 0, trials = 100; > int do_gen_candidates = 0, do_screen_candidates = 0; >+ int do_download_pkcs11 = 0, do_gen_key_pkcs11 = 0; > int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; >- unsigned long start_lineno = 0, lines_to_process = 0; >+ unsigned long start_lineno = 0, lines_to_process = 0, pkcs11_slot_idx = 0; > BIGNUM *start = NULL; > FILE *f; > const char *errstr; >@@ -2219,7 +2242,7 @@ main(int argc, char **argv) > } > > while ((opt = getopt(argc, argv, "ABHLQXceghiklpquvxy" >- "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:a:b:f:g:j:m:n:r:s:t:z:")) != -1) { >+ "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:a:b:d:f:g:j:m:n:r:s:t:z:")) != -1) { > switch (opt) { > case 'A': > gen_all_hostkeys = 1; >@@ -2337,8 +2360,16 @@ main(int argc, char **argv) > key_type_name = optarg; > break; > case 'D': >+ do_download_pkcs11 = 1; >+ pkcs11provider = optarg; >+ break; >+ case 'd': >+ do_gen_key_pkcs11 = 1; > pkcs11provider = optarg; > break; >+ case 'E': >+ pkcs11_slot_idx = strtoul(optarg, &ep, 10); >+ break; > case 'u': > update_krl = 1; > break; >@@ -2450,7 +2481,7 @@ main(int argc, char **argv) > do_show_cert(pw); > if (delete_host || hash_hosts || find_host) > do_known_hosts(pw, rr_hostname); >- if (pkcs11provider != NULL) >+ if (do_download_pkcs11) > do_download(pw); > if (print_fingerprint || print_bubblebabble) > do_fingerprint(pw); >@@ -2542,9 +2573,23 @@ main(int argc, char **argv) > type = key_type_from_name(key_type_name); > type_bits_valid(type, &bits); > >- if (!quiet) >- printf("Generating public/private %s key pair.\n", key_type_name); >- private = key_generate(type, bits); >+ if (identity_comment) { >+ strlcpy(comment, identity_comment, sizeof(comment)); >+ } else { >+ /* Create default comment field for the passphrase. */ >+ snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); >+ } >+ >+ if (do_gen_key_pkcs11) { >+ if (!quiet) >+ printf("Generating public/private %s key pair using pkcs11 token %s.\n", >+ key_type_name, pkcs11provider); >+ private = do_generate_key_pkcs11(pkcs11_slot_idx, type, bits, comment); >+ } else { >+ if (!quiet) >+ printf("Generating public/private %s key pair.\n", key_type_name); >+ private = key_generate(type, bits); >+ } > if (private == NULL) { > fprintf(stderr, "key_generate failed\n"); > exit(1); >@@ -2609,13 +2654,6 @@ passphrase_again: > xfree(passphrase2); > } > >- if (identity_comment) { >- strlcpy(comment, identity_comment, sizeof(comment)); >- } else { >- /* Create default comment field for the passphrase. */ >- snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); >- } >- > /* Save the key with the given passphrase and comment. */ > if (!key_save_private(private, identity_file, passphrase1, comment)) { > printf("Saving the key failed: %s.\n", identity_file); >@@ -2631,8 +2669,13 @@ passphrase_again: > key_free(private); > arc4random_stir(); > >- if (!quiet) >+ if (!quiet) { > printf("Your identification has been saved in %s.\n", identity_file); >+ if (do_gen_key_pkcs11) { >+ printf("To use this identity you must configure ssh to use the the given " >+ "pkcs11 provider.\n"); >+ } >+ } > > strlcat(identity_file, ".pub", sizeof(identity_file)); > fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); >diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c >index 1f4c1c8..66e0545 100644 >--- a/ssh-pkcs11.c >+++ b/ssh-pkcs11.c >@@ -168,6 +168,35 @@ pkcs11_del_provider(char *provider_id) > return (-1); > } > >+static int >+pkcs11_login(struct pkcs11_provider *p, struct pkcs11_slotinfo *si) { >+ CK_FUNCTION_LIST *f; >+ CK_RV rv; >+ char *pin, prompt[1024]; >+ >+ f = p->function_list; >+ >+ if (!pkcs11_interactive) { >+ error("need pin"); >+ return (-1); >+ } >+ snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", >+ si->token.label); >+ pin = read_passphrase(prompt, RP_ALLOW_EOF); >+ if (pin == NULL) >+ return (-1); /* bail out */ >+ if ((rv = f->C_Login(si->session, CKU_USER, pin, strlen(pin))) >+ != CKR_OK) { >+ xfree(pin); >+ error("C_Login failed: %lu", rv); >+ return (-1); >+ } >+ xfree(pin); >+ si->logged_in = 1; >+ >+ return 0; >+} >+ > /* openssl callback for freeing an RSA key */ > static int > pkcs11_rsa_finish(RSA *rsa) >@@ -236,7 +265,6 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, > {CKA_ID, NULL, 0}, > {CKA_SIGN, NULL, sizeof(true_val) } > }; >- char *pin, prompt[1024]; > int rval = -1; > > /* some compilers complain about non-constant initializer so we >@@ -254,24 +282,9 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, > } > f = k11->provider->function_list; > si = &k11->provider->slotinfo[k11->slotidx]; >- if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { >- if (!pkcs11_interactive) { >- error("need pin"); >- return (-1); >- } >- snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", >- si->token.label); >- pin = read_passphrase(prompt, RP_ALLOW_EOF); >- if (pin == NULL) >- return (-1); /* bail out */ >- if ((rv = f->C_Login(si->session, CKU_USER, pin, strlen(pin))) >- != CKR_OK) { >- xfree(pin); >- error("C_Login failed: %lu", rv); >- return (-1); >- } >- xfree(pin); >- si->logged_in = 1; >+ if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in && >+ pkcs11_login(k11->provider, si)) { >+ return (-1); > } > key_filter[1].pValue = k11->keyid; > key_filter[1].ulValueLen = k11->keyid_len; >@@ -327,6 +340,67 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, > return (0); > } > >+static Key* >+extract_key(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE obj) { >+ Key *key; >+ RSA *rsa; >+ CK_RV rv; >+ CK_SESSION_HANDLE session; >+ CK_FUNCTION_LIST *f; >+ CK_ATTRIBUTE attribs[] = { >+ { CKA_ID, NULL, 0 }, >+ { CKA_MODULUS, NULL, 0 }, >+ { CKA_PUBLIC_EXPONENT, NULL, 0 } >+ }; >+ int i; >+ >+ key = NULL; >+ >+ f = p->function_list; >+ session = p->slotinfo[slotidx].session; >+ >+ /* figure out size of the attributes */ >+ if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) >+ != CKR_OK) { >+ error("C_GetAttributeValue failed: %lu", rv); >+ return NULL; >+ } >+ /* check that none of the attributes are zero length */ >+ if (attribs[0].ulValueLen == 0 || >+ attribs[1].ulValueLen == 0 || >+ attribs[2].ulValueLen == 0) { >+ return NULL; >+ } >+ /* allocate buffers for attributes */ >+ for (i = 0; i < 3; i++) >+ attribs[i].pValue = xmalloc(attribs[i].ulValueLen); >+ /* retrieve ID, modulus and public exponent of RSA key */ >+ if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) >+ != CKR_OK) { >+ error("C_GetAttributeValue failed: %lu", rv); >+ } else if ((rsa = RSA_new()) == NULL) { >+ error("RSA_new failed"); >+ } else { >+ rsa->n = BN_bin2bn(attribs[1].pValue, >+ attribs[1].ulValueLen, NULL); >+ rsa->e = BN_bin2bn(attribs[2].pValue, >+ attribs[2].ulValueLen, NULL); >+ if (rsa->n && rsa->e && >+ pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { >+ key = key_new(KEY_UNSPEC); >+ key->rsa = rsa; >+ key->type = KEY_RSA; >+ key->flags |= KEY_FLAG_EXT; >+ } else { >+ RSA_free(rsa); >+ } >+ } >+ for (i = 0; i < 3; i++) >+ xfree(attribs[i].pValue); >+ >+ return key; >+} >+ > /* remove trailing spaces */ > static void > rmspace(char *buf, size_t len) >@@ -380,6 +454,86 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) > return (0); > } > >+static Key* >+pkcs11_rsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx, >+ char *label, CK_ULONG bits) >+{ >+ struct pkcs11_slotinfo *si; >+ CK_FUNCTION_LIST *f; >+ CK_SESSION_HANDLE session; >+ CK_BBOOL true_val = CK_TRUE; >+ CK_MECHANISM mech = { >+ CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 >+ }; >+ CK_BYTE pubExponent[] = { >+ 0x01, 0x00, 0x01 /* RSA_F4 in bytes */ >+ }; >+ CK_ATTRIBUTE pubKeyTemplate[] = { >+ {CKA_TOKEN, &true_val, sizeof(true_val)}, >+ {CKA_LABEL, label, strlen(label)}, >+ {CKA_ENCRYPT, &true_val, sizeof(true_val)}, >+ {CKA_VERIFY, &true_val, sizeof(true_val)}, >+ {CKA_WRAP, &true_val, sizeof(true_val)}, >+ {CKA_MODULUS_BITS, &bits, sizeof(bits)}, >+ {CKA_PUBLIC_EXPONENT, pubExponent, sizeof(pubExponent)} >+ }; >+ CK_ATTRIBUTE privKeyTemplate[] = { >+ {CKA_TOKEN, &true_val, sizeof(true_val)}, >+ {CKA_LABEL, label, strlen(label)}, >+ {CKA_PRIVATE, &true_val, sizeof(true_val)}, >+ {CKA_SENSITIVE, &true_val, sizeof(true_val)}, >+ {CKA_DECRYPT, &true_val, sizeof(true_val)}, >+ {CKA_SIGN, &true_val, sizeof(true_val)}, >+ {CKA_UNWRAP, &true_val, sizeof(true_val)} >+ }; >+ CK_ATTRIBUTE modulus[] = { >+ { CKA_MODULUS, NULL, 0 } >+ }; >+ CK_ATTRIBUTE id[] = { >+ { CKA_ID, NULL, 0 } >+ }; >+ CK_OBJECT_HANDLE pubKey, privKey; >+ CK_RV rv; >+ >+ f = p->function_list; >+ si = &p->slotinfo[slotidx]; >+ session = si->session; >+ >+ /* login if we haven't done so yet */ >+ if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in && >+ pkcs11_login(p, si)) >+ fatal("Unable to login to slotidx %lu", slotidx); >+ >+ /* generate public / private key pair */ >+ if ((rv = f->C_GenerateKeyPair(session, &mech, pubKeyTemplate, 7, >+ privKeyTemplate, 6, &pubKey, &privKey)) != CKR_OK) { >+ fatal("pkcs11 rsa key pair generation failed with error 0x%lx", rv); >+ } >+ >+ /* get the generated public modulus */ >+ if ((rv = f->C_GetAttributeValue(session, pubKey, modulus, 1)) != CKR_OK) { >+ fatal("C_GetAttributeValue failed: %lu", rv); >+ } >+ modulus[0].pValue = xmalloc(modulus[0].ulValueLen); >+ if ((rv = f->C_GetAttributeValue(session, pubKey, modulus, 1)) != CKR_OK) { >+ fatal("C_GetAttributeValue failed: %lu", rv); >+ } >+ >+ /* set the id of the generated public and private keys to the modulus */ >+ id[0].pValue = modulus[0].pValue; >+ id[0].ulValueLen = modulus[0].ulValueLen; >+ if ((rv = f->C_SetAttributeValue(session, pubKey, id, 1)) != CKR_OK) { >+ fatal("C_SetAttributeValue failed: %lu", rv); >+ } >+ if ((rv = f->C_SetAttributeValue(session, privKey, id, 1)) != CKR_OK) { >+ fatal("C_SetAttributeValue failed: %lu", rv); >+ } >+ >+ xfree(modulus[0].pValue); >+ >+ return extract_key(p, slotidx, privKey); >+} >+ > /* > * lookup public keys for token in slot identified by slotidx, > * add 'wrapped' public keys to the 'keysp' array and increment nkeys. >@@ -390,8 +544,6 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, > int *nkeys) > { > Key *key; >- RSA *rsa; >- int i; > CK_RV rv; > CK_OBJECT_HANDLE obj; > CK_ULONG nfound; >@@ -401,11 +553,6 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, > CK_ATTRIBUTE pubkey_filter[] = { > { CKA_CLASS, NULL, sizeof(pubkey_class) } > }; >- CK_ATTRIBUTE attribs[] = { >- { CKA_ID, NULL, 0 }, >- { CKA_MODULUS, NULL, 0 }, >- { CKA_PUBLIC_EXPONENT, NULL, 0 } >- }; > > /* some compilers complain about non-constant initializer so we > use NULL in CK_ATTRIBUTE above and set the value here */ >@@ -419,78 +566,38 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, > return (-1); > } > while (1) { >- /* XXX 3 attributes in attribs[] */ >- for (i = 0; i < 3; i++) { >- attribs[i].pValue = NULL; >- attribs[i].ulValueLen = 0; >- } > if ((rv = f->C_FindObjects(session, &obj, 1, &nfound)) != CKR_OK > || nfound == 0) > break; >- /* found a key, so figure out size of the attributes */ >- if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) >- != CKR_OK) { >- error("C_GetAttributeValue failed: %lu", rv); >- continue; >- } >- /* check that none of the attributes are zero length */ >- if (attribs[0].ulValueLen == 0 || >- attribs[1].ulValueLen == 0 || >- attribs[2].ulValueLen == 0) { >- continue; >- } >- /* allocate buffers for attributes */ >- for (i = 0; i < 3; i++) >- attribs[i].pValue = xmalloc(attribs[i].ulValueLen); >- /* retrieve ID, modulus and public exponent of RSA key */ >- if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) >- != CKR_OK) { >- error("C_GetAttributeValue failed: %lu", rv); >- } else if ((rsa = RSA_new()) == NULL) { >- error("RSA_new failed"); >- } else { >- rsa->n = BN_bin2bn(attribs[1].pValue, >- attribs[1].ulValueLen, NULL); >- rsa->e = BN_bin2bn(attribs[2].pValue, >- attribs[2].ulValueLen, NULL); >- if (rsa->n && rsa->e && >- pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { >- key = key_new(KEY_UNSPEC); >- key->rsa = rsa; >- key->type = KEY_RSA; >- key->flags |= KEY_FLAG_EXT; >- /* expand key array and add key */ >- *keysp = xrealloc(*keysp, *nkeys + 1, >- sizeof(Key *)); >- (*keysp)[*nkeys] = key; >- *nkeys = *nkeys + 1; >- debug("have %d keys", *nkeys); >- } else { >- RSA_free(rsa); >- } >+ >+ /* found a key, extract details */ >+ if ((key = extract_key(p, slotidx, obj)) != NULL) { >+ /* expand key array and add key */ >+ *keysp = xrealloc(*keysp, *nkeys + 1, >+ sizeof(Key *)); >+ (*keysp)[*nkeys] = key; >+ *nkeys = *nkeys + 1; >+ debug("have %d keys", *nkeys); > } >- for (i = 0; i < 3; i++) >- xfree(attribs[i].pValue); > } > if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) > error("C_FindObjectsFinal failed: %lu", rv); > return (0); > } > >-/* register a new provider, fails if provider already exists */ >-int >-pkcs11_add_provider(char *provider_id, char *pin, Key ***keyp) >+/* initialize a new provider, fails if provider is already registered */ >+static struct pkcs11_provider * >+pkcs11_init_provider(char *provider_id, char *pin) > { >- int nkeys, need_finalize = 0; >+ int need_finalize = 0; > struct pkcs11_provider *p = NULL; > void *handle = NULL; > CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **); >- CK_RV rv; > CK_FUNCTION_LIST *f = NULL; > CK_TOKEN_INFO *token; > CK_ULONG i; >+ CK_RV rv; > >- *keyp = NULL; > if (pkcs11_provider_lookup(provider_id) != NULL) { > error("provider already registered: %s", provider_id); > goto fail; >@@ -542,17 +649,17 @@ pkcs11_add_provider(char *provider_id, char *pin, Key ***keyp) > } > p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); > if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) >- != CKR_OK) { >+ != CKR_OK) { > error("C_GetSlotList failed: %lu", rv); > goto fail; > } > p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); > p->valid = 1; >- nkeys = 0; >+ > for (i = 0; i < p->nslots; i++) { > token = &p->slotinfo[i].token; >- if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) >- != CKR_OK) { >+ if ((rv = p->function_list->C_GetTokenInfo(p->slotlist[i], token)) >+ != CKR_OK) { > error("C_GetTokenInfo failed: %lu", rv); > continue; > } >@@ -561,20 +668,15 @@ pkcs11_add_provider(char *provider_id, char *pin, Key ***keyp) > rmspace(token->model, sizeof(token->model)); > rmspace(token->serialNumber, sizeof(token->serialNumber)); > debug("label <%s> manufacturerID <%s> model <%s> serial <%s>" >- " flags 0x%lx", >- token->label, token->manufacturerID, token->model, >- token->serialNumber, token->flags); >- /* open session, login with pin and retrieve public keys */ >- if (pkcs11_open_session(p, i, pin) == 0) >- pkcs11_fetch_keys(p, i, keyp, &nkeys); >+ " flags 0x%lx", >+ token->label, token->manufacturerID, token->model, >+ token->serialNumber, token->flags); >+ /* open session, login with pin */ >+ pkcs11_open_session(p, i, pin); > } >- if (nkeys > 0) { >- TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); >- p->refcount++; /* add to provider list */ >- return (nkeys); >- } >- error("no keys"); >- /* don't add the provider, since it does not have any keys */ >+ >+ return p; >+ > fail: > if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) > error("C_Finalize failed: %lu", rv); >@@ -587,7 +689,76 @@ fail: > } > if (handle) > dlclose(handle); >- return (-1); >+ return NULL; >+} >+ >+/* register a new provider and get keys, fails if provider already exists or >+ * contains no keys */ >+int >+pkcs11_add_provider(char *provider_id, char *pin, Key ***keyp) >+{ >+ struct pkcs11_provider *p; >+ int nkeys; >+ CK_ULONG i; >+ >+ if (pkcs11_provider_lookup(provider_id) != NULL) { >+ error("provider already registered: %s", provider_id); >+ return (-1); >+ } >+ >+ if ((p = pkcs11_init_provider(provider_id, pin)) == NULL) { >+ return (-1); >+ } >+ >+ *keyp = NULL; >+ nkeys = 0; >+ for (i = 0; i < p->nslots; i++) { >+ /* Fetch keys for any slots with open sessions */ >+ if (p->slotinfo[i].session) >+ pkcs11_fetch_keys(p, i, keyp, &nkeys); >+ } >+ if (nkeys > 0) { >+ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); >+ p->refcount++; /* add to provider list */ >+ return (nkeys); >+ } else { >+ error("no keys"); >+ /* don't add the provider, since it does not have any keys */ >+ pkcs11_provider_finalize(p); >+ pkcs11_provider_unref(p); >+ return (-1); >+ } >+} >+ >+Key * >+pkcs11_key_generate(char *provider_id, char *pin, u_int slotidx, char *label, >+ int type, u_int bits) >+{ >+ Key *k = NULL; >+ struct pkcs11_provider *p; >+ >+ if (((p = pkcs11_provider_lookup(provider_id)) == NULL) >+ && ((p = pkcs11_init_provider(provider_id, pin)) == NULL)) { >+ fatal("pkcs11 provider initialization failed"); >+ } >+ >+ switch (type) { >+ case KEY_RSA: >+ case KEY_RSA1: >+ if ((k = pkcs11_rsa_generate_private_key(p, slotidx, label, bits)) == NULL) >+ fatal("Error generating pkcs11 RSA key"); >+ break; >+ default: >+ fatal("key_generate: unknown type %d", type); >+ } >+ >+ if (k != NULL) { >+ // Add to pkcs11 provider list >+ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); >+ p->refcount++; >+ } >+ >+ return k; > } > > #else >diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h >index 59f456a..5c78cca 100644 >--- a/ssh-pkcs11.h >+++ b/ssh-pkcs11.h >@@ -18,3 +18,4 @@ int pkcs11_init(int); > void pkcs11_terminate(void); > int pkcs11_add_provider(char *, char *, Key ***); > int pkcs11_del_provider(char *); >+Key * pkcs11_key_generate(char *, char *, u_int, char *, int, u_int); >diff --git a/ssh.c b/ssh.c >index 3f61eb0..f35eabc 100644 >--- a/ssh.c >+++ b/ssh.c >@@ -826,7 +826,7 @@ main(int ac, char **av) > > PRIV_START; > sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, >- _PATH_HOST_KEY_FILE, "", NULL, NULL); >+ _PATH_HOST_KEY_FILE, "", NULL, NULL, NULL); > sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, > _PATH_HOST_DSA_KEY_FILE, "", NULL); > #ifdef OPENSSL_HAS_ECC >@@ -836,13 +836,13 @@ main(int ac, char **av) > sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, > _PATH_HOST_RSA_KEY_FILE, "", NULL); > sensitive_data.keys[4] = key_load_private_type(KEY_DSA, >- _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); >+ _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL, NULL); > #ifdef OPENSSL_HAS_ECC > sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA, >- _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); >+ _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL, NULL); > #endif > sensitive_data.keys[6] = key_load_private_type(KEY_RSA, >- _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); >+ _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL, NULL); > PRIV_END; > > if (options.hostbased_authentication == 1 && >diff --git a/sshconnect1.c b/sshconnect1.c >index fd07bbf..0632dda 100644 >--- a/sshconnect1.c >+++ b/sshconnect1.c >@@ -208,7 +208,7 @@ try_rsa_authentication(int idx) > BIGNUM *challenge; > Key *public, *private; > char buf[300], *passphrase, *comment, *authfile; >- int i, perm_ok = 1, type, quit; >+ int i, perm_ok = 1, is_external = 0, type, quit; > > public = options.identity_keys[idx]; > authfile = options.identity_files[idx]; >@@ -255,15 +255,15 @@ try_rsa_authentication(int idx) > private = public; > else > private = key_load_private_type(KEY_RSA1, authfile, "", NULL, >- &perm_ok); >- if (private == NULL && !options.batch_mode && perm_ok) { >+ &perm_ok, &is_external); >+ if (private == NULL && !options.batch_mode && perm_ok && !is_external) { > snprintf(buf, sizeof(buf), > "Enter passphrase for RSA key '%.100s': ", comment); > for (i = 0; i < options.number_of_password_prompts; i++) { > passphrase = read_passphrase(buf, 0); > if (strcmp(passphrase, "") != 0) { > private = key_load_private_type(KEY_RSA1, >- authfile, passphrase, NULL, NULL); >+ authfile, passphrase, NULL, NULL, NULL); > quit = 0; > } else { > debug2("no passphrase given, try next key"); >diff --git a/sshconnect2.c b/sshconnect2.c >index a306447..3fa00c7 100644 >--- a/sshconnect2.c >+++ b/sshconnect2.c >@@ -1316,7 +1316,7 @@ load_identity_file(char *filename, int userprovided) > { > Key *private; > char prompt[300], *passphrase; >- int perm_ok = 0, quit, i; >+ int perm_ok = 0, is_external = 0, quit, i; > struct stat st; > > if (stat(filename, &st) < 0) { >@@ -1324,7 +1324,12 @@ load_identity_file(char *filename, int userprovided) > filename, strerror(errno)); > return NULL; > } >- private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok); >+ private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok, >+ &is_external); >+ if (is_external) { >+ error("Key %s is external. Load it through it's pkcs11 module.", filename); >+ return NULL; >+ } > if (!perm_ok) > return NULL; > if (private == NULL) { >@@ -1336,7 +1341,7 @@ load_identity_file(char *filename, int userprovided) > passphrase = read_passphrase(prompt, 0); > if (strcmp(passphrase, "") != 0) { > private = key_load_private_type(KEY_UNSPEC, >- filename, passphrase, NULL, NULL); >+ filename, passphrase, NULL, NULL, NULL); > quit = 0; > } else { > debug2("no passphrase given, try next key"); >-- >1.8.1.3 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2075
: 2225