diff options
author | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
commit | efd3d4522636ae029488c2e9730b60c88e257d2e (patch) | |
tree | 31e02ac3f16090ce8c53448677356b2b7f423683 /ssh-keygen.c | |
parent | bbec4db36d464ea1d464a707625125f9fd5c7b5e (diff) | |
parent | d1a87e462e1db89f19cd960588d0c6b287cb5ccc (diff) |
* New upstream release (LP: #535029).
- After a transition period of about 10 years, this release disables SSH
protocol 1 by default. Clients and servers that need to use the
legacy protocol must explicitly enable it in ssh_config / sshd_config
or on the command-line.
- Remove the libsectok/OpenSC-based smartcard code and add support for
PKCS#11 tokens. This support is enabled by default in the Debian
packaging, since it now doesn't involve additional library
dependencies (closes: #231472, LP: #16918).
- Add support for certificate authentication of users and hosts using a
new, minimal OpenSSH certificate format (closes: #482806).
- Added a 'netcat mode' to ssh(1): "ssh -W host:port ...".
- Add the ability to revoke keys in sshd(8) and ssh(1). (For the Debian
package, this overlaps with the key blacklisting facility added in
openssh 1:4.7p1-9, but with different file formats and slightly
different scopes; for the moment, I've roughly merged the two.)
- Various multiplexing improvements, including support for requesting
port-forwardings via the multiplex protocol (closes: #360151).
- Allow setting an explicit umask on the sftp-server(8) commandline to
override whatever default the user has (closes: #496843).
- Many sftp client improvements, including tab-completion, more options,
and recursive transfer support for get/put (LP: #33378). The old
mget/mput commands never worked properly and have been removed
(closes: #270399, #428082).
- Do not prompt for a passphrase if we fail to open a keyfile, and log
the reason why the open failed to debug (closes: #431538).
- Prevent sftp from crashing when given a "-" without a command. Also,
allow whitespace to follow a "-" (closes: #531561).
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 636 |
1 files changed, 543 insertions, 93 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c index da5db9845..dd662c907 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.174 2009/06/22 05:39:28 dtucker Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.184 2010/03/07 22:16:01 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 |
@@ -48,9 +48,10 @@ | |||
48 | #include "match.h" | 48 | #include "match.h" |
49 | #include "hostfile.h" | 49 | #include "hostfile.h" |
50 | #include "dns.h" | 50 | #include "dns.h" |
51 | #include "ssh2.h" | ||
51 | 52 | ||
52 | #ifdef SMARTCARD | 53 | #ifdef ENABLE_PKCS11 |
53 | #include "scard.h" | 54 | #include "ssh-pkcs11.h" |
54 | #endif | 55 | #endif |
55 | 56 | ||
56 | /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ | 57 | /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ |
@@ -81,6 +82,9 @@ int find_host = 0; | |||
81 | /* Flag indicating that we want to delete a host from a known_hosts file */ | 82 | /* Flag indicating that we want to delete a host from a known_hosts file */ |
82 | int delete_host = 0; | 83 | int delete_host = 0; |
83 | 84 | ||
85 | /* Flag indicating that we want to show the contents of a certificate */ | ||
86 | int show_cert = 0; | ||
87 | |||
84 | /* Flag indicating that we just want to see the key fingerprint */ | 88 | /* Flag indicating that we just want to see the key fingerprint */ |
85 | int print_fingerprint = 0; | 89 | int print_fingerprint = 0; |
86 | int print_bubblebabble = 0; | 90 | int print_bubblebabble = 0; |
@@ -98,6 +102,35 @@ char *identity_new_passphrase = NULL; | |||
98 | /* This is set to the new comment if given on the command line. */ | 102 | /* This is set to the new comment if given on the command line. */ |
99 | char *identity_comment = NULL; | 103 | char *identity_comment = NULL; |
100 | 104 | ||
105 | /* Path to CA key when certifying keys. */ | ||
106 | char *ca_key_path = NULL; | ||
107 | |||
108 | /* Key type when certifying */ | ||
109 | u_int cert_key_type = SSH2_CERT_TYPE_USER; | ||
110 | |||
111 | /* "key ID" of signed key */ | ||
112 | char *cert_key_id = NULL; | ||
113 | |||
114 | /* Comma-separated list of principal names for certifying keys */ | ||
115 | char *cert_principals = NULL; | ||
116 | |||
117 | /* Validity period for certificates */ | ||
118 | u_int64_t cert_valid_from = 0; | ||
119 | u_int64_t cert_valid_to = ~0ULL; | ||
120 | |||
121 | /* Certificate constraints */ | ||
122 | #define CONSTRAINT_X_FWD (1) | ||
123 | #define CONSTRAINT_AGENT_FWD (1<<1) | ||
124 | #define CONSTRAINT_PORT_FWD (1<<2) | ||
125 | #define CONSTRAINT_PTY (1<<3) | ||
126 | #define CONSTRAINT_USER_RC (1<<4) | ||
127 | #define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \ | ||
128 | CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \ | ||
129 | CONSTRAINT_USER_RC) | ||
130 | u_int32_t constraint_flags = CONSTRAINT_DEFAULT; | ||
131 | char *constraint_command = NULL; | ||
132 | char *constraint_src_addr = NULL; | ||
133 | |||
101 | /* Dump public key file in format used by real and the original SSH 2 */ | 134 | /* Dump public key file in format used by real and the original SSH 2 */ |
102 | int convert_to_ssh2 = 0; | 135 | int convert_to_ssh2 = 0; |
103 | int convert_from_ssh2 = 0; | 136 | int convert_from_ssh2 = 0; |
@@ -181,6 +214,7 @@ do_convert_to_ssh2(struct passwd *pw) | |||
181 | Key *k; | 214 | Key *k; |
182 | u_int len; | 215 | u_int len; |
183 | u_char *blob; | 216 | u_char *blob; |
217 | char comment[61]; | ||
184 | struct stat st; | 218 | struct stat st; |
185 | 219 | ||
186 | if (!have_identity) | 220 | if (!have_identity) |
@@ -203,11 +237,14 @@ do_convert_to_ssh2(struct passwd *pw) | |||
203 | fprintf(stderr, "key_to_blob failed\n"); | 237 | fprintf(stderr, "key_to_blob failed\n"); |
204 | exit(1); | 238 | exit(1); |
205 | } | 239 | } |
206 | fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); | 240 | /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ |
207 | fprintf(stdout, | 241 | snprintf(comment, sizeof(comment), |
208 | "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n", | 242 | "%u-bit %s, converted by %s@%s from OpenSSH", |
209 | key_size(k), key_type(k), | 243 | key_size(k), key_type(k), |
210 | pw->pw_name, hostname); | 244 | pw->pw_name, hostname); |
245 | |||
246 | fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); | ||
247 | fprintf(stdout, "Comment: \"%s\"\n", comment); | ||
211 | dump_base64(stdout, blob, len); | 248 | dump_base64(stdout, blob, len); |
212 | fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); | 249 | fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); |
213 | key_free(k); | 250 | key_free(k); |
@@ -455,51 +492,29 @@ do_print_public(struct passwd *pw) | |||
455 | exit(0); | 492 | exit(0); |
456 | } | 493 | } |
457 | 494 | ||
458 | #ifdef SMARTCARD | ||
459 | static void | 495 | static void |
460 | do_upload(struct passwd *pw, const char *sc_reader_id) | 496 | do_download(struct passwd *pw, char *pkcs11provider) |
461 | { | ||
462 | Key *prv = NULL; | ||
463 | struct stat st; | ||
464 | int ret; | ||
465 | |||
466 | if (!have_identity) | ||
467 | ask_filename(pw, "Enter file in which the key is"); | ||
468 | if (stat(identity_file, &st) < 0) { | ||
469 | perror(identity_file); | ||
470 | exit(1); | ||
471 | } | ||
472 | prv = load_identity(identity_file); | ||
473 | if (prv == NULL) { | ||
474 | error("load failed"); | ||
475 | exit(1); | ||
476 | } | ||
477 | ret = sc_put_key(prv, sc_reader_id); | ||
478 | key_free(prv); | ||
479 | if (ret < 0) | ||
480 | exit(1); | ||
481 | logit("loading key done"); | ||
482 | exit(0); | ||
483 | } | ||
484 | |||
485 | static void | ||
486 | do_download(struct passwd *pw, const char *sc_reader_id) | ||
487 | { | 497 | { |
498 | #ifdef ENABLE_PKCS11 | ||
488 | Key **keys = NULL; | 499 | Key **keys = NULL; |
489 | int i; | 500 | int i, nkeys; |
490 | 501 | ||
491 | keys = sc_get_keys(sc_reader_id, NULL); | 502 | pkcs11_init(0); |
492 | if (keys == NULL) | 503 | nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); |
493 | fatal("cannot read public key from smartcard"); | 504 | if (nkeys <= 0) |
494 | for (i = 0; keys[i]; i++) { | 505 | fatal("cannot read public key from pkcs11"); |
506 | for (i = 0; i < nkeys; i++) { | ||
495 | key_write(keys[i], stdout); | 507 | key_write(keys[i], stdout); |
496 | key_free(keys[i]); | 508 | key_free(keys[i]); |
497 | fprintf(stdout, "\n"); | 509 | fprintf(stdout, "\n"); |
498 | } | 510 | } |
499 | xfree(keys); | 511 | xfree(keys); |
512 | pkcs11_terminate(); | ||
500 | exit(0); | 513 | exit(0); |
514 | #else | ||
515 | fatal("no pkcs11 support"); | ||
516 | #endif /* ENABLE_PKCS11 */ | ||
501 | } | 517 | } |
502 | #endif /* SMARTCARD */ | ||
503 | 518 | ||
504 | static void | 519 | static void |
505 | do_fingerprint(struct passwd *pw) | 520 | do_fingerprint(struct passwd *pw) |
@@ -524,7 +539,7 @@ do_fingerprint(struct passwd *pw) | |||
524 | public = key_load_public(identity_file, &comment); | 539 | public = key_load_public(identity_file, &comment); |
525 | if (public != NULL) { | 540 | if (public != NULL) { |
526 | fp = key_fingerprint(public, fptype, rep); | 541 | fp = key_fingerprint(public, fptype, rep); |
527 | ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); | 542 | ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); |
528 | printf("%u %s %s (%s)\n", key_size(public), fp, comment, | 543 | printf("%u %s %s (%s)\n", key_size(public), fp, comment, |
529 | key_type(public)); | 544 | key_type(public)); |
530 | if (log_level >= SYSLOG_LEVEL_VERBOSE) | 545 | if (log_level >= SYSLOG_LEVEL_VERBOSE) |
@@ -589,7 +604,7 @@ do_fingerprint(struct passwd *pw) | |||
589 | } | 604 | } |
590 | comment = *cp ? cp : comment; | 605 | comment = *cp ? cp : comment; |
591 | fp = key_fingerprint(public, fptype, rep); | 606 | fp = key_fingerprint(public, fptype, rep); |
592 | ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); | 607 | ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); |
593 | printf("%u %s %s (%s)\n", key_size(public), fp, | 608 | printf("%u %s %s (%s)\n", key_size(public), fp, |
594 | comment ? comment : "no comment", key_type(public)); | 609 | comment ? comment : "no comment", key_type(public)); |
595 | if (log_level >= SYSLOG_LEVEL_VERBOSE) | 610 | if (log_level >= SYSLOG_LEVEL_VERBOSE) |
@@ -609,7 +624,7 @@ do_fingerprint(struct passwd *pw) | |||
609 | } | 624 | } |
610 | 625 | ||
611 | static void | 626 | static void |
612 | print_host(FILE *f, const char *name, Key *public, int hash) | 627 | printhost(FILE *f, const char *name, Key *public, int ca, int hash) |
613 | { | 628 | { |
614 | if (print_fingerprint) { | 629 | if (print_fingerprint) { |
615 | enum fp_rep rep; | 630 | enum fp_rep rep; |
@@ -619,7 +634,7 @@ print_host(FILE *f, const char *name, Key *public, int hash) | |||
619 | fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; | 634 | fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; |
620 | rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; | 635 | rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; |
621 | fp = key_fingerprint(public, fptype, rep); | 636 | fp = key_fingerprint(public, fptype, rep); |
622 | ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); | 637 | ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); |
623 | printf("%u %s %s (%s)\n", key_size(public), fp, name, | 638 | printf("%u %s %s (%s)\n", key_size(public), fp, name, |
624 | key_type(public)); | 639 | key_type(public)); |
625 | if (log_level >= SYSLOG_LEVEL_VERBOSE) | 640 | if (log_level >= SYSLOG_LEVEL_VERBOSE) |
@@ -629,7 +644,7 @@ print_host(FILE *f, const char *name, Key *public, int hash) | |||
629 | } else { | 644 | } else { |
630 | if (hash && (name = host_hash(name, NULL, 0)) == NULL) | 645 | if (hash && (name = host_hash(name, NULL, 0)) == NULL) |
631 | fatal("hash_host failed"); | 646 | fatal("hash_host failed"); |
632 | fprintf(f, "%s ", name); | 647 | fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name); |
633 | if (!key_write(public, f)) | 648 | if (!key_write(public, f)) |
634 | fatal("key_write failed"); | 649 | fatal("key_write failed"); |
635 | fprintf(f, "\n"); | 650 | fprintf(f, "\n"); |
@@ -640,10 +655,11 @@ static void | |||
640 | do_known_hosts(struct passwd *pw, const char *name) | 655 | do_known_hosts(struct passwd *pw, const char *name) |
641 | { | 656 | { |
642 | FILE *in, *out = stdout; | 657 | FILE *in, *out = stdout; |
643 | Key *public; | 658 | Key *pub; |
644 | char *cp, *cp2, *kp, *kp2; | 659 | char *cp, *cp2, *kp, *kp2; |
645 | char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; | 660 | char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; |
646 | int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; | 661 | int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; |
662 | int ca; | ||
647 | 663 | ||
648 | if (!have_identity) { | 664 | if (!have_identity) { |
649 | cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); | 665 | cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); |
@@ -699,9 +715,19 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
699 | fprintf(out, "%s\n", cp); | 715 | fprintf(out, "%s\n", cp); |
700 | continue; | 716 | continue; |
701 | } | 717 | } |
718 | /* Check whether this is a CA key */ | ||
719 | if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && | ||
720 | (cp[sizeof(CA_MARKER) - 1] == ' ' || | ||
721 | cp[sizeof(CA_MARKER) - 1] == '\t')) { | ||
722 | ca = 1; | ||
723 | cp += sizeof(CA_MARKER); | ||
724 | } else | ||
725 | ca = 0; | ||
726 | |||
702 | /* Find the end of the host name portion. */ | 727 | /* Find the end of the host name portion. */ |
703 | for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) | 728 | for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) |
704 | ; | 729 | ; |
730 | |||
705 | if (*kp == '\0' || *(kp + 1) == '\0') { | 731 | if (*kp == '\0' || *(kp + 1) == '\0') { |
706 | error("line %d missing key: %.40s...", | 732 | error("line %d missing key: %.40s...", |
707 | num, line); | 733 | num, line); |
@@ -711,15 +737,15 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
711 | *kp++ = '\0'; | 737 | *kp++ = '\0'; |
712 | kp2 = kp; | 738 | kp2 = kp; |
713 | 739 | ||
714 | public = key_new(KEY_RSA1); | 740 | pub = key_new(KEY_RSA1); |
715 | if (key_read(public, &kp) != 1) { | 741 | if (key_read(pub, &kp) != 1) { |
716 | kp = kp2; | 742 | kp = kp2; |
717 | key_free(public); | 743 | key_free(pub); |
718 | public = key_new(KEY_UNSPEC); | 744 | pub = key_new(KEY_UNSPEC); |
719 | if (key_read(public, &kp) != 1) { | 745 | if (key_read(pub, &kp) != 1) { |
720 | error("line %d invalid key: %.40s...", | 746 | error("line %d invalid key: %.40s...", |
721 | num, line); | 747 | num, line); |
722 | key_free(public); | 748 | key_free(pub); |
723 | invalid = 1; | 749 | invalid = 1; |
724 | continue; | 750 | continue; |
725 | } | 751 | } |
@@ -737,43 +763,52 @@ do_known_hosts(struct passwd *pw, const char *name) | |||
737 | c = (strcmp(cp2, cp) == 0); | 763 | c = (strcmp(cp2, cp) == 0); |
738 | if (find_host && c) { | 764 | if (find_host && c) { |
739 | printf("# Host %s found: " | 765 | printf("# Host %s found: " |
740 | "line %d type %s\n", name, | 766 | "line %d type %s%s\n", name, |
741 | num, key_type(public)); | 767 | num, key_type(pub), |
742 | print_host(out, cp, public, 0); | 768 | ca ? " (CA key)" : ""); |
769 | printhost(out, cp, pub, ca, 0); | ||
743 | } | 770 | } |
744 | if (delete_host && !c) | 771 | if (delete_host && !c && !ca) |
745 | print_host(out, cp, public, 0); | 772 | printhost(out, cp, pub, ca, 0); |
746 | } else if (hash_hosts) | 773 | } else if (hash_hosts) |
747 | print_host(out, cp, public, 0); | 774 | printhost(out, cp, pub, ca, 0); |
748 | } else { | 775 | } else { |
749 | if (find_host || delete_host) { | 776 | if (find_host || delete_host) { |
750 | c = (match_hostname(name, cp, | 777 | c = (match_hostname(name, cp, |
751 | strlen(cp)) == 1); | 778 | strlen(cp)) == 1); |
752 | if (find_host && c) { | 779 | if (find_host && c) { |
753 | printf("# Host %s found: " | 780 | printf("# Host %s found: " |
754 | "line %d type %s\n", name, | 781 | "line %d type %s%s\n", name, |
755 | num, key_type(public)); | 782 | num, key_type(pub), |
756 | print_host(out, name, public, | 783 | ca ? " (CA key)" : ""); |
757 | hash_hosts); | 784 | printhost(out, name, pub, |
785 | ca, hash_hosts && !ca); | ||
758 | } | 786 | } |
759 | if (delete_host && !c) | 787 | if (delete_host && !c && !ca) |
760 | print_host(out, cp, public, 0); | 788 | printhost(out, cp, pub, ca, 0); |
761 | } else if (hash_hosts) { | 789 | } else if (hash_hosts) { |
762 | for (cp2 = strsep(&cp, ","); | 790 | for (cp2 = strsep(&cp, ","); |
763 | cp2 != NULL && *cp2 != '\0'; | 791 | cp2 != NULL && *cp2 != '\0'; |
764 | cp2 = strsep(&cp, ",")) { | 792 | cp2 = strsep(&cp, ",")) { |
765 | if (strcspn(cp2, "*?!") != strlen(cp2)) | 793 | if (ca) { |
794 | fprintf(stderr, "Warning: " | ||
795 | "ignoring CA key for host: " | ||
796 | "%.64s\n", cp2); | ||
797 | printhost(out, cp2, pub, ca, 0); | ||
798 | } else if (strcspn(cp2, "*?!") != | ||
799 | strlen(cp2)) { | ||
766 | fprintf(stderr, "Warning: " | 800 | fprintf(stderr, "Warning: " |
767 | "ignoring host name with " | 801 | "ignoring host name with " |
768 | "metacharacters: %.64s\n", | 802 | "metacharacters: %.64s\n", |
769 | cp2); | 803 | cp2); |
770 | else | 804 | printhost(out, cp2, pub, ca, 0); |
771 | print_host(out, cp2, public, 1); | 805 | } else |
806 | printhost(out, cp2, pub, ca, 1); | ||
772 | } | 807 | } |
773 | has_unhashed = 1; | 808 | has_unhashed = 1; |
774 | } | 809 | } |
775 | } | 810 | } |
776 | key_free(public); | 811 | key_free(pub); |
777 | } | 812 | } |
778 | fclose(in); | 813 | fclose(in); |
779 | 814 | ||
@@ -1030,6 +1065,391 @@ do_change_comment(struct passwd *pw) | |||
1030 | exit(0); | 1065 | exit(0); |
1031 | } | 1066 | } |
1032 | 1067 | ||
1068 | static const char * | ||
1069 | fmt_validity(u_int64_t valid_from, u_int64_t valid_to) | ||
1070 | { | ||
1071 | char from[32], to[32]; | ||
1072 | static char ret[64]; | ||
1073 | time_t tt; | ||
1074 | struct tm *tm; | ||
1075 | |||
1076 | *from = *to = '\0'; | ||
1077 | if (valid_from == 0 && valid_to == 0xffffffffffffffffULL) | ||
1078 | return "forever"; | ||
1079 | |||
1080 | if (valid_from != 0) { | ||
1081 | /* XXX revisit INT_MAX in 2038 :) */ | ||
1082 | tt = valid_from > INT_MAX ? INT_MAX : valid_from; | ||
1083 | tm = localtime(&tt); | ||
1084 | strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); | ||
1085 | } | ||
1086 | if (valid_to != 0xffffffffffffffffULL) { | ||
1087 | /* XXX revisit INT_MAX in 2038 :) */ | ||
1088 | tt = valid_to > INT_MAX ? INT_MAX : valid_to; | ||
1089 | tm = localtime(&tt); | ||
1090 | strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); | ||
1091 | } | ||
1092 | |||
1093 | if (valid_from == 0) { | ||
1094 | snprintf(ret, sizeof(ret), "before %s", to); | ||
1095 | return ret; | ||
1096 | } | ||
1097 | if (valid_to == 0xffffffffffffffffULL) { | ||
1098 | snprintf(ret, sizeof(ret), "after %s", from); | ||
1099 | return ret; | ||
1100 | } | ||
1101 | |||
1102 | snprintf(ret, sizeof(ret), "from %s to %s", from, to); | ||
1103 | return ret; | ||
1104 | } | ||
1105 | |||
1106 | static void | ||
1107 | add_flag_constraint(Buffer *c, const char *name) | ||
1108 | { | ||
1109 | debug3("%s: %s", __func__, name); | ||
1110 | buffer_put_cstring(c, name); | ||
1111 | buffer_put_string(c, NULL, 0); | ||
1112 | } | ||
1113 | |||
1114 | static void | ||
1115 | add_string_constraint(Buffer *c, const char *name, const char *value) | ||
1116 | { | ||
1117 | Buffer b; | ||
1118 | |||
1119 | debug3("%s: %s=%s", __func__, name, value); | ||
1120 | buffer_init(&b); | ||
1121 | buffer_put_cstring(&b, value); | ||
1122 | |||
1123 | buffer_put_cstring(c, name); | ||
1124 | buffer_put_string(c, buffer_ptr(&b), buffer_len(&b)); | ||
1125 | |||
1126 | buffer_free(&b); | ||
1127 | } | ||
1128 | |||
1129 | static void | ||
1130 | prepare_constraint_buf(Buffer *c) | ||
1131 | { | ||
1132 | |||
1133 | buffer_clear(c); | ||
1134 | if ((constraint_flags & CONSTRAINT_X_FWD) != 0) | ||
1135 | add_flag_constraint(c, "permit-X11-forwarding"); | ||
1136 | if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0) | ||
1137 | add_flag_constraint(c, "permit-agent-forwarding"); | ||
1138 | if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0) | ||
1139 | add_flag_constraint(c, "permit-port-forwarding"); | ||
1140 | if ((constraint_flags & CONSTRAINT_PTY) != 0) | ||
1141 | add_flag_constraint(c, "permit-pty"); | ||
1142 | if ((constraint_flags & CONSTRAINT_USER_RC) != 0) | ||
1143 | add_flag_constraint(c, "permit-user-rc"); | ||
1144 | if (constraint_command != NULL) | ||
1145 | add_string_constraint(c, "force-command", constraint_command); | ||
1146 | if (constraint_src_addr != NULL) | ||
1147 | add_string_constraint(c, "source-address", constraint_src_addr); | ||
1148 | } | ||
1149 | |||
1150 | static void | ||
1151 | do_ca_sign(struct passwd *pw, int argc, char **argv) | ||
1152 | { | ||
1153 | int i, fd; | ||
1154 | u_int n; | ||
1155 | Key *ca, *public; | ||
1156 | char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; | ||
1157 | FILE *f; | ||
1158 | |||
1159 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); | ||
1160 | if ((ca = load_identity(tmp)) == NULL) | ||
1161 | fatal("Couldn't load CA key \"%s\"", tmp); | ||
1162 | xfree(tmp); | ||
1163 | |||
1164 | for (i = 0; i < argc; i++) { | ||
1165 | /* Split list of principals */ | ||
1166 | n = 0; | ||
1167 | if (cert_principals != NULL) { | ||
1168 | otmp = tmp = xstrdup(cert_principals); | ||
1169 | plist = NULL; | ||
1170 | for (; (cp = strsep(&tmp, ",")) != NULL; n++) { | ||
1171 | plist = xrealloc(plist, n + 1, sizeof(*plist)); | ||
1172 | if (*(plist[n] = xstrdup(cp)) == '\0') | ||
1173 | fatal("Empty principal name"); | ||
1174 | } | ||
1175 | xfree(otmp); | ||
1176 | } | ||
1177 | |||
1178 | tmp = tilde_expand_filename(argv[i], pw->pw_uid); | ||
1179 | if ((public = key_load_public(tmp, &comment)) == NULL) | ||
1180 | fatal("%s: unable to open \"%s\"", __func__, tmp); | ||
1181 | if (public->type != KEY_RSA && public->type != KEY_DSA) | ||
1182 | fatal("%s: key \"%s\" type %s cannot be certified", | ||
1183 | __func__, tmp, key_type(public)); | ||
1184 | |||
1185 | /* Prepare certificate to sign */ | ||
1186 | if (key_to_certified(public) != 0) | ||
1187 | fatal("Could not upgrade key %s to certificate", tmp); | ||
1188 | public->cert->type = cert_key_type; | ||
1189 | public->cert->key_id = xstrdup(cert_key_id); | ||
1190 | public->cert->nprincipals = n; | ||
1191 | public->cert->principals = plist; | ||
1192 | public->cert->valid_after = cert_valid_from; | ||
1193 | public->cert->valid_before = cert_valid_to; | ||
1194 | prepare_constraint_buf(&public->cert->constraints); | ||
1195 | public->cert->signature_key = key_from_private(ca); | ||
1196 | |||
1197 | if (key_certify(public, ca) != 0) | ||
1198 | fatal("Couldn't not certify key %s", tmp); | ||
1199 | |||
1200 | if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) | ||
1201 | *cp = '\0'; | ||
1202 | xasprintf(&out, "%s-cert.pub", tmp); | ||
1203 | xfree(tmp); | ||
1204 | |||
1205 | if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) | ||
1206 | fatal("Could not open \"%s\" for writing: %s", out, | ||
1207 | strerror(errno)); | ||
1208 | if ((f = fdopen(fd, "w")) == NULL) | ||
1209 | fatal("%s: fdopen: %s", __func__, strerror(errno)); | ||
1210 | if (!key_write(public, f)) | ||
1211 | fatal("Could not write certified key to %s", out); | ||
1212 | fprintf(f, " %s\n", comment); | ||
1213 | fclose(f); | ||
1214 | |||
1215 | if (!quiet) | ||
1216 | logit("Signed %s key %s: id \"%s\"%s%s valid %s", | ||
1217 | cert_key_type == SSH2_CERT_TYPE_USER?"user":"host", | ||
1218 | out, cert_key_id, | ||
1219 | cert_principals != NULL ? " for " : "", | ||
1220 | cert_principals != NULL ? cert_principals : "", | ||
1221 | fmt_validity(cert_valid_from, cert_valid_to)); | ||
1222 | |||
1223 | key_free(public); | ||
1224 | xfree(out); | ||
1225 | } | ||
1226 | exit(0); | ||
1227 | } | ||
1228 | |||
1229 | static u_int64_t | ||
1230 | parse_relative_time(const char *s, time_t now) | ||
1231 | { | ||
1232 | int64_t mul, secs; | ||
1233 | |||
1234 | mul = *s == '-' ? -1 : 1; | ||
1235 | |||
1236 | if ((secs = convtime(s + 1)) == -1) | ||
1237 | fatal("Invalid relative certificate time %s", s); | ||
1238 | if (mul == -1 && secs > now) | ||
1239 | fatal("Certificate time %s cannot be represented", s); | ||
1240 | return now + (u_int64_t)(secs * mul); | ||
1241 | } | ||
1242 | |||
1243 | static u_int64_t | ||
1244 | parse_absolute_time(const char *s) | ||
1245 | { | ||
1246 | struct tm tm; | ||
1247 | time_t tt; | ||
1248 | char buf[32], *fmt; | ||
1249 | |||
1250 | /* | ||
1251 | * POSIX strptime says "The application shall ensure that there | ||
1252 | * is white-space or other non-alphanumeric characters between | ||
1253 | * any two conversion specifications" so arrange things this way. | ||
1254 | */ | ||
1255 | switch (strlen(s)) { | ||
1256 | case 8: | ||
1257 | fmt = "%Y-%m-%d"; | ||
1258 | snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); | ||
1259 | break; | ||
1260 | case 14: | ||
1261 | fmt = "%Y-%m-%dT%H:%M:%S"; | ||
1262 | snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s", | ||
1263 | s, s + 4, s + 6, s + 8, s + 10, s + 12); | ||
1264 | break; | ||
1265 | default: | ||
1266 | fatal("Invalid certificate time format %s", s); | ||
1267 | } | ||
1268 | |||
1269 | bzero(&tm, sizeof(tm)); | ||
1270 | if (strptime(buf, fmt, &tm) == NULL) | ||
1271 | fatal("Invalid certificate time %s", s); | ||
1272 | if ((tt = mktime(&tm)) < 0) | ||
1273 | fatal("Certificate time %s cannot be represented", s); | ||
1274 | return (u_int64_t)tt; | ||
1275 | } | ||
1276 | |||
1277 | static void | ||
1278 | parse_cert_times(char *timespec) | ||
1279 | { | ||
1280 | char *from, *to; | ||
1281 | time_t now = time(NULL); | ||
1282 | int64_t secs; | ||
1283 | |||
1284 | /* +timespec relative to now */ | ||
1285 | if (*timespec == '+' && strchr(timespec, ':') == NULL) { | ||
1286 | if ((secs = convtime(timespec + 1)) == -1) | ||
1287 | fatal("Invalid relative certificate life %s", timespec); | ||
1288 | cert_valid_to = now + secs; | ||
1289 | /* | ||
1290 | * Backdate certificate one minute to avoid problems on hosts | ||
1291 | * with poorly-synchronised clocks. | ||
1292 | */ | ||
1293 | cert_valid_from = ((now - 59)/ 60) * 60; | ||
1294 | return; | ||
1295 | } | ||
1296 | |||
1297 | /* | ||
1298 | * from:to, where | ||
1299 | * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | ||
1300 | * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | ||
1301 | */ | ||
1302 | from = xstrdup(timespec); | ||
1303 | to = strchr(from, ':'); | ||
1304 | if (to == NULL || from == to || *(to + 1) == '\0') | ||
1305 | fatal("Invalid certificate life specification %s", timespec); | ||
1306 | *to++ = '\0'; | ||
1307 | |||
1308 | if (*from == '-' || *from == '+') | ||
1309 | cert_valid_from = parse_relative_time(from, now); | ||
1310 | else | ||
1311 | cert_valid_from = parse_absolute_time(from); | ||
1312 | |||
1313 | if (*to == '-' || *to == '+') | ||
1314 | cert_valid_to = parse_relative_time(to, cert_valid_from); | ||
1315 | else | ||
1316 | cert_valid_to = parse_absolute_time(to); | ||
1317 | |||
1318 | if (cert_valid_to <= cert_valid_from) | ||
1319 | fatal("Empty certificate validity interval"); | ||
1320 | xfree(from); | ||
1321 | } | ||
1322 | |||
1323 | static void | ||
1324 | add_cert_constraint(char *opt) | ||
1325 | { | ||
1326 | char *val; | ||
1327 | |||
1328 | if (strcmp(opt, "clear") == 0) | ||
1329 | constraint_flags = 0; | ||
1330 | else if (strcasecmp(opt, "no-x11-forwarding") == 0) | ||
1331 | constraint_flags &= ~CONSTRAINT_X_FWD; | ||
1332 | else if (strcasecmp(opt, "permit-x11-forwarding") == 0) | ||
1333 | constraint_flags |= CONSTRAINT_X_FWD; | ||
1334 | else if (strcasecmp(opt, "no-agent-forwarding") == 0) | ||
1335 | constraint_flags &= ~CONSTRAINT_AGENT_FWD; | ||
1336 | else if (strcasecmp(opt, "permit-agent-forwarding") == 0) | ||
1337 | constraint_flags |= CONSTRAINT_AGENT_FWD; | ||
1338 | else if (strcasecmp(opt, "no-port-forwarding") == 0) | ||
1339 | constraint_flags &= ~CONSTRAINT_PORT_FWD; | ||
1340 | else if (strcasecmp(opt, "permit-port-forwarding") == 0) | ||
1341 | constraint_flags |= CONSTRAINT_PORT_FWD; | ||
1342 | else if (strcasecmp(opt, "no-pty") == 0) | ||
1343 | constraint_flags &= ~CONSTRAINT_PTY; | ||
1344 | else if (strcasecmp(opt, "permit-pty") == 0) | ||
1345 | constraint_flags |= CONSTRAINT_PTY; | ||
1346 | else if (strcasecmp(opt, "no-user-rc") == 0) | ||
1347 | constraint_flags &= ~CONSTRAINT_USER_RC; | ||
1348 | else if (strcasecmp(opt, "permit-user-rc") == 0) | ||
1349 | constraint_flags |= CONSTRAINT_USER_RC; | ||
1350 | else if (strncasecmp(opt, "force-command=", 14) == 0) { | ||
1351 | val = opt + 14; | ||
1352 | if (*val == '\0') | ||
1353 | fatal("Empty force-command constraint"); | ||
1354 | if (constraint_command != NULL) | ||
1355 | fatal("force-command already specified"); | ||
1356 | constraint_command = xstrdup(val); | ||
1357 | } else if (strncasecmp(opt, "source-address=", 15) == 0) { | ||
1358 | val = opt + 15; | ||
1359 | if (*val == '\0') | ||
1360 | fatal("Empty source-address constraint"); | ||
1361 | if (constraint_src_addr != NULL) | ||
1362 | fatal("source-address already specified"); | ||
1363 | if (addr_match_cidr_list(NULL, val) != 0) | ||
1364 | fatal("Invalid source-address list"); | ||
1365 | constraint_src_addr = xstrdup(val); | ||
1366 | } else | ||
1367 | fatal("Unsupported certificate constraint \"%s\"", opt); | ||
1368 | } | ||
1369 | |||
1370 | static void | ||
1371 | do_show_cert(struct passwd *pw) | ||
1372 | { | ||
1373 | Key *key; | ||
1374 | struct stat st; | ||
1375 | char *key_fp, *ca_fp; | ||
1376 | Buffer constraints, constraint; | ||
1377 | u_char *name, *data; | ||
1378 | u_int i, dlen; | ||
1379 | |||
1380 | if (!have_identity) | ||
1381 | ask_filename(pw, "Enter file in which the key is"); | ||
1382 | if (stat(identity_file, &st) < 0) { | ||
1383 | perror(identity_file); | ||
1384 | exit(1); | ||
1385 | } | ||
1386 | if ((key = key_load_public(identity_file, NULL)) == NULL) | ||
1387 | fatal("%s is not a public key", identity_file); | ||
1388 | if (!key_is_cert(key)) | ||
1389 | fatal("%s is not a certificate", identity_file); | ||
1390 | |||
1391 | key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | ||
1392 | ca_fp = key_fingerprint(key->cert->signature_key, | ||
1393 | SSH_FP_MD5, SSH_FP_HEX); | ||
1394 | |||
1395 | printf("%s:\n", identity_file); | ||
1396 | printf(" %s certificate %s\n", key_type(key), key_fp); | ||
1397 | printf(" Signed by %s CA %s\n", | ||
1398 | key_type(key->cert->signature_key), ca_fp); | ||
1399 | printf(" Key ID \"%s\"\n", key->cert->key_id); | ||
1400 | printf(" Valid: %s\n", | ||
1401 | fmt_validity(key->cert->valid_after, key->cert->valid_before)); | ||
1402 | printf(" Principals: "); | ||
1403 | if (key->cert->nprincipals == 0) | ||
1404 | printf("(none)\n"); | ||
1405 | else { | ||
1406 | for (i = 0; i < key->cert->nprincipals; i++) | ||
1407 | printf("\n %s", | ||
1408 | key->cert->principals[i]); | ||
1409 | printf("\n"); | ||
1410 | } | ||
1411 | printf(" Constraints: "); | ||
1412 | if (buffer_len(&key->cert->constraints) == 0) | ||
1413 | printf("(none)\n"); | ||
1414 | else { | ||
1415 | printf("\n"); | ||
1416 | buffer_init(&constraints); | ||
1417 | buffer_append(&constraints, | ||
1418 | buffer_ptr(&key->cert->constraints), | ||
1419 | buffer_len(&key->cert->constraints)); | ||
1420 | buffer_init(&constraint); | ||
1421 | while (buffer_len(&constraints) != 0) { | ||
1422 | name = buffer_get_string(&constraints, NULL); | ||
1423 | data = buffer_get_string_ptr(&constraints, &dlen); | ||
1424 | buffer_append(&constraint, data, dlen); | ||
1425 | printf(" %s", name); | ||
1426 | if (strcmp(name, "permit-X11-forwarding") == 0 || | ||
1427 | strcmp(name, "permit-agent-forwarding") == 0 || | ||
1428 | strcmp(name, "permit-port-forwarding") == 0 || | ||
1429 | strcmp(name, "permit-pty") == 0 || | ||
1430 | strcmp(name, "permit-user-rc") == 0) | ||
1431 | printf("\n"); | ||
1432 | else if (strcmp(name, "force-command") == 0 || | ||
1433 | strcmp(name, "source-address") == 0) { | ||
1434 | data = buffer_get_string(&constraint, NULL); | ||
1435 | printf(" %s\n", data); | ||
1436 | xfree(data); | ||
1437 | } else { | ||
1438 | printf(" UNKNOWN CONSTRAINT (len %u)\n", | ||
1439 | buffer_len(&constraint)); | ||
1440 | buffer_clear(&constraint); | ||
1441 | } | ||
1442 | xfree(name); | ||
1443 | if (buffer_len(&constraint) != 0) | ||
1444 | fatal("Constraint corrupt: extra data at end"); | ||
1445 | } | ||
1446 | buffer_free(&constraint); | ||
1447 | buffer_free(&constraints); | ||
1448 | } | ||
1449 | |||
1450 | exit(0); | ||
1451 | } | ||
1452 | |||
1033 | static void | 1453 | static void |
1034 | usage(void) | 1454 | usage(void) |
1035 | { | 1455 | { |
@@ -1040,30 +1460,34 @@ usage(void) | |||
1040 | fprintf(stderr, " -b bits Number of bits in the key to create.\n"); | 1460 | fprintf(stderr, " -b bits Number of bits in the key to create.\n"); |
1041 | fprintf(stderr, " -C comment Provide new comment.\n"); | 1461 | fprintf(stderr, " -C comment Provide new comment.\n"); |
1042 | fprintf(stderr, " -c Change comment in private and public key files.\n"); | 1462 | fprintf(stderr, " -c Change comment in private and public key files.\n"); |
1043 | #ifdef SMARTCARD | 1463 | #ifdef ENABLE_PKCS11 |
1044 | fprintf(stderr, " -D reader Download public key from smartcard.\n"); | 1464 | fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); |
1045 | #endif /* SMARTCARD */ | 1465 | #endif |
1046 | fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); | 1466 | fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); |
1047 | fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); | 1467 | fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); |
1048 | fprintf(stderr, " -f filename Filename of the key file.\n"); | 1468 | fprintf(stderr, " -f filename Filename of the key file.\n"); |
1049 | fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); | 1469 | fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); |
1050 | fprintf(stderr, " -g Use generic DNS resource record format.\n"); | 1470 | fprintf(stderr, " -g Use generic DNS resource record format.\n"); |
1051 | fprintf(stderr, " -H Hash names in known_hosts file.\n"); | 1471 | fprintf(stderr, " -H Hash names in known_hosts file.\n"); |
1472 | fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n"); | ||
1473 | fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); | ||
1052 | fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); | 1474 | fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); |
1475 | fprintf(stderr, " -L Print the contents of a certificate.\n"); | ||
1053 | fprintf(stderr, " -l Show fingerprint of key file.\n"); | 1476 | fprintf(stderr, " -l Show fingerprint of key file.\n"); |
1054 | fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); | 1477 | fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); |
1478 | fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); | ||
1055 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); | 1479 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); |
1480 | fprintf(stderr, " -O cnstr Specify a certificate constraint.\n"); | ||
1056 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); | 1481 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); |
1057 | fprintf(stderr, " -p Change passphrase of private key file.\n"); | 1482 | fprintf(stderr, " -p Change passphrase of private key file.\n"); |
1058 | fprintf(stderr, " -q Quiet.\n"); | 1483 | fprintf(stderr, " -q Quiet.\n"); |
1059 | fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); | 1484 | fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); |
1060 | fprintf(stderr, " -r hostname Print DNS resource record.\n"); | 1485 | fprintf(stderr, " -r hostname Print DNS resource record.\n"); |
1486 | fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); | ||
1061 | fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); | 1487 | fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); |
1062 | fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); | 1488 | fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); |
1063 | fprintf(stderr, " -t type Specify type of key to create.\n"); | 1489 | fprintf(stderr, " -t type Specify type of key to create.\n"); |
1064 | #ifdef SMARTCARD | 1490 | fprintf(stderr, " -V from:to Specify certificate validity interval.\n"); |
1065 | fprintf(stderr, " -U reader Upload private key to smartcard.\n"); | ||
1066 | #endif /* SMARTCARD */ | ||
1067 | fprintf(stderr, " -v Verbose.\n"); | 1491 | fprintf(stderr, " -v Verbose.\n"); |
1068 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); | 1492 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); |
1069 | fprintf(stderr, " -y Read private key file and print public key.\n"); | 1493 | fprintf(stderr, " -y Read private key file and print public key.\n"); |
@@ -1078,12 +1502,12 @@ int | |||
1078 | main(int argc, char **argv) | 1502 | main(int argc, char **argv) |
1079 | { | 1503 | { |
1080 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; | 1504 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; |
1081 | char out_file[MAXPATHLEN], *reader_id = NULL; | 1505 | char out_file[MAXPATHLEN], *pkcs11provider = NULL; |
1082 | char *rr_hostname = NULL; | 1506 | char *rr_hostname = NULL; |
1083 | Key *private, *public; | 1507 | Key *private, *public; |
1084 | struct passwd *pw; | 1508 | struct passwd *pw; |
1085 | struct stat st; | 1509 | struct stat st; |
1086 | int opt, type, fd, download = 0; | 1510 | int opt, type, fd; |
1087 | u_int32_t memory = 0, generator_wanted = 0, trials = 100; | 1511 | u_int32_t memory = 0, generator_wanted = 0, trials = 100; |
1088 | int do_gen_candidates = 0, do_screen_candidates = 0; | 1512 | int do_gen_candidates = 0, do_screen_candidates = 0; |
1089 | BIGNUM *start = NULL; | 1513 | BIGNUM *start = NULL; |
@@ -1115,8 +1539,8 @@ main(int argc, char **argv) | |||
1115 | exit(1); | 1539 | exit(1); |
1116 | } | 1540 | } |
1117 | 1541 | ||
1118 | while ((opt = getopt(argc, argv, | 1542 | while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:" |
1119 | "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { | 1543 | "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { |
1120 | switch (opt) { | 1544 | switch (opt) { |
1121 | case 'b': | 1545 | case 'b': |
1122 | bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); | 1546 | bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); |
@@ -1131,16 +1555,25 @@ main(int argc, char **argv) | |||
1131 | case 'H': | 1555 | case 'H': |
1132 | hash_hosts = 1; | 1556 | hash_hosts = 1; |
1133 | break; | 1557 | break; |
1558 | case 'I': | ||
1559 | cert_key_id = optarg; | ||
1560 | break; | ||
1134 | case 'R': | 1561 | case 'R': |
1135 | delete_host = 1; | 1562 | delete_host = 1; |
1136 | rr_hostname = optarg; | 1563 | rr_hostname = optarg; |
1137 | break; | 1564 | break; |
1565 | case 'L': | ||
1566 | show_cert = 1; | ||
1567 | break; | ||
1138 | case 'l': | 1568 | case 'l': |
1139 | print_fingerprint = 1; | 1569 | print_fingerprint = 1; |
1140 | break; | 1570 | break; |
1141 | case 'B': | 1571 | case 'B': |
1142 | print_bubblebabble = 1; | 1572 | print_bubblebabble = 1; |
1143 | break; | 1573 | break; |
1574 | case 'n': | ||
1575 | cert_principals = optarg; | ||
1576 | break; | ||
1144 | case 'p': | 1577 | case 'p': |
1145 | change_passphrase = 1; | 1578 | change_passphrase = 1; |
1146 | break; | 1579 | break; |
@@ -1162,6 +1595,9 @@ main(int argc, char **argv) | |||
1162 | case 'N': | 1595 | case 'N': |
1163 | identity_new_passphrase = optarg; | 1596 | identity_new_passphrase = optarg; |
1164 | break; | 1597 | break; |
1598 | case 'O': | ||
1599 | add_cert_constraint(optarg); | ||
1600 | break; | ||
1165 | case 'C': | 1601 | case 'C': |
1166 | identity_comment = optarg; | 1602 | identity_comment = optarg; |
1167 | break; | 1603 | break; |
@@ -1173,6 +1609,10 @@ main(int argc, char **argv) | |||
1173 | /* export key */ | 1609 | /* export key */ |
1174 | convert_to_ssh2 = 1; | 1610 | convert_to_ssh2 = 1; |
1175 | break; | 1611 | break; |
1612 | case 'h': | ||
1613 | cert_key_type = SSH2_CERT_TYPE_HOST; | ||
1614 | constraint_flags = 0; | ||
1615 | break; | ||
1176 | case 'i': | 1616 | case 'i': |
1177 | case 'X': | 1617 | case 'X': |
1178 | /* import key */ | 1618 | /* import key */ |
@@ -1184,14 +1624,14 @@ main(int argc, char **argv) | |||
1184 | case 'd': | 1624 | case 'd': |
1185 | key_type_name = "dsa"; | 1625 | key_type_name = "dsa"; |
1186 | break; | 1626 | break; |
1627 | case 's': | ||
1628 | ca_key_path = optarg; | ||
1629 | break; | ||
1187 | case 't': | 1630 | case 't': |
1188 | key_type_name = optarg; | 1631 | key_type_name = optarg; |
1189 | break; | 1632 | break; |
1190 | case 'D': | 1633 | case 'D': |
1191 | download = 1; | 1634 | pkcs11provider = optarg; |
1192 | /*FALLTHROUGH*/ | ||
1193 | case 'U': | ||
1194 | reader_id = optarg; | ||
1195 | break; | 1635 | break; |
1196 | case 'v': | 1636 | case 'v': |
1197 | if (log_level == SYSLOG_LEVEL_INFO) | 1637 | if (log_level == SYSLOG_LEVEL_INFO) |
@@ -1241,6 +1681,9 @@ main(int argc, char **argv) | |||
1241 | if (BN_hex2bn(&start, optarg) == 0) | 1681 | if (BN_hex2bn(&start, optarg) == 0) |
1242 | fatal("Invalid start point."); | 1682 | fatal("Invalid start point."); |
1243 | break; | 1683 | break; |
1684 | case 'V': | ||
1685 | parse_cert_times(optarg); | ||
1686 | break; | ||
1244 | case '?': | 1687 | case '?': |
1245 | default: | 1688 | default: |
1246 | usage(); | 1689 | usage(); |
@@ -1250,7 +1693,15 @@ main(int argc, char **argv) | |||
1250 | /* reinit */ | 1693 | /* reinit */ |
1251 | log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); | 1694 | log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); |
1252 | 1695 | ||
1253 | if (optind < argc) { | 1696 | argv += optind; |
1697 | argc -= optind; | ||
1698 | |||
1699 | if (ca_key_path != NULL) { | ||
1700 | if (argc < 1) { | ||
1701 | printf("Too few arguments.\n"); | ||
1702 | usage(); | ||
1703 | } | ||
1704 | } else if (argc > 0) { | ||
1254 | printf("Too many arguments.\n"); | 1705 | printf("Too many arguments.\n"); |
1255 | usage(); | 1706 | usage(); |
1256 | } | 1707 | } |
@@ -1262,6 +1713,13 @@ main(int argc, char **argv) | |||
1262 | printf("Cannot use -l with -D or -R.\n"); | 1713 | printf("Cannot use -l with -D or -R.\n"); |
1263 | usage(); | 1714 | usage(); |
1264 | } | 1715 | } |
1716 | if (ca_key_path != NULL) { | ||
1717 | if (cert_key_id == NULL) | ||
1718 | fatal("Must specify key id (-I) when certifying"); | ||
1719 | do_ca_sign(pw, argc, argv); | ||
1720 | } | ||
1721 | if (show_cert) | ||
1722 | do_show_cert(pw); | ||
1265 | if (delete_host || hash_hosts || find_host) | 1723 | if (delete_host || hash_hosts || find_host) |
1266 | do_known_hosts(pw, rr_hostname); | 1724 | do_known_hosts(pw, rr_hostname); |
1267 | if (print_fingerprint || print_bubblebabble) | 1725 | if (print_fingerprint || print_bubblebabble) |
@@ -1299,16 +1757,8 @@ main(int argc, char **argv) | |||
1299 | exit(0); | 1757 | exit(0); |
1300 | } | 1758 | } |
1301 | } | 1759 | } |
1302 | if (reader_id != NULL) { | 1760 | if (pkcs11provider != NULL) |
1303 | #ifdef SMARTCARD | 1761 | do_download(pw, pkcs11provider); |
1304 | if (download) | ||
1305 | do_download(pw, reader_id); | ||
1306 | else | ||
1307 | do_upload(pw, reader_id); | ||
1308 | #else /* SMARTCARD */ | ||
1309 | fatal("no support for smartcards."); | ||
1310 | #endif /* SMARTCARD */ | ||
1311 | } | ||
1312 | 1762 | ||
1313 | if (do_gen_candidates) { | 1763 | if (do_gen_candidates) { |
1314 | FILE *out = fopen(out_file, "w"); | 1764 | FILE *out = fopen(out_file, "w"); |