- markus@cvs.openbsd.org 2013/12/06 13:34:54
     [authfile.c authfile.h cipher.c cipher.h key.c packet.c ssh-agent.c]
     [ssh-keygen.c PROTOCOL.key] new private key format, bcrypt as KDF by
     default; details in PROTOCOL.key; feedback and lots help from djm;
     ok djm@
diff --git a/ssh-keygen.c b/ssh-keygen.c
index e5e2f2f..533eed2 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.236 2013/12/06 03:40:51 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.237 2013/12/06 13:34:54 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -150,6 +150,18 @@
 /* Load key from this PKCS#11 provider */
 char *pkcs11provider = NULL;
 
+/* Use new OpenSSH private key format when writing SSH2 keys instead of PEM */
+int use_new_format = 0;
+
+/* Cipher for new-format private keys */
+char *new_format_cipher = NULL;
+
+/*
+ * Number of KDF rounds to derive new format keys /
+ * number of primality trials when screening moduli.
+ */
+int rounds = 0;
+
 /* argv0 */
 extern char *__progname;
 
@@ -923,7 +935,8 @@
 		public  = key_from_private(private);
 		snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
 		    hostname);
-		if (!key_save_private(private, identity_file, "", comment)) {
+		if (!key_save_private(private, identity_file, "", comment,
+		    use_new_format, new_format_cipher, rounds)) {
 			printf("Saving the key failed: %s.\n", identity_file);
 			key_free(private);
 			key_free(public);
@@ -1275,7 +1288,8 @@
 	}
 
 	/* Save the file using the new passphrase. */
-	if (!key_save_private(private, identity_file, passphrase1, comment)) {
+	if (!key_save_private(private, identity_file, passphrase1, comment,
+	    use_new_format, new_format_cipher, rounds)) {
 		printf("Saving the key failed: %s.\n", identity_file);
 		memset(passphrase1, 0, strlen(passphrase1));
 		free(passphrase1);
@@ -1385,7 +1399,8 @@
 	}
 
 	/* Save the file using the new passphrase. */
-	if (!key_save_private(private, identity_file, passphrase, new_comment)) {
+	if (!key_save_private(private, identity_file, passphrase, new_comment,
+	    use_new_format, new_format_cipher, rounds)) {
 		printf("Saving the key failed: %s.\n", identity_file);
 		memset(passphrase, 0, strlen(passphrase));
 		free(passphrase);
@@ -2132,7 +2147,7 @@
 	fprintf(stderr, "usage: %s [options]\n", __progname);
 	fprintf(stderr, "Options:\n");
 	fprintf(stderr, "  -A          Generate non-existent host keys for all key types.\n");
-	fprintf(stderr, "  -a trials   Number of trials for screening DH-GEX moduli.\n");
+	fprintf(stderr, "  -a number   Number of KDF rounds for new key format or moduli primality tests.\n");
 	fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
 	fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
 	fprintf(stderr, "  -C comment  Provide new comment.\n");
@@ -2160,6 +2175,7 @@
 	fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
 	fprintf(stderr, "  -n name,... User/host principal names to include in certificate\n");
 	fprintf(stderr, "  -O option   Specify a certificate option.\n");
+	fprintf(stderr, "  -o          Enforce new private key format.\n");
 	fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
 	fprintf(stderr, "  -p          Change passphrase of private key file.\n");
 	fprintf(stderr, "  -Q          Test whether key(s) are revoked in KRL.\n");
@@ -2176,6 +2192,7 @@
 	fprintf(stderr, "  -W gen      Generator to use for generating DH-GEX moduli.\n");
 	fprintf(stderr, "  -y          Read private key file and print public key.\n");
 	fprintf(stderr, "  -z serial   Specify a serial number.\n");
+	fprintf(stderr, "  -Z cipher   Specify a cipher for new private key format.\n");
 
 	exit(1);
 }
@@ -2193,7 +2210,7 @@
 	struct passwd *pw;
 	struct stat st;
 	int opt, type, fd;
-	u_int32_t memory = 0, generator_wanted = 0, trials = 100;
+	u_int32_t memory = 0, generator_wanted = 0;
 	int do_gen_candidates = 0, do_screen_candidates = 0;
 	int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0;
 	unsigned long start_lineno = 0, lines_to_process = 0;
@@ -2225,9 +2242,9 @@
 		exit(1);
 	}
 
-	/* Remaining characters: EUYZdow */
-	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:j:m:n:r:s:t:z:")) != -1) {
+	/* Remaining characters: EUYdw */
+	while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy"
+	    "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) {
 		switch (opt) {
 		case 'A':
 			gen_all_hostkeys = 1;
@@ -2285,6 +2302,9 @@
 		case 'n':
 			cert_principals = optarg;
 			break;
+		case 'o':
+			use_new_format = 1;
+			break;
 		case 'p':
 			change_passphrase = 1;
 			break;
@@ -2312,6 +2332,9 @@
 		case 'O':
 			add_cert_option(optarg);
 			break;
+		case 'Z':
+			new_format_cipher = optarg;
+			break;
 		case 'C':
 			identity_comment = optarg;
 			break;
@@ -2370,9 +2393,9 @@
 					optarg, errstr);
 			break;
 		case 'a':
-			trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
+			rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr);
 			if (errstr)
-				fatal("Invalid number of trials: %s (%s)",
+				fatal("Invalid number: %s (%s)",
 					optarg, errstr);
 			break;
 		case 'M':
@@ -2531,7 +2554,8 @@
 			fatal("Couldn't open moduli file \"%s\": %s",
 			    out_file, strerror(errno));
 		}
-		if (prime_test(in, out, trials, generator_wanted, checkpoint,
+		if (prime_test(in, out, rounds == 0 ? 100 : rounds,
+		    generator_wanted, checkpoint,
 		    start_lineno, lines_to_process) != 0)
 			fatal("modulus screening failed");
 		return (0);
@@ -2623,7 +2647,8 @@
 	}
 
 	/* Save the key with the given passphrase and comment. */
-	if (!key_save_private(private, identity_file, passphrase1, comment)) {
+	if (!key_save_private(private, identity_file, passphrase1, comment,
+	    use_new_format, new_format_cipher, rounds)) {
 		printf("Saving the key failed: %s.\n", identity_file);
 		memset(passphrase1, 0, strlen(passphrase1));
 		free(passphrase1);