diff options
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 149 |
1 files changed, 109 insertions, 40 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c index 64fadc7a1..04a9b939a 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,3 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.160 2007/01/21 01:41:54 stevesk Exp $ */ | ||
1 | /* | 2 | /* |
2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
3 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -12,28 +13,44 @@ | |||
12 | */ | 13 | */ |
13 | 14 | ||
14 | #include "includes.h" | 15 | #include "includes.h" |
15 | RCSID("$OpenBSD: ssh-keygen.c,v 1.135 2005/11/29 02:04:55 dtucker Exp $"); | 16 | |
17 | #include <sys/types.h> | ||
18 | #include <sys/socket.h> | ||
19 | #include <sys/stat.h> | ||
20 | #include <sys/param.h> | ||
16 | 21 | ||
17 | #include <openssl/evp.h> | 22 | #include <openssl/evp.h> |
18 | #include <openssl/pem.h> | 23 | #include <openssl/pem.h> |
19 | 24 | ||
25 | #include <errno.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <netdb.h> | ||
28 | #ifdef HAVE_PATHS_H | ||
29 | # include <paths.h> | ||
30 | #endif | ||
31 | #include <pwd.h> | ||
32 | #include <stdarg.h> | ||
33 | #include <stdio.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <string.h> | ||
36 | #include <unistd.h> | ||
37 | |||
20 | #include "xmalloc.h" | 38 | #include "xmalloc.h" |
21 | #include "key.h" | 39 | #include "key.h" |
22 | #include "rsa.h" | 40 | #include "rsa.h" |
23 | #include "authfile.h" | 41 | #include "authfile.h" |
24 | #include "uuencode.h" | 42 | #include "uuencode.h" |
25 | #include "buffer.h" | 43 | #include "buffer.h" |
26 | #include "bufaux.h" | ||
27 | #include "pathnames.h" | 44 | #include "pathnames.h" |
28 | #include "log.h" | 45 | #include "log.h" |
29 | #include "misc.h" | 46 | #include "misc.h" |
30 | #include "match.h" | 47 | #include "match.h" |
31 | #include "hostfile.h" | 48 | #include "hostfile.h" |
49 | #include "dns.h" | ||
32 | 50 | ||
33 | #ifdef SMARTCARD | 51 | #ifdef SMARTCARD |
34 | #include "scard.h" | 52 | #include "scard.h" |
35 | #endif | 53 | #endif |
36 | #include "dns.h" | ||
37 | 54 | ||
38 | /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ | 55 | /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ |
39 | #define DEFAULT_BITS 2048 | 56 | #define DEFAULT_BITS 2048 |
@@ -103,7 +120,7 @@ ask_filename(struct passwd *pw, const char *prompt) | |||
103 | 120 | ||
104 | if (key_type_name == NULL) | 121 | if (key_type_name == NULL) |
105 | name = _PATH_SSH_CLIENT_ID_RSA; | 122 | name = _PATH_SSH_CLIENT_ID_RSA; |
106 | else | 123 | else { |
107 | switch (key_type_from_name(key_type_name)) { | 124 | switch (key_type_from_name(key_type_name)) { |
108 | case KEY_RSA1: | 125 | case KEY_RSA1: |
109 | name = _PATH_SSH_CLIENT_IDENTITY; | 126 | name = _PATH_SSH_CLIENT_IDENTITY; |
@@ -119,7 +136,7 @@ ask_filename(struct passwd *pw, const char *prompt) | |||
119 | exit(1); | 136 | exit(1); |
120 | break; | 137 | break; |
121 | } | 138 | } |
122 | 139 | } | |
123 | snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); | 140 | snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); |
124 | fprintf(stderr, "%s (%s): ", prompt, identity_file); | 141 | fprintf(stderr, "%s (%s): ", prompt, identity_file); |
125 | if (fgets(buf, sizeof(buf), stdin) == NULL) | 142 | if (fgets(buf, sizeof(buf), stdin) == NULL) |
@@ -205,7 +222,8 @@ buffer_get_bignum_bits(Buffer *b, BIGNUM *value) | |||
205 | if (buffer_len(b) < bytes) | 222 | if (buffer_len(b) < bytes) |
206 | fatal("buffer_get_bignum_bits: input buffer too small: " | 223 | fatal("buffer_get_bignum_bits: input buffer too small: " |
207 | "need %d have %d", bytes, buffer_len(b)); | 224 | "need %d have %d", bytes, buffer_len(b)); |
208 | BN_bin2bn(buffer_ptr(b), bytes, value); | 225 | if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL) |
226 | fatal("buffer_get_bignum_bits: BN_bin2bn failed"); | ||
209 | buffer_consume(b, bytes); | 227 | buffer_consume(b, bytes); |
210 | } | 228 | } |
211 | 229 | ||
@@ -223,7 +241,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
223 | buffer_init(&b); | 241 | buffer_init(&b); |
224 | buffer_append(&b, blob, blen); | 242 | buffer_append(&b, blob, blen); |
225 | 243 | ||
226 | magic = buffer_get_int(&b); | 244 | magic = buffer_get_int(&b); |
227 | if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { | 245 | if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { |
228 | error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); | 246 | error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); |
229 | buffer_free(&b); | 247 | buffer_free(&b); |
@@ -235,7 +253,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
235 | i2 = buffer_get_int(&b); | 253 | i2 = buffer_get_int(&b); |
236 | i3 = buffer_get_int(&b); | 254 | i3 = buffer_get_int(&b); |
237 | i4 = buffer_get_int(&b); | 255 | i4 = buffer_get_int(&b); |
238 | debug("ignore (%d %d %d %d)", i1,i2,i3,i4); | 256 | debug("ignore (%d %d %d %d)", i1, i2, i3, i4); |
239 | if (strcmp(cipher, "none") != 0) { | 257 | if (strcmp(cipher, "none") != 0) { |
240 | error("unsupported cipher %s", cipher); | 258 | error("unsupported cipher %s", cipher); |
241 | xfree(cipher); | 259 | xfree(cipher); |
@@ -266,7 +284,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
266 | buffer_get_bignum_bits(&b, key->dsa->priv_key); | 284 | buffer_get_bignum_bits(&b, key->dsa->priv_key); |
267 | break; | 285 | break; |
268 | case KEY_RSA: | 286 | case KEY_RSA: |
269 | e = buffer_get_char(&b); | 287 | e = buffer_get_char(&b); |
270 | debug("e %lx", e); | 288 | debug("e %lx", e); |
271 | if (e < 30) { | 289 | if (e < 30) { |
272 | e <<= 8; | 290 | e <<= 8; |
@@ -302,13 +320,43 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
302 | return key; | 320 | return key; |
303 | } | 321 | } |
304 | 322 | ||
323 | static int | ||
324 | get_line(FILE *fp, char *line, size_t len) | ||
325 | { | ||
326 | int c; | ||
327 | size_t pos = 0; | ||
328 | |||
329 | line[0] = '\0'; | ||
330 | while ((c = fgetc(fp)) != EOF) { | ||
331 | if (pos >= len - 1) { | ||
332 | fprintf(stderr, "input line too long.\n"); | ||
333 | exit(1); | ||
334 | } | ||
335 | switch (c) { | ||
336 | case '\r': | ||
337 | c = fgetc(fp); | ||
338 | if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) { | ||
339 | fprintf(stderr, "unget: %s\n", strerror(errno)); | ||
340 | exit(1); | ||
341 | } | ||
342 | return pos; | ||
343 | case '\n': | ||
344 | return pos; | ||
345 | } | ||
346 | line[pos++] = c; | ||
347 | line[pos] = '\0'; | ||
348 | } | ||
349 | /* We reached EOF */ | ||
350 | return -1; | ||
351 | } | ||
352 | |||
305 | static void | 353 | static void |
306 | do_convert_from_ssh2(struct passwd *pw) | 354 | do_convert_from_ssh2(struct passwd *pw) |
307 | { | 355 | { |
308 | Key *k; | 356 | Key *k; |
309 | int blen; | 357 | int blen; |
310 | u_int len; | 358 | u_int len; |
311 | char line[1024], *p; | 359 | char line[1024]; |
312 | u_char blob[8096]; | 360 | u_char blob[8096]; |
313 | char encoded[8096]; | 361 | char encoded[8096]; |
314 | struct stat st; | 362 | struct stat st; |
@@ -327,12 +375,8 @@ do_convert_from_ssh2(struct passwd *pw) | |||
327 | exit(1); | 375 | exit(1); |
328 | } | 376 | } |
329 | encoded[0] = '\0'; | 377 | encoded[0] = '\0'; |
330 | while (fgets(line, sizeof(line), fp)) { | 378 | while ((blen = get_line(fp, line, sizeof(line))) != -1) { |
331 | if (!(p = strchr(line, '\n'))) { | 379 | if (line[blen - 1] == '\\') |
332 | fprintf(stderr, "input line too long.\n"); | ||
333 | exit(1); | ||
334 | } | ||
335 | if (p > line && p[-1] == '\\') | ||
336 | escaped++; | 380 | escaped++; |
337 | if (strncmp(line, "----", 4) == 0 || | 381 | if (strncmp(line, "----", 4) == 0 || |
338 | strstr(line, ": ") != NULL) { | 382 | strstr(line, ": ") != NULL) { |
@@ -349,7 +393,6 @@ do_convert_from_ssh2(struct passwd *pw) | |||
349 | /* fprintf(stderr, "escaped: %s", line); */ | 393 | /* fprintf(stderr, "escaped: %s", line); */ |
350 | continue; | 394 | continue; |
351 | } | 395 | } |
352 | *p = '\0'; | ||
353 | strlcat(encoded, line, sizeof(encoded)); | 396 | strlcat(encoded, line, sizeof(encoded)); |
354 | } | 397 | } |
355 | len = strlen(encoded); | 398 | len = strlen(encoded); |
@@ -485,8 +528,10 @@ do_fingerprint(struct passwd *pw) | |||
485 | xfree(fp); | 528 | xfree(fp); |
486 | exit(0); | 529 | exit(0); |
487 | } | 530 | } |
488 | if (comment) | 531 | if (comment) { |
489 | xfree(comment); | 532 | xfree(comment); |
533 | comment = NULL; | ||
534 | } | ||
490 | 535 | ||
491 | f = fopen(identity_file, "r"); | 536 | f = fopen(identity_file, "r"); |
492 | if (f != NULL) { | 537 | if (f != NULL) { |
@@ -508,7 +553,7 @@ do_fingerprint(struct passwd *pw) | |||
508 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | 553 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
509 | ; | 554 | ; |
510 | if (!*cp || *cp == '\n' || *cp == '#') | 555 | if (!*cp || *cp == '\n' || *cp == '#') |
511 | continue ; | 556 | continue; |
512 | i = strtol(cp, &ep, 10); | 557 | i = strtol(cp, &ep, 10); |
513 | if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { | 558 | if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { |
514 | int quoted = 0; | 559 | int quoted = 0; |
@@ -832,30 +877,32 @@ do_change_passphrase(struct passwd *pw) | |||
832 | /* | 877 | /* |
833 | * Print the SSHFP RR. | 878 | * Print the SSHFP RR. |
834 | */ | 879 | */ |
835 | static void | 880 | static int |
836 | do_print_resource_record(struct passwd *pw, char *hname) | 881 | do_print_resource_record(struct passwd *pw, char *fname, char *hname) |
837 | { | 882 | { |
838 | Key *public; | 883 | Key *public; |
839 | char *comment = NULL; | 884 | char *comment = NULL; |
840 | struct stat st; | 885 | struct stat st; |
841 | 886 | ||
842 | if (!have_identity) | 887 | if (fname == NULL) |
843 | ask_filename(pw, "Enter file in which the key is"); | 888 | ask_filename(pw, "Enter file in which the key is"); |
844 | if (stat(identity_file, &st) < 0) { | 889 | if (stat(fname, &st) < 0) { |
845 | perror(identity_file); | 890 | if (errno == ENOENT) |
891 | return 0; | ||
892 | perror(fname); | ||
846 | exit(1); | 893 | exit(1); |
847 | } | 894 | } |
848 | public = key_load_public(identity_file, &comment); | 895 | public = key_load_public(fname, &comment); |
849 | if (public != NULL) { | 896 | if (public != NULL) { |
850 | export_dns_rr(hname, public, stdout, print_generic); | 897 | export_dns_rr(hname, public, stdout, print_generic); |
851 | key_free(public); | 898 | key_free(public); |
852 | xfree(comment); | 899 | xfree(comment); |
853 | exit(0); | 900 | return 1; |
854 | } | 901 | } |
855 | if (comment) | 902 | if (comment) |
856 | xfree(comment); | 903 | xfree(comment); |
857 | 904 | ||
858 | printf("failed to read v2 public key from %s.\n", identity_file); | 905 | printf("failed to read v2 public key from %s.\n", fname); |
859 | exit(1); | 906 | exit(1); |
860 | } | 907 | } |
861 | 908 | ||
@@ -969,13 +1016,13 @@ usage(void) | |||
969 | #ifdef SMARTCARD | 1016 | #ifdef SMARTCARD |
970 | fprintf(stderr, " -D reader Download public key from smartcard.\n"); | 1017 | fprintf(stderr, " -D reader Download public key from smartcard.\n"); |
971 | #endif /* SMARTCARD */ | 1018 | #endif /* SMARTCARD */ |
972 | fprintf(stderr, " -e Convert OpenSSH to IETF SECSH key file.\n"); | 1019 | fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); |
973 | fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); | 1020 | fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); |
974 | fprintf(stderr, " -f filename Filename of the key file.\n"); | 1021 | fprintf(stderr, " -f filename Filename of the key file.\n"); |
975 | fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); | 1022 | fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); |
976 | fprintf(stderr, " -g Use generic DNS resource record format.\n"); | 1023 | fprintf(stderr, " -g Use generic DNS resource record format.\n"); |
977 | fprintf(stderr, " -H Hash names in known_hosts file.\n"); | 1024 | fprintf(stderr, " -H Hash names in known_hosts file.\n"); |
978 | fprintf(stderr, " -i Convert IETF SECSH to OpenSSH key file.\n"); | 1025 | fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); |
979 | fprintf(stderr, " -l Show fingerprint of key file.\n"); | 1026 | fprintf(stderr, " -l Show fingerprint of key file.\n"); |
980 | fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); | 1027 | fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); |
981 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); | 1028 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); |
@@ -1001,7 +1048,7 @@ usage(void) | |||
1001 | * Main program for key management. | 1048 | * Main program for key management. |
1002 | */ | 1049 | */ |
1003 | int | 1050 | int |
1004 | main(int ac, char **av) | 1051 | main(int argc, char **argv) |
1005 | { | 1052 | { |
1006 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; | 1053 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; |
1007 | char out_file[MAXPATHLEN], *reader_id = NULL; | 1054 | char out_file[MAXPATHLEN], *reader_id = NULL; |
@@ -1023,10 +1070,10 @@ main(int ac, char **av) | |||
1023 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 1070 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
1024 | sanitise_stdfd(); | 1071 | sanitise_stdfd(); |
1025 | 1072 | ||
1026 | __progname = ssh_get_progname(av[0]); | 1073 | __progname = ssh_get_progname(argv[0]); |
1027 | 1074 | ||
1028 | SSLeay_add_all_algorithms(); | 1075 | SSLeay_add_all_algorithms(); |
1029 | log_init(av[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); | 1076 | log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); |
1030 | 1077 | ||
1031 | init_rng(); | 1078 | init_rng(); |
1032 | seed_rng(); | 1079 | seed_rng(); |
@@ -1042,11 +1089,11 @@ main(int ac, char **av) | |||
1042 | exit(1); | 1089 | exit(1); |
1043 | } | 1090 | } |
1044 | 1091 | ||
1045 | while ((opt = getopt(ac, av, | 1092 | while ((opt = getopt(argc, argv, |
1046 | "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { | 1093 | "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { |
1047 | switch (opt) { | 1094 | switch (opt) { |
1048 | case 'b': | 1095 | case 'b': |
1049 | bits = strtonum(optarg, 768, 32768, &errstr); | 1096 | bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); |
1050 | if (errstr) | 1097 | if (errstr) |
1051 | fatal("Bits has bad value %s (%s)", | 1098 | fatal("Bits has bad value %s (%s)", |
1052 | optarg, errstr); | 1099 | optarg, errstr); |
@@ -1116,6 +1163,7 @@ main(int ac, char **av) | |||
1116 | break; | 1163 | break; |
1117 | case 'D': | 1164 | case 'D': |
1118 | download = 1; | 1165 | download = 1; |
1166 | /*FALLTHROUGH*/ | ||
1119 | case 'U': | 1167 | case 'U': |
1120 | reader_id = optarg; | 1168 | reader_id = optarg; |
1121 | break; | 1169 | break; |
@@ -1132,19 +1180,20 @@ main(int ac, char **av) | |||
1132 | rr_hostname = optarg; | 1180 | rr_hostname = optarg; |
1133 | break; | 1181 | break; |
1134 | case 'W': | 1182 | case 'W': |
1135 | generator_wanted = strtonum(optarg, 1, UINT_MAX, &errstr); | 1183 | generator_wanted = (u_int32_t)strtonum(optarg, 1, |
1184 | UINT_MAX, &errstr); | ||
1136 | if (errstr) | 1185 | if (errstr) |
1137 | fatal("Desired generator has bad value: %s (%s)", | 1186 | fatal("Desired generator has bad value: %s (%s)", |
1138 | optarg, errstr); | 1187 | optarg, errstr); |
1139 | break; | 1188 | break; |
1140 | case 'a': | 1189 | case 'a': |
1141 | trials = strtonum(optarg, 1, UINT_MAX, &errstr); | 1190 | trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); |
1142 | if (errstr) | 1191 | if (errstr) |
1143 | fatal("Invalid number of trials: %s (%s)", | 1192 | fatal("Invalid number of trials: %s (%s)", |
1144 | optarg, errstr); | 1193 | optarg, errstr); |
1145 | break; | 1194 | break; |
1146 | case 'M': | 1195 | case 'M': |
1147 | memory = strtonum(optarg, 1, UINT_MAX, &errstr); | 1196 | memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); |
1148 | if (errstr) { | 1197 | if (errstr) { |
1149 | fatal("Memory limit is %s: %s", errstr, optarg); | 1198 | fatal("Memory limit is %s: %s", errstr, optarg); |
1150 | } | 1199 | } |
@@ -1173,9 +1222,9 @@ main(int ac, char **av) | |||
1173 | } | 1222 | } |
1174 | 1223 | ||
1175 | /* reinit */ | 1224 | /* reinit */ |
1176 | log_init(av[0], log_level, SYSLOG_FACILITY_USER, 1); | 1225 | log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); |
1177 | 1226 | ||
1178 | if (optind < ac) { | 1227 | if (optind < argc) { |
1179 | printf("Too many arguments.\n"); | 1228 | printf("Too many arguments.\n"); |
1180 | usage(); | 1229 | usage(); |
1181 | } | 1230 | } |
@@ -1198,7 +1247,27 @@ main(int ac, char **av) | |||
1198 | if (print_public) | 1247 | if (print_public) |
1199 | do_print_public(pw); | 1248 | do_print_public(pw); |
1200 | if (rr_hostname != NULL) { | 1249 | if (rr_hostname != NULL) { |
1201 | do_print_resource_record(pw, rr_hostname); | 1250 | unsigned int n = 0; |
1251 | |||
1252 | if (have_identity) { | ||
1253 | n = do_print_resource_record(pw, | ||
1254 | identity_file, rr_hostname); | ||
1255 | if (n == 0) { | ||
1256 | perror(identity_file); | ||
1257 | exit(1); | ||
1258 | } | ||
1259 | exit(0); | ||
1260 | } else { | ||
1261 | |||
1262 | n += do_print_resource_record(pw, | ||
1263 | _PATH_HOST_RSA_KEY_FILE, rr_hostname); | ||
1264 | n += do_print_resource_record(pw, | ||
1265 | _PATH_HOST_DSA_KEY_FILE, rr_hostname); | ||
1266 | |||
1267 | if (n == 0) | ||
1268 | fatal("no keys found."); | ||
1269 | exit(0); | ||
1270 | } | ||
1202 | } | 1271 | } |
1203 | if (reader_id != NULL) { | 1272 | if (reader_id != NULL) { |
1204 | #ifdef SMARTCARD | 1273 | #ifdef SMARTCARD |