diff options
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 759 |
1 files changed, 524 insertions, 235 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c index 37e516ff2..d90b1dfdd 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.185 2010/03/15 19:40:02 stevesk Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.197 2010/08/04 06:07:11 djm 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 |
@@ -105,6 +105,9 @@ char *identity_comment = NULL; | |||
105 | /* Path to CA key when certifying keys. */ | 105 | /* Path to CA key when certifying keys. */ |
106 | char *ca_key_path = NULL; | 106 | char *ca_key_path = NULL; |
107 | 107 | ||
108 | /* Certificate serial number */ | ||
109 | long long cert_serial = 0; | ||
110 | |||
108 | /* Key type when certifying */ | 111 | /* Key type when certifying */ |
109 | u_int cert_key_type = SSH2_CERT_TYPE_USER; | 112 | u_int cert_key_type = SSH2_CERT_TYPE_USER; |
110 | 113 | ||
@@ -118,27 +121,34 @@ char *cert_principals = NULL; | |||
118 | u_int64_t cert_valid_from = 0; | 121 | u_int64_t cert_valid_from = 0; |
119 | u_int64_t cert_valid_to = ~0ULL; | 122 | u_int64_t cert_valid_to = ~0ULL; |
120 | 123 | ||
121 | /* Certificate constraints */ | 124 | /* Certificate options */ |
122 | #define CONSTRAINT_X_FWD (1) | 125 | #define CERTOPT_X_FWD (1) |
123 | #define CONSTRAINT_AGENT_FWD (1<<1) | 126 | #define CERTOPT_AGENT_FWD (1<<1) |
124 | #define CONSTRAINT_PORT_FWD (1<<2) | 127 | #define CERTOPT_PORT_FWD (1<<2) |
125 | #define CONSTRAINT_PTY (1<<3) | 128 | #define CERTOPT_PTY (1<<3) |
126 | #define CONSTRAINT_USER_RC (1<<4) | 129 | #define CERTOPT_USER_RC (1<<4) |
127 | #define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \ | 130 | #define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ |
128 | CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \ | 131 | CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) |
129 | CONSTRAINT_USER_RC) | 132 | u_int32_t certflags_flags = CERTOPT_DEFAULT; |
130 | u_int32_t constraint_flags = CONSTRAINT_DEFAULT; | 133 | char *certflags_command = NULL; |
131 | char *constraint_command = NULL; | 134 | char *certflags_src_addr = NULL; |
132 | char *constraint_src_addr = NULL; | 135 | |
133 | 136 | /* Conversion to/from various formats */ | |
134 | /* Dump public key file in format used by real and the original SSH 2 */ | 137 | int convert_to = 0; |
135 | int convert_to_ssh2 = 0; | 138 | int convert_from = 0; |
136 | int convert_from_ssh2 = 0; | 139 | enum { |
140 | FMT_RFC4716, | ||
141 | FMT_PKCS8, | ||
142 | FMT_PEM | ||
143 | } convert_format = FMT_RFC4716; | ||
137 | int print_public = 0; | 144 | int print_public = 0; |
138 | int print_generic = 0; | 145 | int print_generic = 0; |
139 | 146 | ||
140 | char *key_type_name = NULL; | 147 | char *key_type_name = NULL; |
141 | 148 | ||
149 | /* Load key from this PKCS#11 provider */ | ||
150 | char *pkcs11provider = NULL; | ||
151 | |||
142 | /* argv0 */ | 152 | /* argv0 */ |
143 | extern char *__progname; | 153 | extern char *__progname; |
144 | 154 | ||
@@ -161,9 +171,13 @@ ask_filename(struct passwd *pw, const char *prompt) | |||
161 | case KEY_RSA1: | 171 | case KEY_RSA1: |
162 | name = _PATH_SSH_CLIENT_IDENTITY; | 172 | name = _PATH_SSH_CLIENT_IDENTITY; |
163 | break; | 173 | break; |
174 | case KEY_DSA_CERT: | ||
175 | case KEY_DSA_CERT_V00: | ||
164 | case KEY_DSA: | 176 | case KEY_DSA: |
165 | name = _PATH_SSH_CLIENT_ID_DSA; | 177 | name = _PATH_SSH_CLIENT_ID_DSA; |
166 | break; | 178 | break; |
179 | case KEY_RSA_CERT: | ||
180 | case KEY_RSA_CERT_V00: | ||
167 | case KEY_RSA: | 181 | case KEY_RSA: |
168 | name = _PATH_SSH_CLIENT_ID_RSA; | 182 | name = _PATH_SSH_CLIENT_ID_RSA; |
169 | break; | 183 | break; |
@@ -209,30 +223,12 @@ load_identity(char *filename) | |||
209 | #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb | 223 | #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb |
210 | 224 | ||
211 | static void | 225 | static void |
212 | do_convert_to_ssh2(struct passwd *pw) | 226 | do_convert_to_ssh2(struct passwd *pw, Key *k) |
213 | { | 227 | { |
214 | Key *k; | ||
215 | u_int len; | 228 | u_int len; |
216 | u_char *blob; | 229 | u_char *blob; |
217 | char comment[61]; | 230 | char comment[61]; |
218 | struct stat st; | ||
219 | 231 | ||
220 | if (!have_identity) | ||
221 | ask_filename(pw, "Enter file in which the key is"); | ||
222 | if (stat(identity_file, &st) < 0) { | ||
223 | perror(identity_file); | ||
224 | exit(1); | ||
225 | } | ||
226 | if ((k = key_load_public(identity_file, NULL)) == NULL) { | ||
227 | if ((k = load_identity(identity_file)) == NULL) { | ||
228 | fprintf(stderr, "load failed\n"); | ||
229 | exit(1); | ||
230 | } | ||
231 | } | ||
232 | if (k->type == KEY_RSA1) { | ||
233 | fprintf(stderr, "version 1 keys are not supported\n"); | ||
234 | exit(1); | ||
235 | } | ||
236 | if (key_to_blob(k, &blob, &len) <= 0) { | 232 | if (key_to_blob(k, &blob, &len) <= 0) { |
237 | fprintf(stderr, "key_to_blob failed\n"); | 233 | fprintf(stderr, "key_to_blob failed\n"); |
238 | exit(1); | 234 | exit(1); |
@@ -253,6 +249,81 @@ do_convert_to_ssh2(struct passwd *pw) | |||
253 | } | 249 | } |
254 | 250 | ||
255 | static void | 251 | static void |
252 | do_convert_to_pkcs8(Key *k) | ||
253 | { | ||
254 | switch (key_type_plain(k->type)) { | ||
255 | case KEY_RSA: | ||
256 | if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) | ||
257 | fatal("PEM_write_RSA_PUBKEY failed"); | ||
258 | break; | ||
259 | case KEY_DSA: | ||
260 | if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) | ||
261 | fatal("PEM_write_DSA_PUBKEY failed"); | ||
262 | break; | ||
263 | default: | ||
264 | fatal("%s: unsupported key type %s", __func__, key_type(k)); | ||
265 | } | ||
266 | exit(0); | ||
267 | } | ||
268 | |||
269 | static void | ||
270 | do_convert_to_pem(Key *k) | ||
271 | { | ||
272 | switch (key_type_plain(k->type)) { | ||
273 | case KEY_RSA: | ||
274 | if (!PEM_write_RSAPublicKey(stdout, k->rsa)) | ||
275 | fatal("PEM_write_RSAPublicKey failed"); | ||
276 | break; | ||
277 | #if notyet /* OpenSSH 0.9.8 lacks this function */ | ||
278 | case KEY_DSA: | ||
279 | if (!PEM_write_DSAPublicKey(stdout, k->dsa)) | ||
280 | fatal("PEM_write_DSAPublicKey failed"); | ||
281 | break; | ||
282 | #endif | ||
283 | default: | ||
284 | fatal("%s: unsupported key type %s", __func__, key_type(k)); | ||
285 | } | ||
286 | exit(0); | ||
287 | } | ||
288 | |||
289 | static void | ||
290 | do_convert_to(struct passwd *pw) | ||
291 | { | ||
292 | Key *k; | ||
293 | struct stat st; | ||
294 | |||
295 | if (!have_identity) | ||
296 | ask_filename(pw, "Enter file in which the key is"); | ||
297 | if (stat(identity_file, &st) < 0) | ||
298 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); | ||
299 | if ((k = key_load_public(identity_file, NULL)) == NULL) { | ||
300 | if ((k = load_identity(identity_file)) == NULL) { | ||
301 | fprintf(stderr, "load failed\n"); | ||
302 | exit(1); | ||
303 | } | ||
304 | } | ||
305 | if (k->type == KEY_RSA1) { | ||
306 | fprintf(stderr, "version 1 keys are not supported\n"); | ||
307 | exit(1); | ||
308 | } | ||
309 | |||
310 | switch (convert_format) { | ||
311 | case FMT_RFC4716: | ||
312 | do_convert_to_ssh2(pw, k); | ||
313 | break; | ||
314 | case FMT_PKCS8: | ||
315 | do_convert_to_pkcs8(k); | ||
316 | break; | ||
317 | case FMT_PEM: | ||
318 | do_convert_to_pem(k); | ||
319 | break; | ||
320 | default: | ||
321 | fatal("%s: unknown key format %d", __func__, convert_format); | ||
322 | } | ||
323 | exit(0); | ||
324 | } | ||
325 | |||
326 | static void | ||
256 | buffer_get_bignum_bits(Buffer *b, BIGNUM *value) | 327 | buffer_get_bignum_bits(Buffer *b, BIGNUM *value) |
257 | { | 328 | { |
258 | u_int bignum_bits = buffer_get_int(b); | 329 | u_int bignum_bits = buffer_get_int(b); |
@@ -390,29 +461,18 @@ get_line(FILE *fp, char *line, size_t len) | |||
390 | } | 461 | } |
391 | 462 | ||
392 | static void | 463 | static void |
393 | do_convert_from_ssh2(struct passwd *pw) | 464 | do_convert_from_ssh2(struct passwd *pw, Key **k, int *private) |
394 | { | 465 | { |
395 | Key *k; | ||
396 | int blen; | 466 | int blen; |
397 | u_int len; | 467 | u_int len; |
398 | char line[1024]; | 468 | char line[1024]; |
399 | u_char blob[8096]; | 469 | u_char blob[8096]; |
400 | char encoded[8096]; | 470 | char encoded[8096]; |
401 | struct stat st; | 471 | int escaped = 0; |
402 | int escaped = 0, private = 0, ok; | ||
403 | FILE *fp; | 472 | FILE *fp; |
404 | 473 | ||
405 | if (!have_identity) | 474 | if ((fp = fopen(identity_file, "r")) == NULL) |
406 | ask_filename(pw, "Enter file in which the key is"); | 475 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); |
407 | if (stat(identity_file, &st) < 0) { | ||
408 | perror(identity_file); | ||
409 | exit(1); | ||
410 | } | ||
411 | fp = fopen(identity_file, "r"); | ||
412 | if (fp == NULL) { | ||
413 | perror(identity_file); | ||
414 | exit(1); | ||
415 | } | ||
416 | encoded[0] = '\0'; | 476 | encoded[0] = '\0'; |
417 | while ((blen = get_line(fp, line, sizeof(line))) != -1) { | 477 | while ((blen = get_line(fp, line, sizeof(line))) != -1) { |
418 | if (line[blen - 1] == '\\') | 478 | if (line[blen - 1] == '\\') |
@@ -420,7 +480,7 @@ do_convert_from_ssh2(struct passwd *pw) | |||
420 | if (strncmp(line, "----", 4) == 0 || | 480 | if (strncmp(line, "----", 4) == 0 || |
421 | strstr(line, ": ") != NULL) { | 481 | strstr(line, ": ") != NULL) { |
422 | if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) | 482 | if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) |
423 | private = 1; | 483 | *private = 1; |
424 | if (strstr(line, " END ") != NULL) { | 484 | if (strstr(line, " END ") != NULL) { |
425 | break; | 485 | break; |
426 | } | 486 | } |
@@ -445,26 +505,130 @@ do_convert_from_ssh2(struct passwd *pw) | |||
445 | fprintf(stderr, "uudecode failed.\n"); | 505 | fprintf(stderr, "uudecode failed.\n"); |
446 | exit(1); | 506 | exit(1); |
447 | } | 507 | } |
448 | k = private ? | 508 | *k = *private ? |
449 | do_convert_private_ssh2_from_blob(blob, blen) : | 509 | do_convert_private_ssh2_from_blob(blob, blen) : |
450 | key_from_blob(blob, blen); | 510 | key_from_blob(blob, blen); |
451 | if (k == NULL) { | 511 | if (*k == NULL) { |
452 | fprintf(stderr, "decode blob failed.\n"); | 512 | fprintf(stderr, "decode blob failed.\n"); |
453 | exit(1); | 513 | exit(1); |
454 | } | 514 | } |
455 | ok = private ? | 515 | fclose(fp); |
456 | (k->type == KEY_DSA ? | 516 | } |
457 | PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : | 517 | |
458 | PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : | 518 | static void |
459 | key_write(k, stdout); | 519 | do_convert_from_pkcs8(Key **k, int *private) |
520 | { | ||
521 | EVP_PKEY *pubkey; | ||
522 | FILE *fp; | ||
523 | |||
524 | if ((fp = fopen(identity_file, "r")) == NULL) | ||
525 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); | ||
526 | if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
527 | fatal("%s: %s is not a recognised public key format", __func__, | ||
528 | identity_file); | ||
529 | } | ||
530 | fclose(fp); | ||
531 | switch (EVP_PKEY_type(pubkey->type)) { | ||
532 | case EVP_PKEY_RSA: | ||
533 | *k = key_new(KEY_UNSPEC); | ||
534 | (*k)->type = KEY_RSA; | ||
535 | (*k)->rsa = EVP_PKEY_get1_RSA(pubkey); | ||
536 | break; | ||
537 | case EVP_PKEY_DSA: | ||
538 | *k = key_new(KEY_UNSPEC); | ||
539 | (*k)->type = KEY_DSA; | ||
540 | (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); | ||
541 | break; | ||
542 | default: | ||
543 | fatal("%s: unsupported pubkey type %d", __func__, | ||
544 | EVP_PKEY_type(pubkey->type)); | ||
545 | } | ||
546 | EVP_PKEY_free(pubkey); | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | static void | ||
551 | do_convert_from_pem(Key **k, int *private) | ||
552 | { | ||
553 | FILE *fp; | ||
554 | RSA *rsa; | ||
555 | #ifdef notyet | ||
556 | DSA *dsa; | ||
557 | #endif | ||
558 | |||
559 | if ((fp = fopen(identity_file, "r")) == NULL) | ||
560 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); | ||
561 | if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { | ||
562 | *k = key_new(KEY_UNSPEC); | ||
563 | (*k)->type = KEY_RSA; | ||
564 | (*k)->rsa = rsa; | ||
565 | fclose(fp); | ||
566 | return; | ||
567 | } | ||
568 | #if notyet /* OpenSSH 0.9.8 lacks this function */ | ||
569 | rewind(fp); | ||
570 | if ((dsa = PEM_read_DSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { | ||
571 | *k = key_new(KEY_UNSPEC); | ||
572 | (*k)->type = KEY_DSA; | ||
573 | (*k)->dsa = dsa; | ||
574 | fclose(fp); | ||
575 | return; | ||
576 | } | ||
577 | #endif | ||
578 | fatal("%s: unrecognised raw private key format", __func__); | ||
579 | } | ||
580 | |||
581 | static void | ||
582 | do_convert_from(struct passwd *pw) | ||
583 | { | ||
584 | Key *k = NULL; | ||
585 | int private = 0, ok = 0; | ||
586 | struct stat st; | ||
587 | |||
588 | if (!have_identity) | ||
589 | ask_filename(pw, "Enter file in which the key is"); | ||
590 | if (stat(identity_file, &st) < 0) | ||
591 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); | ||
592 | |||
593 | switch (convert_format) { | ||
594 | case FMT_RFC4716: | ||
595 | do_convert_from_ssh2(pw, &k, &private); | ||
596 | break; | ||
597 | case FMT_PKCS8: | ||
598 | do_convert_from_pkcs8(&k, &private); | ||
599 | break; | ||
600 | case FMT_PEM: | ||
601 | do_convert_from_pem(&k, &private); | ||
602 | break; | ||
603 | default: | ||
604 | fatal("%s: unknown key format %d", __func__, convert_format); | ||
605 | } | ||
606 | |||
607 | if (!private) | ||
608 | ok = key_write(k, stdout); | ||
609 | if (ok) | ||
610 | fprintf(stdout, "\n"); | ||
611 | else { | ||
612 | switch (k->type) { | ||
613 | case KEY_DSA: | ||
614 | ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, | ||
615 | NULL, 0, NULL, NULL); | ||
616 | break; | ||
617 | case KEY_RSA: | ||
618 | ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, | ||
619 | NULL, 0, NULL, NULL); | ||
620 | break; | ||
621 | default: | ||
622 | fatal("%s: unsupported key type %s", __func__, | ||
623 | key_type(k)); | ||
624 | } | ||
625 | } | ||
626 | |||
460 | if (!ok) { | 627 | if (!ok) { |
461 | fprintf(stderr, "key write failed\n"); | 628 | fprintf(stderr, "key write failed\n"); |
462 | exit(1); | 629 | exit(1); |
463 | } | 630 | } |
464 | key_free(k); | 631 | key_free(k); |
465 | if (!private) | ||
466 | fprintf(stdout, "\n"); | ||
467 | fclose(fp); | ||
468 | exit(0); | 632 | exit(0); |
469 | } | 633 | } |
470 | 634 | ||
@@ -493,7 +657,7 @@ do_print_public(struct passwd *pw) | |||
493 | } | 657 | } |
494 | 658 | ||
495 | static void | 659 | static void |
496 | do_download(struct passwd *pw, char *pkcs11provider) | 660 | do_download(struct passwd *pw) |
497 | { | 661 | { |
498 | #ifdef ENABLE_PKCS11 | 662 | #ifdef ENABLE_PKCS11 |
499 | Key **keys = NULL; | 663 | Key **keys = NULL; |
@@ -555,67 +719,68 @@ do_fingerprint(struct passwd *pw) | |||
555 | comment = NULL; | 719 | comment = NULL; |
556 | } | 720 | } |
557 | 721 | ||
558 | f = fopen(identity_file, "r"); | 722 | if ((f = fopen(identity_file, "r")) == NULL) |
559 | if (f != NULL) { | 723 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); |
560 | while (fgets(line, sizeof(line), f)) { | ||
561 | if ((cp = strchr(line, '\n')) == NULL) { | ||
562 | error("line %d too long: %.40s...", | ||
563 | num + 1, line); | ||
564 | skip = 1; | ||
565 | continue; | ||
566 | } | ||
567 | num++; | ||
568 | if (skip) { | ||
569 | skip = 0; | ||
570 | continue; | ||
571 | } | ||
572 | *cp = '\0'; | ||
573 | 724 | ||
574 | /* Skip leading whitespace, empty and comment lines. */ | 725 | while (fgets(line, sizeof(line), f)) { |
575 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | 726 | if ((cp = strchr(line, '\n')) == NULL) { |
576 | ; | 727 | error("line %d too long: %.40s...", |
577 | if (!*cp || *cp == '\n' || *cp == '#') | 728 | num + 1, line); |
578 | continue; | 729 | skip = 1; |
579 | i = strtol(cp, &ep, 10); | 730 | continue; |
580 | if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { | 731 | } |
581 | int quoted = 0; | 732 | num++; |
582 | comment = cp; | 733 | if (skip) { |
583 | for (; *cp && (quoted || (*cp != ' ' && | 734 | skip = 0; |
584 | *cp != '\t')); cp++) { | 735 | continue; |
585 | if (*cp == '\\' && cp[1] == '"') | 736 | } |
586 | cp++; /* Skip both */ | 737 | *cp = '\0'; |
587 | else if (*cp == '"') | 738 | |
588 | quoted = !quoted; | 739 | /* Skip leading whitespace, empty and comment lines. */ |
589 | } | 740 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
590 | if (!*cp) | 741 | ; |
591 | continue; | 742 | if (!*cp || *cp == '\n' || *cp == '#') |
592 | *cp++ = '\0'; | 743 | continue; |
744 | i = strtol(cp, &ep, 10); | ||
745 | if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { | ||
746 | int quoted = 0; | ||
747 | comment = cp; | ||
748 | for (; *cp && (quoted || (*cp != ' ' && | ||
749 | *cp != '\t')); cp++) { | ||
750 | if (*cp == '\\' && cp[1] == '"') | ||
751 | cp++; /* Skip both */ | ||
752 | else if (*cp == '"') | ||
753 | quoted = !quoted; | ||
593 | } | 754 | } |
594 | ep = cp; | 755 | if (!*cp) |
595 | public = key_new(KEY_RSA1); | 756 | continue; |
757 | *cp++ = '\0'; | ||
758 | } | ||
759 | ep = cp; | ||
760 | public = key_new(KEY_RSA1); | ||
761 | if (key_read(public, &cp) != 1) { | ||
762 | cp = ep; | ||
763 | key_free(public); | ||
764 | public = key_new(KEY_UNSPEC); | ||
596 | if (key_read(public, &cp) != 1) { | 765 | if (key_read(public, &cp) != 1) { |
597 | cp = ep; | ||
598 | key_free(public); | 766 | key_free(public); |
599 | public = key_new(KEY_UNSPEC); | 767 | continue; |
600 | if (key_read(public, &cp) != 1) { | ||
601 | key_free(public); | ||
602 | continue; | ||
603 | } | ||
604 | } | 768 | } |
605 | comment = *cp ? cp : comment; | ||
606 | fp = key_fingerprint(public, fptype, rep); | ||
607 | ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); | ||
608 | printf("%u %s %s (%s)\n", key_size(public), fp, | ||
609 | comment ? comment : "no comment", key_type(public)); | ||
610 | if (log_level >= SYSLOG_LEVEL_VERBOSE) | ||
611 | printf("%s\n", ra); | ||
612 | xfree(ra); | ||
613 | xfree(fp); | ||
614 | key_free(public); | ||
615 | invalid = 0; | ||
616 | } | 769 | } |
617 | fclose(f); | 770 | comment = *cp ? cp : comment; |
771 | fp = key_fingerprint(public, fptype, rep); | ||
772 | ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); | ||
773 | printf("%u %s %s (%s)\n", key_size(public), fp, | ||
774 | comment ? comment : "no comment", key_type(public)); | ||
775 | if (log_level >= SYSLOG_LEVEL_VERBOSE) | ||
776 | printf("%s\n", ra); | ||
777 | xfree(ra); | ||
778 | xfree(fp); | ||
779 | key_free(public); | ||
780 | invalid = 0; | ||
618 | } | 781 | } |
782 | fclose(f); | ||
783 | |||
619 | if (invalid) { | 784 | if (invalid) { |
620 | printf("%s is not a public key file.\n", identity_file); | 785 | printf("%s is not a public key file.\n", identity_file); |
621 | exit(1); | 786 | exit(1); |
@@ -670,7 +835,7 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
670 | have_identity = 1; | 835 | have_identity = 1; |
671 | } | 836 | } |
672 | if ((in = fopen(identity_file, "r")) == NULL) | 837 | if ((in = fopen(identity_file, "r")) == NULL) |
673 | fatal("fopen: %s", strerror(errno)); | 838 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); |
674 | 839 | ||
675 | /* | 840 | /* |
676 | * Find hosts goes to stdout, hash and deletions happen in-place | 841 | * Find hosts goes to stdout, hash and deletions happen in-place |
@@ -1104,7 +1269,7 @@ fmt_validity(u_int64_t valid_from, u_int64_t valid_to) | |||
1104 | } | 1269 | } |
1105 | 1270 | ||
1106 | static void | 1271 | static void |
1107 | add_flag_constraint(Buffer *c, const char *name) | 1272 | add_flag_option(Buffer *c, const char *name) |
1108 | { | 1273 | { |
1109 | debug3("%s: %s", __func__, name); | 1274 | debug3("%s: %s", __func__, name); |
1110 | buffer_put_cstring(c, name); | 1275 | buffer_put_cstring(c, name); |
@@ -1112,7 +1277,7 @@ add_flag_constraint(Buffer *c, const char *name) | |||
1112 | } | 1277 | } |
1113 | 1278 | ||
1114 | static void | 1279 | static void |
1115 | add_string_constraint(Buffer *c, const char *name, const char *value) | 1280 | add_string_option(Buffer *c, const char *name, const char *value) |
1116 | { | 1281 | { |
1117 | Buffer b; | 1282 | Buffer b; |
1118 | 1283 | ||
@@ -1126,25 +1291,62 @@ add_string_constraint(Buffer *c, const char *name, const char *value) | |||
1126 | buffer_free(&b); | 1291 | buffer_free(&b); |
1127 | } | 1292 | } |
1128 | 1293 | ||
1294 | #define OPTIONS_CRITICAL 1 | ||
1295 | #define OPTIONS_EXTENSIONS 2 | ||
1129 | static void | 1296 | static void |
1130 | prepare_constraint_buf(Buffer *c) | 1297 | prepare_options_buf(Buffer *c, int which) |
1131 | { | 1298 | { |
1132 | |||
1133 | buffer_clear(c); | 1299 | buffer_clear(c); |
1134 | if ((constraint_flags & CONSTRAINT_X_FWD) != 0) | 1300 | if ((which & OPTIONS_CRITICAL) != 0 && |
1135 | add_flag_constraint(c, "permit-X11-forwarding"); | 1301 | certflags_command != NULL) |
1136 | if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0) | 1302 | add_string_option(c, "force-command", certflags_command); |
1137 | add_flag_constraint(c, "permit-agent-forwarding"); | 1303 | if ((which & OPTIONS_EXTENSIONS) != 0 && |
1138 | if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0) | 1304 | (certflags_flags & CERTOPT_AGENT_FWD) != 0) |
1139 | add_flag_constraint(c, "permit-port-forwarding"); | 1305 | add_flag_option(c, "permit-agent-forwarding"); |
1140 | if ((constraint_flags & CONSTRAINT_PTY) != 0) | 1306 | if ((which & OPTIONS_EXTENSIONS) != 0 && |
1141 | add_flag_constraint(c, "permit-pty"); | 1307 | (certflags_flags & CERTOPT_PORT_FWD) != 0) |
1142 | if ((constraint_flags & CONSTRAINT_USER_RC) != 0) | 1308 | add_flag_option(c, "permit-port-forwarding"); |
1143 | add_flag_constraint(c, "permit-user-rc"); | 1309 | if ((which & OPTIONS_EXTENSIONS) != 0 && |
1144 | if (constraint_command != NULL) | 1310 | (certflags_flags & CERTOPT_PTY) != 0) |
1145 | add_string_constraint(c, "force-command", constraint_command); | 1311 | add_flag_option(c, "permit-pty"); |
1146 | if (constraint_src_addr != NULL) | 1312 | if ((which & OPTIONS_EXTENSIONS) != 0 && |
1147 | add_string_constraint(c, "source-address", constraint_src_addr); | 1313 | (certflags_flags & CERTOPT_USER_RC) != 0) |
1314 | add_flag_option(c, "permit-user-rc"); | ||
1315 | if ((which & OPTIONS_EXTENSIONS) != 0 && | ||
1316 | (certflags_flags & CERTOPT_X_FWD) != 0) | ||
1317 | add_flag_option(c, "permit-X11-forwarding"); | ||
1318 | if ((which & OPTIONS_CRITICAL) != 0 && | ||
1319 | certflags_src_addr != NULL) | ||
1320 | add_string_option(c, "source-address", certflags_src_addr); | ||
1321 | } | ||
1322 | |||
1323 | static Key * | ||
1324 | load_pkcs11_key(char *path) | ||
1325 | { | ||
1326 | #ifdef ENABLE_PKCS11 | ||
1327 | Key **keys = NULL, *public, *private = NULL; | ||
1328 | int i, nkeys; | ||
1329 | |||
1330 | if ((public = key_load_public(path, NULL)) == NULL) | ||
1331 | fatal("Couldn't load CA public key \"%s\"", path); | ||
1332 | |||
1333 | nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys); | ||
1334 | debug3("%s: %d keys", __func__, nkeys); | ||
1335 | if (nkeys <= 0) | ||
1336 | fatal("cannot read public key from pkcs11"); | ||
1337 | for (i = 0; i < nkeys; i++) { | ||
1338 | if (key_equal_public(public, keys[i])) { | ||
1339 | private = keys[i]; | ||
1340 | continue; | ||
1341 | } | ||
1342 | key_free(keys[i]); | ||
1343 | } | ||
1344 | xfree(keys); | ||
1345 | key_free(public); | ||
1346 | return private; | ||
1347 | #else | ||
1348 | fatal("no pkcs11 support"); | ||
1349 | #endif /* ENABLE_PKCS11 */ | ||
1148 | } | 1350 | } |
1149 | 1351 | ||
1150 | static void | 1352 | static void |
@@ -1155,9 +1357,33 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) | |||
1155 | Key *ca, *public; | 1357 | Key *ca, *public; |
1156 | char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; | 1358 | char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; |
1157 | FILE *f; | 1359 | FILE *f; |
1360 | int v00 = 0; /* legacy keys */ | ||
1361 | |||
1362 | if (key_type_name != NULL) { | ||
1363 | switch (key_type_from_name(key_type_name)) { | ||
1364 | case KEY_RSA_CERT_V00: | ||
1365 | case KEY_DSA_CERT_V00: | ||
1366 | v00 = 1; | ||
1367 | break; | ||
1368 | case KEY_UNSPEC: | ||
1369 | if (strcasecmp(key_type_name, "v00") == 0) { | ||
1370 | v00 = 1; | ||
1371 | break; | ||
1372 | } else if (strcasecmp(key_type_name, "v01") == 0) | ||
1373 | break; | ||
1374 | /* FALLTHROUGH */ | ||
1375 | default: | ||
1376 | fprintf(stderr, "unknown key type %s\n", key_type_name); | ||
1377 | exit(1); | ||
1378 | } | ||
1379 | } | ||
1158 | 1380 | ||
1381 | pkcs11_init(1); | ||
1159 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); | 1382 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); |
1160 | if ((ca = load_identity(tmp)) == NULL) | 1383 | if (pkcs11provider != NULL) { |
1384 | if ((ca = load_pkcs11_key(tmp)) == NULL) | ||
1385 | fatal("No PKCS#11 key matching %s found", ca_key_path); | ||
1386 | } else if ((ca = load_identity(tmp)) == NULL) | ||
1161 | fatal("Couldn't load CA key \"%s\"", tmp); | 1387 | fatal("Couldn't load CA key \"%s\"", tmp); |
1162 | xfree(tmp); | 1388 | xfree(tmp); |
1163 | 1389 | ||
@@ -1183,15 +1409,24 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) | |||
1183 | __func__, tmp, key_type(public)); | 1409 | __func__, tmp, key_type(public)); |
1184 | 1410 | ||
1185 | /* Prepare certificate to sign */ | 1411 | /* Prepare certificate to sign */ |
1186 | if (key_to_certified(public) != 0) | 1412 | if (key_to_certified(public, v00) != 0) |
1187 | fatal("Could not upgrade key %s to certificate", tmp); | 1413 | fatal("Could not upgrade key %s to certificate", tmp); |
1188 | public->cert->type = cert_key_type; | 1414 | public->cert->type = cert_key_type; |
1415 | public->cert->serial = (u_int64_t)cert_serial; | ||
1189 | public->cert->key_id = xstrdup(cert_key_id); | 1416 | public->cert->key_id = xstrdup(cert_key_id); |
1190 | public->cert->nprincipals = n; | 1417 | public->cert->nprincipals = n; |
1191 | public->cert->principals = plist; | 1418 | public->cert->principals = plist; |
1192 | public->cert->valid_after = cert_valid_from; | 1419 | public->cert->valid_after = cert_valid_from; |
1193 | public->cert->valid_before = cert_valid_to; | 1420 | public->cert->valid_before = cert_valid_to; |
1194 | prepare_constraint_buf(&public->cert->constraints); | 1421 | if (v00) { |
1422 | prepare_options_buf(&public->cert->critical, | ||
1423 | OPTIONS_CRITICAL|OPTIONS_EXTENSIONS); | ||
1424 | } else { | ||
1425 | prepare_options_buf(&public->cert->critical, | ||
1426 | OPTIONS_CRITICAL); | ||
1427 | prepare_options_buf(&public->cert->extensions, | ||
1428 | OPTIONS_EXTENSIONS); | ||
1429 | } | ||
1195 | public->cert->signature_key = key_from_private(ca); | 1430 | public->cert->signature_key = key_from_private(ca); |
1196 | 1431 | ||
1197 | if (key_certify(public, ca) != 0) | 1432 | if (key_certify(public, ca) != 0) |
@@ -1212,17 +1447,19 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) | |||
1212 | fprintf(f, " %s\n", comment); | 1447 | fprintf(f, " %s\n", comment); |
1213 | fclose(f); | 1448 | fclose(f); |
1214 | 1449 | ||
1215 | if (!quiet) | 1450 | if (!quiet) { |
1216 | logit("Signed %s key %s: id \"%s\"%s%s valid %s", | 1451 | logit("Signed %s key %s: id \"%s\" serial %llu%s%s " |
1217 | cert_key_type == SSH2_CERT_TYPE_USER?"user":"host", | 1452 | "valid %s", key_cert_type(public), |
1218 | out, cert_key_id, | 1453 | out, public->cert->key_id, public->cert->serial, |
1219 | cert_principals != NULL ? " for " : "", | 1454 | cert_principals != NULL ? " for " : "", |
1220 | cert_principals != NULL ? cert_principals : "", | 1455 | cert_principals != NULL ? cert_principals : "", |
1221 | fmt_validity(cert_valid_from, cert_valid_to)); | 1456 | fmt_validity(cert_valid_from, cert_valid_to)); |
1457 | } | ||
1222 | 1458 | ||
1223 | key_free(public); | 1459 | key_free(public); |
1224 | xfree(out); | 1460 | xfree(out); |
1225 | } | 1461 | } |
1462 | pkcs11_terminate(); | ||
1226 | exit(0); | 1463 | exit(0); |
1227 | } | 1464 | } |
1228 | 1465 | ||
@@ -1321,50 +1558,92 @@ parse_cert_times(char *timespec) | |||
1321 | } | 1558 | } |
1322 | 1559 | ||
1323 | static void | 1560 | static void |
1324 | add_cert_constraint(char *opt) | 1561 | add_cert_option(char *opt) |
1325 | { | 1562 | { |
1326 | char *val; | 1563 | char *val; |
1327 | 1564 | ||
1328 | if (strcmp(opt, "clear") == 0) | 1565 | if (strcmp(opt, "clear") == 0) |
1329 | constraint_flags = 0; | 1566 | certflags_flags = 0; |
1330 | else if (strcasecmp(opt, "no-x11-forwarding") == 0) | 1567 | else if (strcasecmp(opt, "no-x11-forwarding") == 0) |
1331 | constraint_flags &= ~CONSTRAINT_X_FWD; | 1568 | certflags_flags &= ~CERTOPT_X_FWD; |
1332 | else if (strcasecmp(opt, "permit-x11-forwarding") == 0) | 1569 | else if (strcasecmp(opt, "permit-x11-forwarding") == 0) |
1333 | constraint_flags |= CONSTRAINT_X_FWD; | 1570 | certflags_flags |= CERTOPT_X_FWD; |
1334 | else if (strcasecmp(opt, "no-agent-forwarding") == 0) | 1571 | else if (strcasecmp(opt, "no-agent-forwarding") == 0) |
1335 | constraint_flags &= ~CONSTRAINT_AGENT_FWD; | 1572 | certflags_flags &= ~CERTOPT_AGENT_FWD; |
1336 | else if (strcasecmp(opt, "permit-agent-forwarding") == 0) | 1573 | else if (strcasecmp(opt, "permit-agent-forwarding") == 0) |
1337 | constraint_flags |= CONSTRAINT_AGENT_FWD; | 1574 | certflags_flags |= CERTOPT_AGENT_FWD; |
1338 | else if (strcasecmp(opt, "no-port-forwarding") == 0) | 1575 | else if (strcasecmp(opt, "no-port-forwarding") == 0) |
1339 | constraint_flags &= ~CONSTRAINT_PORT_FWD; | 1576 | certflags_flags &= ~CERTOPT_PORT_FWD; |
1340 | else if (strcasecmp(opt, "permit-port-forwarding") == 0) | 1577 | else if (strcasecmp(opt, "permit-port-forwarding") == 0) |
1341 | constraint_flags |= CONSTRAINT_PORT_FWD; | 1578 | certflags_flags |= CERTOPT_PORT_FWD; |
1342 | else if (strcasecmp(opt, "no-pty") == 0) | 1579 | else if (strcasecmp(opt, "no-pty") == 0) |
1343 | constraint_flags &= ~CONSTRAINT_PTY; | 1580 | certflags_flags &= ~CERTOPT_PTY; |
1344 | else if (strcasecmp(opt, "permit-pty") == 0) | 1581 | else if (strcasecmp(opt, "permit-pty") == 0) |
1345 | constraint_flags |= CONSTRAINT_PTY; | 1582 | certflags_flags |= CERTOPT_PTY; |
1346 | else if (strcasecmp(opt, "no-user-rc") == 0) | 1583 | else if (strcasecmp(opt, "no-user-rc") == 0) |
1347 | constraint_flags &= ~CONSTRAINT_USER_RC; | 1584 | certflags_flags &= ~CERTOPT_USER_RC; |
1348 | else if (strcasecmp(opt, "permit-user-rc") == 0) | 1585 | else if (strcasecmp(opt, "permit-user-rc") == 0) |
1349 | constraint_flags |= CONSTRAINT_USER_RC; | 1586 | certflags_flags |= CERTOPT_USER_RC; |
1350 | else if (strncasecmp(opt, "force-command=", 14) == 0) { | 1587 | else if (strncasecmp(opt, "force-command=", 14) == 0) { |
1351 | val = opt + 14; | 1588 | val = opt + 14; |
1352 | if (*val == '\0') | 1589 | if (*val == '\0') |
1353 | fatal("Empty force-command constraint"); | 1590 | fatal("Empty force-command option"); |
1354 | if (constraint_command != NULL) | 1591 | if (certflags_command != NULL) |
1355 | fatal("force-command already specified"); | 1592 | fatal("force-command already specified"); |
1356 | constraint_command = xstrdup(val); | 1593 | certflags_command = xstrdup(val); |
1357 | } else if (strncasecmp(opt, "source-address=", 15) == 0) { | 1594 | } else if (strncasecmp(opt, "source-address=", 15) == 0) { |
1358 | val = opt + 15; | 1595 | val = opt + 15; |
1359 | if (*val == '\0') | 1596 | if (*val == '\0') |
1360 | fatal("Empty source-address constraint"); | 1597 | fatal("Empty source-address option"); |
1361 | if (constraint_src_addr != NULL) | 1598 | if (certflags_src_addr != NULL) |
1362 | fatal("source-address already specified"); | 1599 | fatal("source-address already specified"); |
1363 | if (addr_match_cidr_list(NULL, val) != 0) | 1600 | if (addr_match_cidr_list(NULL, val) != 0) |
1364 | fatal("Invalid source-address list"); | 1601 | fatal("Invalid source-address list"); |
1365 | constraint_src_addr = xstrdup(val); | 1602 | certflags_src_addr = xstrdup(val); |
1366 | } else | 1603 | } else |
1367 | fatal("Unsupported certificate constraint \"%s\"", opt); | 1604 | fatal("Unsupported certificate option \"%s\"", opt); |
1605 | } | ||
1606 | |||
1607 | static void | ||
1608 | show_options(const Buffer *optbuf, int v00, int in_critical) | ||
1609 | { | ||
1610 | u_char *name, *data; | ||
1611 | u_int dlen; | ||
1612 | Buffer options, option; | ||
1613 | |||
1614 | buffer_init(&options); | ||
1615 | buffer_append(&options, buffer_ptr(optbuf), buffer_len(optbuf)); | ||
1616 | |||
1617 | buffer_init(&option); | ||
1618 | while (buffer_len(&options) != 0) { | ||
1619 | name = buffer_get_string(&options, NULL); | ||
1620 | data = buffer_get_string_ptr(&options, &dlen); | ||
1621 | buffer_append(&option, data, dlen); | ||
1622 | printf(" %s", name); | ||
1623 | if ((v00 || !in_critical) && | ||
1624 | (strcmp(name, "permit-X11-forwarding") == 0 || | ||
1625 | strcmp(name, "permit-agent-forwarding") == 0 || | ||
1626 | strcmp(name, "permit-port-forwarding") == 0 || | ||
1627 | strcmp(name, "permit-pty") == 0 || | ||
1628 | strcmp(name, "permit-user-rc") == 0)) | ||
1629 | printf("\n"); | ||
1630 | else if ((v00 || in_critical) && | ||
1631 | (strcmp(name, "force-command") == 0 || | ||
1632 | strcmp(name, "source-address") == 0)) { | ||
1633 | data = buffer_get_string(&option, NULL); | ||
1634 | printf(" %s\n", data); | ||
1635 | xfree(data); | ||
1636 | } else { | ||
1637 | printf(" UNKNOWN OPTION (len %u)\n", | ||
1638 | buffer_len(&option)); | ||
1639 | buffer_clear(&option); | ||
1640 | } | ||
1641 | xfree(name); | ||
1642 | if (buffer_len(&option) != 0) | ||
1643 | fatal("Option corrupt: extra data at end"); | ||
1644 | } | ||
1645 | buffer_free(&option); | ||
1646 | buffer_free(&options); | ||
1368 | } | 1647 | } |
1369 | 1648 | ||
1370 | static void | 1649 | static void |
@@ -1373,31 +1652,31 @@ do_show_cert(struct passwd *pw) | |||
1373 | Key *key; | 1652 | Key *key; |
1374 | struct stat st; | 1653 | struct stat st; |
1375 | char *key_fp, *ca_fp; | 1654 | char *key_fp, *ca_fp; |
1376 | Buffer constraints, constraint; | 1655 | u_int i, v00; |
1377 | u_char *name, *data; | ||
1378 | u_int i, dlen; | ||
1379 | 1656 | ||
1380 | if (!have_identity) | 1657 | if (!have_identity) |
1381 | ask_filename(pw, "Enter file in which the key is"); | 1658 | ask_filename(pw, "Enter file in which the key is"); |
1382 | if (stat(identity_file, &st) < 0) { | 1659 | if (stat(identity_file, &st) < 0) |
1383 | perror(identity_file); | 1660 | fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); |
1384 | exit(1); | ||
1385 | } | ||
1386 | if ((key = key_load_public(identity_file, NULL)) == NULL) | 1661 | if ((key = key_load_public(identity_file, NULL)) == NULL) |
1387 | fatal("%s is not a public key", identity_file); | 1662 | fatal("%s is not a public key", identity_file); |
1388 | if (!key_is_cert(key)) | 1663 | if (!key_is_cert(key)) |
1389 | fatal("%s is not a certificate", identity_file); | 1664 | fatal("%s is not a certificate", identity_file); |
1390 | 1665 | v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; | |
1666 | |||
1391 | key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | 1667 | key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); |
1392 | ca_fp = key_fingerprint(key->cert->signature_key, | 1668 | ca_fp = key_fingerprint(key->cert->signature_key, |
1393 | SSH_FP_MD5, SSH_FP_HEX); | 1669 | SSH_FP_MD5, SSH_FP_HEX); |
1394 | 1670 | ||
1395 | printf("%s:\n", identity_file); | 1671 | printf("%s:\n", identity_file); |
1396 | printf(" %s %s certificate %s\n", key_type(key), | 1672 | printf(" Type: %s %s certificate\n", key_ssh_name(key), |
1397 | key_cert_type(key), key_fp); | 1673 | key_cert_type(key)); |
1398 | printf(" Signed by %s CA %s\n", | 1674 | printf(" Public key: %s %s\n", key_type(key), key_fp); |
1675 | printf(" Signing CA: %s %s\n", | ||
1399 | key_type(key->cert->signature_key), ca_fp); | 1676 | key_type(key->cert->signature_key), ca_fp); |
1400 | printf(" Key ID \"%s\"\n", key->cert->key_id); | 1677 | printf(" Key ID: \"%s\"\n", key->cert->key_id); |
1678 | if (!v00) | ||
1679 | printf(" Serial: %llu\n", key->cert->serial); | ||
1401 | printf(" Valid: %s\n", | 1680 | printf(" Valid: %s\n", |
1402 | fmt_validity(key->cert->valid_after, key->cert->valid_before)); | 1681 | fmt_validity(key->cert->valid_after, key->cert->valid_before)); |
1403 | printf(" Principals: "); | 1682 | printf(" Principals: "); |
@@ -1409,45 +1688,22 @@ do_show_cert(struct passwd *pw) | |||
1409 | key->cert->principals[i]); | 1688 | key->cert->principals[i]); |
1410 | printf("\n"); | 1689 | printf("\n"); |
1411 | } | 1690 | } |
1412 | printf(" Constraints: "); | 1691 | printf(" Critical Options: "); |
1413 | if (buffer_len(&key->cert->constraints) == 0) | 1692 | if (buffer_len(&key->cert->critical) == 0) |
1414 | printf("(none)\n"); | 1693 | printf("(none)\n"); |
1415 | else { | 1694 | else { |
1416 | printf("\n"); | 1695 | printf("\n"); |
1417 | buffer_init(&constraints); | 1696 | show_options(&key->cert->critical, v00, 1); |
1418 | buffer_append(&constraints, | 1697 | } |
1419 | buffer_ptr(&key->cert->constraints), | 1698 | if (!v00) { |
1420 | buffer_len(&key->cert->constraints)); | 1699 | printf(" Extensions: "); |
1421 | buffer_init(&constraint); | 1700 | if (buffer_len(&key->cert->extensions) == 0) |
1422 | while (buffer_len(&constraints) != 0) { | 1701 | printf("(none)\n"); |
1423 | name = buffer_get_string(&constraints, NULL); | 1702 | else { |
1424 | data = buffer_get_string_ptr(&constraints, &dlen); | 1703 | printf("\n"); |
1425 | buffer_append(&constraint, data, dlen); | 1704 | show_options(&key->cert->extensions, v00, 0); |
1426 | printf(" %s", name); | ||
1427 | if (strcmp(name, "permit-X11-forwarding") == 0 || | ||
1428 | strcmp(name, "permit-agent-forwarding") == 0 || | ||
1429 | strcmp(name, "permit-port-forwarding") == 0 || | ||
1430 | strcmp(name, "permit-pty") == 0 || | ||
1431 | strcmp(name, "permit-user-rc") == 0) | ||
1432 | printf("\n"); | ||
1433 | else if (strcmp(name, "force-command") == 0 || | ||
1434 | strcmp(name, "source-address") == 0) { | ||
1435 | data = buffer_get_string(&constraint, NULL); | ||
1436 | printf(" %s\n", data); | ||
1437 | xfree(data); | ||
1438 | } else { | ||
1439 | printf(" UNKNOWN CONSTRAINT (len %u)\n", | ||
1440 | buffer_len(&constraint)); | ||
1441 | buffer_clear(&constraint); | ||
1442 | } | ||
1443 | xfree(name); | ||
1444 | if (buffer_len(&constraint) != 0) | ||
1445 | fatal("Constraint corrupt: extra data at end"); | ||
1446 | } | 1705 | } |
1447 | buffer_free(&constraint); | ||
1448 | buffer_free(&constraints); | ||
1449 | } | 1706 | } |
1450 | |||
1451 | exit(0); | 1707 | exit(0); |
1452 | } | 1708 | } |
1453 | 1709 | ||
@@ -1464,7 +1720,7 @@ usage(void) | |||
1464 | #ifdef ENABLE_PKCS11 | 1720 | #ifdef ENABLE_PKCS11 |
1465 | fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); | 1721 | fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); |
1466 | #endif | 1722 | #endif |
1467 | fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); | 1723 | fprintf(stderr, " -e Export OpenSSH to foreign format key file.\n"); |
1468 | fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); | 1724 | fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); |
1469 | fprintf(stderr, " -f filename Filename of the key file.\n"); | 1725 | fprintf(stderr, " -f filename Filename of the key file.\n"); |
1470 | fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); | 1726 | fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); |
@@ -1472,26 +1728,28 @@ usage(void) | |||
1472 | fprintf(stderr, " -H Hash names in known_hosts file.\n"); | 1728 | fprintf(stderr, " -H Hash names in known_hosts file.\n"); |
1473 | fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n"); | 1729 | fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n"); |
1474 | fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); | 1730 | fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); |
1475 | fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); | 1731 | fprintf(stderr, " -i Import foreign format to OpenSSH key file.\n"); |
1476 | fprintf(stderr, " -L Print the contents of a certificate.\n"); | 1732 | fprintf(stderr, " -L Print the contents of a certificate.\n"); |
1477 | fprintf(stderr, " -l Show fingerprint of key file.\n"); | 1733 | fprintf(stderr, " -l Show fingerprint of key file.\n"); |
1478 | fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); | 1734 | fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); |
1479 | fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); | 1735 | fprintf(stderr, " -m key_fmt Conversion format for -e/-i (PEM|PKCS8|RFC4716).\n"); |
1480 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); | 1736 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); |
1481 | fprintf(stderr, " -O cnstr Specify a certificate constraint.\n"); | 1737 | fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); |
1738 | fprintf(stderr, " -O option Specify a certificate option.\n"); | ||
1482 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); | 1739 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); |
1483 | fprintf(stderr, " -p Change passphrase of private key file.\n"); | 1740 | fprintf(stderr, " -p Change passphrase of private key file.\n"); |
1484 | fprintf(stderr, " -q Quiet.\n"); | 1741 | fprintf(stderr, " -q Quiet.\n"); |
1485 | fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); | 1742 | fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); |
1486 | fprintf(stderr, " -r hostname Print DNS resource record.\n"); | 1743 | fprintf(stderr, " -r hostname Print DNS resource record.\n"); |
1487 | fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); | ||
1488 | fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); | 1744 | fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); |
1745 | fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); | ||
1489 | fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); | 1746 | fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); |
1490 | fprintf(stderr, " -t type Specify type of key to create.\n"); | 1747 | fprintf(stderr, " -t type Specify type of key to create.\n"); |
1491 | fprintf(stderr, " -V from:to Specify certificate validity interval.\n"); | 1748 | fprintf(stderr, " -V from:to Specify certificate validity interval.\n"); |
1492 | fprintf(stderr, " -v Verbose.\n"); | 1749 | fprintf(stderr, " -v Verbose.\n"); |
1493 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); | 1750 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); |
1494 | fprintf(stderr, " -y Read private key file and print public key.\n"); | 1751 | fprintf(stderr, " -y Read private key file and print public key.\n"); |
1752 | fprintf(stderr, " -z serial Specify a serial number.\n"); | ||
1495 | 1753 | ||
1496 | exit(1); | 1754 | exit(1); |
1497 | } | 1755 | } |
@@ -1503,12 +1761,12 @@ int | |||
1503 | main(int argc, char **argv) | 1761 | main(int argc, char **argv) |
1504 | { | 1762 | { |
1505 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; | 1763 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; |
1506 | char out_file[MAXPATHLEN], *pkcs11provider = NULL; | 1764 | char out_file[MAXPATHLEN], *rr_hostname = NULL; |
1507 | char *rr_hostname = NULL; | ||
1508 | Key *private, *public; | 1765 | Key *private, *public; |
1509 | struct passwd *pw; | 1766 | struct passwd *pw; |
1510 | struct stat st; | 1767 | struct stat st; |
1511 | int opt, type, fd; | 1768 | int opt, type, fd; |
1769 | u_int maxbits; | ||
1512 | u_int32_t memory = 0, generator_wanted = 0, trials = 100; | 1770 | u_int32_t memory = 0, generator_wanted = 0, trials = 100; |
1513 | int do_gen_candidates = 0, do_screen_candidates = 0; | 1771 | int do_gen_candidates = 0, do_screen_candidates = 0; |
1514 | BIGNUM *start = NULL; | 1772 | BIGNUM *start = NULL; |
@@ -1540,8 +1798,8 @@ main(int argc, char **argv) | |||
1540 | exit(1); | 1798 | exit(1); |
1541 | } | 1799 | } |
1542 | 1800 | ||
1543 | while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:" | 1801 | while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:" |
1544 | "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { | 1802 | "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) { |
1545 | switch (opt) { | 1803 | switch (opt) { |
1546 | case 'b': | 1804 | case 'b': |
1547 | bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); | 1805 | bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); |
@@ -1572,6 +1830,21 @@ main(int argc, char **argv) | |||
1572 | case 'B': | 1830 | case 'B': |
1573 | print_bubblebabble = 1; | 1831 | print_bubblebabble = 1; |
1574 | break; | 1832 | break; |
1833 | case 'm': | ||
1834 | if (strcasecmp(optarg, "RFC4716") == 0 || | ||
1835 | strcasecmp(optarg, "ssh2") == 0) { | ||
1836 | convert_format = FMT_RFC4716; | ||
1837 | break; | ||
1838 | } | ||
1839 | if (strcasecmp(optarg, "PKCS8") == 0) { | ||
1840 | convert_format = FMT_PKCS8; | ||
1841 | break; | ||
1842 | } | ||
1843 | if (strcasecmp(optarg, "PEM") == 0) { | ||
1844 | convert_format = FMT_PEM; | ||
1845 | break; | ||
1846 | } | ||
1847 | fatal("Unsupported conversion format \"%s\"", optarg); | ||
1575 | case 'n': | 1848 | case 'n': |
1576 | cert_principals = optarg; | 1849 | cert_principals = optarg; |
1577 | break; | 1850 | break; |
@@ -1597,7 +1870,7 @@ main(int argc, char **argv) | |||
1597 | identity_new_passphrase = optarg; | 1870 | identity_new_passphrase = optarg; |
1598 | break; | 1871 | break; |
1599 | case 'O': | 1872 | case 'O': |
1600 | add_cert_constraint(optarg); | 1873 | add_cert_option(optarg); |
1601 | break; | 1874 | break; |
1602 | case 'C': | 1875 | case 'C': |
1603 | identity_comment = optarg; | 1876 | identity_comment = optarg; |
@@ -1608,16 +1881,16 @@ main(int argc, char **argv) | |||
1608 | case 'e': | 1881 | case 'e': |
1609 | case 'x': | 1882 | case 'x': |
1610 | /* export key */ | 1883 | /* export key */ |
1611 | convert_to_ssh2 = 1; | 1884 | convert_to = 1; |
1612 | break; | 1885 | break; |
1613 | case 'h': | 1886 | case 'h': |
1614 | cert_key_type = SSH2_CERT_TYPE_HOST; | 1887 | cert_key_type = SSH2_CERT_TYPE_HOST; |
1615 | constraint_flags = 0; | 1888 | certflags_flags = 0; |
1616 | break; | 1889 | break; |
1617 | case 'i': | 1890 | case 'i': |
1618 | case 'X': | 1891 | case 'X': |
1619 | /* import key */ | 1892 | /* import key */ |
1620 | convert_from_ssh2 = 1; | 1893 | convert_from = 1; |
1621 | break; | 1894 | break; |
1622 | case 'y': | 1895 | case 'y': |
1623 | print_public = 1; | 1896 | print_public = 1; |
@@ -1661,9 +1934,8 @@ main(int argc, char **argv) | |||
1661 | break; | 1934 | break; |
1662 | case 'M': | 1935 | case 'M': |
1663 | memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); | 1936 | memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); |
1664 | if (errstr) { | 1937 | if (errstr) |
1665 | fatal("Memory limit is %s: %s", errstr, optarg); | 1938 | fatal("Memory limit is %s: %s", errstr, optarg); |
1666 | } | ||
1667 | break; | 1939 | break; |
1668 | case 'G': | 1940 | case 'G': |
1669 | do_gen_candidates = 1; | 1941 | do_gen_candidates = 1; |
@@ -1685,6 +1957,11 @@ main(int argc, char **argv) | |||
1685 | case 'V': | 1957 | case 'V': |
1686 | parse_cert_times(optarg); | 1958 | parse_cert_times(optarg); |
1687 | break; | 1959 | break; |
1960 | case 'z': | ||
1961 | cert_serial = strtonum(optarg, 0, LLONG_MAX, &errstr); | ||
1962 | if (errstr) | ||
1963 | fatal("Invalid serial number: %s", errstr); | ||
1964 | break; | ||
1688 | case '?': | 1965 | case '?': |
1689 | default: | 1966 | default: |
1690 | usage(); | 1967 | usage(); |
@@ -1729,10 +2006,10 @@ main(int argc, char **argv) | |||
1729 | do_change_passphrase(pw); | 2006 | do_change_passphrase(pw); |
1730 | if (change_comment) | 2007 | if (change_comment) |
1731 | do_change_comment(pw); | 2008 | do_change_comment(pw); |
1732 | if (convert_to_ssh2) | 2009 | if (convert_to) |
1733 | do_convert_to_ssh2(pw); | 2010 | do_convert_to(pw); |
1734 | if (convert_from_ssh2) | 2011 | if (convert_from) |
1735 | do_convert_from_ssh2(pw); | 2012 | do_convert_from(pw); |
1736 | if (print_public) | 2013 | if (print_public) |
1737 | do_print_public(pw); | 2014 | do_print_public(pw); |
1738 | if (rr_hostname != NULL) { | 2015 | if (rr_hostname != NULL) { |
@@ -1759,7 +2036,7 @@ main(int argc, char **argv) | |||
1759 | } | 2036 | } |
1760 | } | 2037 | } |
1761 | if (pkcs11provider != NULL) | 2038 | if (pkcs11provider != NULL) |
1762 | do_download(pw, pkcs11provider); | 2039 | do_download(pw); |
1763 | 2040 | ||
1764 | if (do_gen_candidates) { | 2041 | if (do_gen_candidates) { |
1765 | FILE *out = fopen(out_file, "w"); | 2042 | FILE *out = fopen(out_file, "w"); |
@@ -1811,6 +2088,12 @@ main(int argc, char **argv) | |||
1811 | } | 2088 | } |
1812 | if (bits == 0) | 2089 | if (bits == 0) |
1813 | bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS; | 2090 | bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS; |
2091 | maxbits = (type == KEY_DSA) ? | ||
2092 | OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; | ||
2093 | if (bits > maxbits) { | ||
2094 | fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); | ||
2095 | exit(1); | ||
2096 | } | ||
1814 | if (type == KEY_DSA && bits != 1024) | 2097 | if (type == KEY_DSA && bits != 1024) |
1815 | fatal("DSA keys must be 1024 bits"); | 2098 | fatal("DSA keys must be 1024 bits"); |
1816 | if (!quiet) | 2099 | if (!quiet) |
@@ -1826,13 +2109,19 @@ main(int argc, char **argv) | |||
1826 | ask_filename(pw, "Enter file in which to save the key"); | 2109 | ask_filename(pw, "Enter file in which to save the key"); |
1827 | 2110 | ||
1828 | /* Create ~/.ssh directory if it doesn't already exist. */ | 2111 | /* Create ~/.ssh directory if it doesn't already exist. */ |
1829 | snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); | 2112 | snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", |
1830 | if (strstr(identity_file, dotsshdir) != NULL && | 2113 | pw->pw_dir, _PATH_SSH_USER_DIR); |
1831 | stat(dotsshdir, &st) < 0) { | 2114 | if (strstr(identity_file, dotsshdir) != NULL) { |
1832 | if (mkdir(dotsshdir, 0700) < 0) | 2115 | if (stat(dotsshdir, &st) < 0) { |
1833 | error("Could not create directory '%s'.", dotsshdir); | 2116 | if (errno != ENOENT) { |
1834 | else if (!quiet) | 2117 | error("Could not stat %s: %s", dotsshdir, |
1835 | printf("Created directory '%s'.\n", dotsshdir); | 2118 | strerror(errno)); |
2119 | } else if (mkdir(dotsshdir, 0700) < 0) { | ||
2120 | error("Could not create directory '%s': %s", | ||
2121 | dotsshdir, strerror(errno)); | ||
2122 | } else if (!quiet) | ||
2123 | printf("Created directory '%s'.\n", dotsshdir); | ||
2124 | } | ||
1836 | } | 2125 | } |
1837 | /* If the file already exists, ask the user to confirm. */ | 2126 | /* If the file already exists, ask the user to confirm. */ |
1838 | if (stat(identity_file, &st) >= 0) { | 2127 | if (stat(identity_file, &st) >= 0) { |