diff options
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 93 |
1 files changed, 62 insertions, 31 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c index 03c444d42..eae83a461 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.230 2013/07/20 01:44:37 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.238 2013/12/06 13:39:49 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -150,6 +150,18 @@ char *key_type_name = NULL; | |||
150 | /* Load key from this PKCS#11 provider */ | 150 | /* Load key from this PKCS#11 provider */ |
151 | char *pkcs11provider = NULL; | 151 | char *pkcs11provider = NULL; |
152 | 152 | ||
153 | /* Use new OpenSSH private key format when writing SSH2 keys instead of PEM */ | ||
154 | int use_new_format = 0; | ||
155 | |||
156 | /* Cipher for new-format private keys */ | ||
157 | char *new_format_cipher = NULL; | ||
158 | |||
159 | /* | ||
160 | * Number of KDF rounds to derive new format keys / | ||
161 | * number of primality trials when screening moduli. | ||
162 | */ | ||
163 | int rounds = 0; | ||
164 | |||
153 | /* argv0 */ | 165 | /* argv0 */ |
154 | extern char *__progname; | 166 | extern char *__progname; |
155 | 167 | ||
@@ -185,7 +197,7 @@ type_bits_valid(int type, u_int32_t *bitsp) | |||
185 | } | 197 | } |
186 | if (type == KEY_DSA && *bitsp != 1024) | 198 | if (type == KEY_DSA && *bitsp != 1024) |
187 | fatal("DSA keys must be 1024 bits"); | 199 | fatal("DSA keys must be 1024 bits"); |
188 | else if (type != KEY_ECDSA && *bitsp < 768) | 200 | else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 768) |
189 | fatal("Key must at least be 768 bits"); | 201 | fatal("Key must at least be 768 bits"); |
190 | else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1) | 202 | else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1) |
191 | fatal("Invalid ECDSA key length - valid lengths are " | 203 | fatal("Invalid ECDSA key length - valid lengths are " |
@@ -221,6 +233,10 @@ ask_filename(struct passwd *pw, const char *prompt) | |||
221 | case KEY_RSA: | 233 | case KEY_RSA: |
222 | name = _PATH_SSH_CLIENT_ID_RSA; | 234 | name = _PATH_SSH_CLIENT_ID_RSA; |
223 | break; | 235 | break; |
236 | case KEY_ED25519: | ||
237 | case KEY_ED25519_CERT: | ||
238 | name = _PATH_SSH_CLIENT_ID_ED25519; | ||
239 | break; | ||
224 | default: | 240 | default: |
225 | fprintf(stderr, "bad key type\n"); | 241 | fprintf(stderr, "bad key type\n"); |
226 | exit(1); | 242 | exit(1); |
@@ -884,6 +900,7 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
884 | #ifdef OPENSSL_HAS_ECC | 900 | #ifdef OPENSSL_HAS_ECC |
885 | { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, | 901 | { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, |
886 | #endif | 902 | #endif |
903 | { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, | ||
887 | { NULL, NULL, NULL } | 904 | { NULL, NULL, NULL } |
888 | }; | 905 | }; |
889 | 906 | ||
@@ -910,7 +927,6 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
910 | } | 927 | } |
911 | printf("%s ", key_types[i].key_type_display); | 928 | printf("%s ", key_types[i].key_type_display); |
912 | fflush(stdout); | 929 | fflush(stdout); |
913 | arc4random_stir(); | ||
914 | type = key_type_from_name(key_types[i].key_type); | 930 | type = key_type_from_name(key_types[i].key_type); |
915 | strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); | 931 | strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); |
916 | bits = 0; | 932 | bits = 0; |
@@ -924,7 +940,8 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
924 | public = key_from_private(private); | 940 | public = key_from_private(private); |
925 | snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, | 941 | snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, |
926 | hostname); | 942 | hostname); |
927 | if (!key_save_private(private, identity_file, "", comment)) { | 943 | if (!key_save_private(private, identity_file, "", comment, |
944 | use_new_format, new_format_cipher, rounds)) { | ||
928 | printf("Saving the key failed: %s.\n", identity_file); | 945 | printf("Saving the key failed: %s.\n", identity_file); |
929 | key_free(private); | 946 | key_free(private); |
930 | key_free(public); | 947 | key_free(public); |
@@ -932,7 +949,6 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
932 | continue; | 949 | continue; |
933 | } | 950 | } |
934 | key_free(private); | 951 | key_free(private); |
935 | arc4random_stir(); | ||
936 | strlcat(identity_file, ".pub", sizeof(identity_file)); | 952 | strlcat(identity_file, ".pub", sizeof(identity_file)); |
937 | fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); | 953 | fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
938 | if (fd == -1) { | 954 | if (fd == -1) { |
@@ -1001,6 +1017,7 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
1001 | char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; | 1017 | char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; |
1002 | int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; | 1018 | int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; |
1003 | int ca; | 1019 | int ca; |
1020 | int found_key = 0; | ||
1004 | 1021 | ||
1005 | if (!have_identity) { | 1022 | if (!have_identity) { |
1006 | cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); | 1023 | cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); |
@@ -1103,11 +1120,13 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
1103 | } | 1120 | } |
1104 | c = (strcmp(cp2, cp) == 0); | 1121 | c = (strcmp(cp2, cp) == 0); |
1105 | if (find_host && c) { | 1122 | if (find_host && c) { |
1106 | printf("# Host %s found: " | 1123 | if (!quiet) |
1107 | "line %d type %s%s\n", name, | 1124 | printf("# Host %s found: " |
1108 | num, key_type(pub), | 1125 | "line %d type %s%s\n", name, |
1109 | ca ? " (CA key)" : ""); | 1126 | num, key_type(pub), |
1127 | ca ? " (CA key)" : ""); | ||
1110 | printhost(out, cp, pub, ca, 0); | 1128 | printhost(out, cp, pub, ca, 0); |
1129 | found_key = 1; | ||
1111 | } | 1130 | } |
1112 | if (delete_host) { | 1131 | if (delete_host) { |
1113 | if (!c && !ca) | 1132 | if (!c && !ca) |
@@ -1124,12 +1143,14 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
1124 | c = (match_hostname(name, cp, | 1143 | c = (match_hostname(name, cp, |
1125 | strlen(cp)) == 1); | 1144 | strlen(cp)) == 1); |
1126 | if (find_host && c) { | 1145 | if (find_host && c) { |
1127 | printf("# Host %s found: " | 1146 | if (!quiet) |
1128 | "line %d type %s%s\n", name, | 1147 | printf("# Host %s found: " |
1129 | num, key_type(pub), | 1148 | "line %d type %s%s\n", name, |
1130 | ca ? " (CA key)" : ""); | 1149 | num, key_type(pub), |
1150 | ca ? " (CA key)" : ""); | ||
1131 | printhost(out, name, pub, | 1151 | printhost(out, name, pub, |
1132 | ca, hash_hosts && !ca); | 1152 | ca, hash_hosts && !ca); |
1153 | found_key = 1; | ||
1133 | } | 1154 | } |
1134 | if (delete_host) { | 1155 | if (delete_host) { |
1135 | if (!c && !ca) | 1156 | if (!c && !ca) |
@@ -1205,7 +1226,7 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
1205 | } | 1226 | } |
1206 | } | 1227 | } |
1207 | 1228 | ||
1208 | exit(0); | 1229 | exit (find_host && !found_key); |
1209 | } | 1230 | } |
1210 | 1231 | ||
1211 | /* | 1232 | /* |
@@ -1272,7 +1293,8 @@ do_change_passphrase(struct passwd *pw) | |||
1272 | } | 1293 | } |
1273 | 1294 | ||
1274 | /* Save the file using the new passphrase. */ | 1295 | /* Save the file using the new passphrase. */ |
1275 | if (!key_save_private(private, identity_file, passphrase1, comment)) { | 1296 | if (!key_save_private(private, identity_file, passphrase1, comment, |
1297 | use_new_format, new_format_cipher, rounds)) { | ||
1276 | printf("Saving the key failed: %s.\n", identity_file); | 1298 | printf("Saving the key failed: %s.\n", identity_file); |
1277 | memset(passphrase1, 0, strlen(passphrase1)); | 1299 | memset(passphrase1, 0, strlen(passphrase1)); |
1278 | free(passphrase1); | 1300 | free(passphrase1); |
@@ -1382,7 +1404,8 @@ do_change_comment(struct passwd *pw) | |||
1382 | } | 1404 | } |
1383 | 1405 | ||
1384 | /* Save the file using the new passphrase. */ | 1406 | /* Save the file using the new passphrase. */ |
1385 | if (!key_save_private(private, identity_file, passphrase, new_comment)) { | 1407 | if (!key_save_private(private, identity_file, passphrase, new_comment, |
1408 | use_new_format, new_format_cipher, rounds)) { | ||
1386 | printf("Saving the key failed: %s.\n", identity_file); | 1409 | printf("Saving the key failed: %s.\n", identity_file); |
1387 | memset(passphrase, 0, strlen(passphrase)); | 1410 | memset(passphrase, 0, strlen(passphrase)); |
1388 | free(passphrase); | 1411 | free(passphrase); |
@@ -1593,7 +1616,7 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) | |||
1593 | if ((public = key_load_public(tmp, &comment)) == NULL) | 1616 | if ((public = key_load_public(tmp, &comment)) == NULL) |
1594 | fatal("%s: unable to open \"%s\"", __func__, tmp); | 1617 | fatal("%s: unable to open \"%s\"", __func__, tmp); |
1595 | if (public->type != KEY_RSA && public->type != KEY_DSA && | 1618 | if (public->type != KEY_RSA && public->type != KEY_DSA && |
1596 | public->type != KEY_ECDSA) | 1619 | public->type != KEY_ECDSA && public->type != KEY_ED25519) |
1597 | fatal("%s: key \"%s\" type %s cannot be certified", | 1620 | fatal("%s: key \"%s\" type %s cannot be certified", |
1598 | __func__, tmp, key_type(public)); | 1621 | __func__, tmp, key_type(public)); |
1599 | 1622 | ||
@@ -1738,7 +1761,7 @@ parse_cert_times(char *timespec) | |||
1738 | cert_valid_from = parse_absolute_time(from); | 1761 | cert_valid_from = parse_absolute_time(from); |
1739 | 1762 | ||
1740 | if (*to == '-' || *to == '+') | 1763 | if (*to == '-' || *to == '+') |
1741 | cert_valid_to = parse_relative_time(to, cert_valid_from); | 1764 | cert_valid_to = parse_relative_time(to, now); |
1742 | else | 1765 | else |
1743 | cert_valid_to = parse_absolute_time(to); | 1766 | cert_valid_to = parse_absolute_time(to); |
1744 | 1767 | ||
@@ -1963,7 +1986,7 @@ update_krl_from_file(struct passwd *pw, const char *file, const Key *ca, | |||
1963 | continue; | 1986 | continue; |
1964 | if (strncasecmp(cp, "serial:", 7) == 0) { | 1987 | if (strncasecmp(cp, "serial:", 7) == 0) { |
1965 | if (ca == NULL) { | 1988 | if (ca == NULL) { |
1966 | fatal("revoking certificated by serial number " | 1989 | fatal("revoking certificates by serial number " |
1967 | "requires specification of a CA key"); | 1990 | "requires specification of a CA key"); |
1968 | } | 1991 | } |
1969 | cp += 7; | 1992 | cp += 7; |
@@ -2000,7 +2023,7 @@ update_krl_from_file(struct passwd *pw, const char *file, const Key *ca, | |||
2000 | } | 2023 | } |
2001 | } else if (strncasecmp(cp, "id:", 3) == 0) { | 2024 | } else if (strncasecmp(cp, "id:", 3) == 0) { |
2002 | if (ca == NULL) { | 2025 | if (ca == NULL) { |
2003 | fatal("revoking certificated by key ID " | 2026 | fatal("revoking certificates by key ID " |
2004 | "requires specification of a CA key"); | 2027 | "requires specification of a CA key"); |
2005 | } | 2028 | } |
2006 | cp += 3; | 2029 | cp += 3; |
@@ -2129,7 +2152,7 @@ usage(void) | |||
2129 | fprintf(stderr, "usage: %s [options]\n", __progname); | 2152 | fprintf(stderr, "usage: %s [options]\n", __progname); |
2130 | fprintf(stderr, "Options:\n"); | 2153 | fprintf(stderr, "Options:\n"); |
2131 | fprintf(stderr, " -A Generate non-existent host keys for all key types.\n"); | 2154 | fprintf(stderr, " -A Generate non-existent host keys for all key types.\n"); |
2132 | fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n"); | 2155 | fprintf(stderr, " -a number Number of KDF rounds for new key format or moduli primality tests.\n"); |
2133 | fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); | 2156 | fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); |
2134 | fprintf(stderr, " -b bits Number of bits in the key to create.\n"); | 2157 | fprintf(stderr, " -b bits Number of bits in the key to create.\n"); |
2135 | fprintf(stderr, " -C comment Provide new comment.\n"); | 2158 | fprintf(stderr, " -C comment Provide new comment.\n"); |
@@ -2157,6 +2180,7 @@ usage(void) | |||
2157 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); | 2180 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); |
2158 | fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); | 2181 | fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); |
2159 | fprintf(stderr, " -O option Specify a certificate option.\n"); | 2182 | fprintf(stderr, " -O option Specify a certificate option.\n"); |
2183 | fprintf(stderr, " -o Enforce new private key format.\n"); | ||
2160 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); | 2184 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); |
2161 | fprintf(stderr, " -p Change passphrase of private key file.\n"); | 2185 | fprintf(stderr, " -p Change passphrase of private key file.\n"); |
2162 | fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n"); | 2186 | fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n"); |
@@ -2173,6 +2197,7 @@ usage(void) | |||
2173 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); | 2197 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); |
2174 | fprintf(stderr, " -y Read private key file and print public key.\n"); | 2198 | fprintf(stderr, " -y Read private key file and print public key.\n"); |
2175 | fprintf(stderr, " -z serial Specify a serial number.\n"); | 2199 | fprintf(stderr, " -z serial Specify a serial number.\n"); |
2200 | fprintf(stderr, " -Z cipher Specify a cipher for new private key format.\n"); | ||
2176 | 2201 | ||
2177 | exit(1); | 2202 | exit(1); |
2178 | } | 2203 | } |
@@ -2190,7 +2215,7 @@ main(int argc, char **argv) | |||
2190 | struct passwd *pw; | 2215 | struct passwd *pw; |
2191 | struct stat st; | 2216 | struct stat st; |
2192 | int opt, type, fd; | 2217 | int opt, type, fd; |
2193 | u_int32_t memory = 0, generator_wanted = 0, trials = 100; | 2218 | u_int32_t memory = 0, generator_wanted = 0; |
2194 | int do_gen_candidates = 0, do_screen_candidates = 0; | 2219 | int do_gen_candidates = 0, do_screen_candidates = 0; |
2195 | int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; | 2220 | int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; |
2196 | unsigned long start_lineno = 0, lines_to_process = 0; | 2221 | unsigned long start_lineno = 0, lines_to_process = 0; |
@@ -2222,8 +2247,9 @@ main(int argc, char **argv) | |||
2222 | exit(1); | 2247 | exit(1); |
2223 | } | 2248 | } |
2224 | 2249 | ||
2225 | while ((opt = getopt(argc, argv, "ABHLQXceghiklpquvxy" | 2250 | /* Remaining characters: EUYdw */ |
2226 | "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) { | 2251 | while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" |
2252 | "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) { | ||
2227 | switch (opt) { | 2253 | switch (opt) { |
2228 | case 'A': | 2254 | case 'A': |
2229 | gen_all_hostkeys = 1; | 2255 | gen_all_hostkeys = 1; |
@@ -2281,6 +2307,9 @@ main(int argc, char **argv) | |||
2281 | case 'n': | 2307 | case 'n': |
2282 | cert_principals = optarg; | 2308 | cert_principals = optarg; |
2283 | break; | 2309 | break; |
2310 | case 'o': | ||
2311 | use_new_format = 1; | ||
2312 | break; | ||
2284 | case 'p': | 2313 | case 'p': |
2285 | change_passphrase = 1; | 2314 | change_passphrase = 1; |
2286 | break; | 2315 | break; |
@@ -2308,6 +2337,9 @@ main(int argc, char **argv) | |||
2308 | case 'O': | 2337 | case 'O': |
2309 | add_cert_option(optarg); | 2338 | add_cert_option(optarg); |
2310 | break; | 2339 | break; |
2340 | case 'Z': | ||
2341 | new_format_cipher = optarg; | ||
2342 | break; | ||
2311 | case 'C': | 2343 | case 'C': |
2312 | identity_comment = optarg; | 2344 | identity_comment = optarg; |
2313 | break; | 2345 | break; |
@@ -2366,9 +2398,9 @@ main(int argc, char **argv) | |||
2366 | optarg, errstr); | 2398 | optarg, errstr); |
2367 | break; | 2399 | break; |
2368 | case 'a': | 2400 | case 'a': |
2369 | trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); | 2401 | rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr); |
2370 | if (errstr) | 2402 | if (errstr) |
2371 | fatal("Invalid number of trials: %s (%s)", | 2403 | fatal("Invalid number: %s (%s)", |
2372 | optarg, errstr); | 2404 | optarg, errstr); |
2373 | break; | 2405 | break; |
2374 | case 'M': | 2406 | case 'M': |
@@ -2527,7 +2559,8 @@ main(int argc, char **argv) | |||
2527 | fatal("Couldn't open moduli file \"%s\": %s", | 2559 | fatal("Couldn't open moduli file \"%s\": %s", |
2528 | out_file, strerror(errno)); | 2560 | out_file, strerror(errno)); |
2529 | } | 2561 | } |
2530 | if (prime_test(in, out, trials, generator_wanted, checkpoint, | 2562 | if (prime_test(in, out, rounds == 0 ? 100 : rounds, |
2563 | generator_wanted, checkpoint, | ||
2531 | start_lineno, lines_to_process) != 0) | 2564 | start_lineno, lines_to_process) != 0) |
2532 | fatal("modulus screening failed"); | 2565 | fatal("modulus screening failed"); |
2533 | return (0); | 2566 | return (0); |
@@ -2538,8 +2571,6 @@ main(int argc, char **argv) | |||
2538 | return (0); | 2571 | return (0); |
2539 | } | 2572 | } |
2540 | 2573 | ||
2541 | arc4random_stir(); | ||
2542 | |||
2543 | if (key_type_name == NULL) | 2574 | if (key_type_name == NULL) |
2544 | key_type_name = "rsa"; | 2575 | key_type_name = "rsa"; |
2545 | 2576 | ||
@@ -2621,7 +2652,8 @@ passphrase_again: | |||
2621 | } | 2652 | } |
2622 | 2653 | ||
2623 | /* Save the key with the given passphrase and comment. */ | 2654 | /* Save the key with the given passphrase and comment. */ |
2624 | if (!key_save_private(private, identity_file, passphrase1, comment)) { | 2655 | if (!key_save_private(private, identity_file, passphrase1, comment, |
2656 | use_new_format, new_format_cipher, rounds)) { | ||
2625 | printf("Saving the key failed: %s.\n", identity_file); | 2657 | printf("Saving the key failed: %s.\n", identity_file); |
2626 | memset(passphrase1, 0, strlen(passphrase1)); | 2658 | memset(passphrase1, 0, strlen(passphrase1)); |
2627 | free(passphrase1); | 2659 | free(passphrase1); |
@@ -2633,7 +2665,6 @@ passphrase_again: | |||
2633 | 2665 | ||
2634 | /* Clear the private key and the random number generator. */ | 2666 | /* Clear the private key and the random number generator. */ |
2635 | key_free(private); | 2667 | key_free(private); |
2636 | arc4random_stir(); | ||
2637 | 2668 | ||
2638 | if (!quiet) | 2669 | if (!quiet) |
2639 | printf("Your identification has been saved in %s.\n", identity_file); | 2670 | printf("Your identification has been saved in %s.\n", identity_file); |