Support CA keys in PKCS#11 tokens; feedback and ok markus@
authordjm <djm@openbsd.org>
Wed, 4 Aug 2010 06:07:11 +0000 (06:07 +0000)
committerdjm <djm@openbsd.org>
Wed, 4 Aug 2010 06:07:11 +0000 (06:07 +0000)
usr.bin/ssh/ssh-keygen.1
usr.bin/ssh/ssh-keygen.c

index c446487..9acd8f8 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-keygen.1,v 1.97 2010/07/15 21:20:38 schwarze Exp $
+.\"    $OpenBSD: ssh-keygen.1,v 1.98 2010/08/04 06:07:11 djm Exp $
 .\"
 .\"  -*- nroff -*-
 .\"
@@ -37,7 +37,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: July 15 2010 $
+.Dd $Mdocdate: August 4 2010 $
 .Dt SSH-KEYGEN 1
 .Os
 .Sh NAME
@@ -215,6 +215,11 @@ the passphrase if the key has one, and for the new comment.
 .It Fl D Ar pkcs11
 Download the RSA public keys provided by the PKCS#11 shared library
 .Ar pkcs11 .
+When used in combination with
+.Fl s ,
+this option indicates that a CA key resides in a PKCS#11 token (see the
+.Sx CERTIFICATES
+section for details).
 .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
@@ -553,7 +558,17 @@ option:
 .Pp
 The host certificate will be output to
 .Pa /path/to/host_key-cert.pub .
-In both cases,
+.Pp
+It is possible to sign using a CA key stored in a PKCS#11 token by
+providing the token library using
+.Fl D
+and identifying the CA key by providing its public half as an argument
+to
+.Fl s :
+.Pp
+.Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id host_key.pub
+.Pp
+In all cases,
 .Ar key_id
 is a "key identifier" that is logged by the server when the certificate
 is used for authentication.
index 3bb28de..c5c2a12 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.196 2010/08/04 05:40:39 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.197 2010/08/04 06:07:11 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -138,6 +138,8 @@ int print_generic = 0;
 
 char *key_type_name = NULL;
 
+/* Load key from this PKCS#11 provider */
+char *pkcs11provider = NULL;
 
 /* argv0 */
 extern char *__progname;
@@ -647,7 +649,7 @@ do_print_public(struct passwd *pw)
 }
 
 static void
-do_download(struct passwd *pw, char *pkcs11provider)
+do_download(struct passwd *pw)
 {
 #ifdef ENABLE_PKCS11
        Key **keys = NULL;
@@ -1310,6 +1312,35 @@ prepare_options_buf(Buffer *c, int which)
                add_string_option(c, "source-address", certflags_src_addr);
 }
 
+static Key *
+load_pkcs11_key(char *path)
+{
+#ifdef ENABLE_PKCS11
+       Key **keys = NULL, *public, *private = NULL;
+       int i, nkeys;
+
+       if ((public = key_load_public(path, NULL)) == NULL)
+               fatal("Couldn't load CA public key \"%s\"", path);
+
+       nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys);
+       debug3("%s: %d keys", __func__, nkeys);
+       if (nkeys <= 0)
+               fatal("cannot read public key from pkcs11");
+       for (i = 0; i < nkeys; i++) {
+               if (key_equal_public(public, keys[i])) {
+                       private = keys[i];
+                       continue;
+               }
+               key_free(keys[i]);
+       }
+       xfree(keys);
+       key_free(public);
+       return private;
+#else
+       fatal("no pkcs11 support");
+#endif /* ENABLE_PKCS11 */
+}
+
 static void
 do_ca_sign(struct passwd *pw, int argc, char **argv)
 {
@@ -1320,11 +1351,6 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
        FILE *f;
        int v00 = 0; /* legacy keys */
 
-       tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
-       if ((ca = load_identity(tmp)) == NULL)
-               fatal("Couldn't load CA key \"%s\"", tmp);
-       xfree(tmp);
-
        if (key_type_name != NULL) {
                switch (key_type_from_name(key_type_name)) {
                case KEY_RSA_CERT_V00:
@@ -1344,6 +1370,15 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
                }
        }
 
+       pkcs11_init(1);
+       tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
+       if (pkcs11provider != NULL) {
+               if ((ca = load_pkcs11_key(tmp)) == NULL)
+                       fatal("No PKCS#11 key matching %s found", ca_key_path);
+       } else if ((ca = load_identity(tmp)) == NULL)
+               fatal("Couldn't load CA key \"%s\"", tmp);
+       xfree(tmp);
+
        for (i = 0; i < argc; i++) {
                /* Split list of principals */
                n = 0;
@@ -1416,6 +1451,7 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
                key_free(public);
                xfree(out);
        }
+       pkcs11_terminate();
        exit(0);
 }
 
@@ -1717,8 +1753,7 @@ int
 main(int argc, char **argv)
 {
        char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
-       char out_file[MAXPATHLEN], *pkcs11provider = NULL;
-       char *rr_hostname = NULL;
+       char out_file[MAXPATHLEN], *rr_hostname = NULL;
        Key *private, *public;
        struct passwd *pw;
        struct stat st;
@@ -1988,7 +2023,7 @@ main(int argc, char **argv)
                }
        }
        if (pkcs11provider != NULL)
-               do_download(pw, pkcs11provider);
+               do_download(pw);
 
        if (do_gen_candidates) {
                FILE *out = fopen(out_file, "w");