summaryrefslogtreecommitdiff
path: root/ssh-keygen.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2010-03-31 10:46:28 +0100
committerColin Watson <cjwatson@debian.org>2010-03-31 10:46:28 +0100
commitefd3d4522636ae029488c2e9730b60c88e257d2e (patch)
tree31e02ac3f16090ce8c53448677356b2b7f423683 /ssh-keygen.c
parentbbec4db36d464ea1d464a707625125f9fd5c7b5e (diff)
parentd1a87e462e1db89f19cd960588d0c6b287cb5ccc (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.c636
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 */
82int delete_host = 0; 83int delete_host = 0;
83 84
85/* Flag indicating that we want to show the contents of a certificate */
86int 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 */
85int print_fingerprint = 0; 89int print_fingerprint = 0;
86int print_bubblebabble = 0; 90int 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. */
99char *identity_comment = NULL; 103char *identity_comment = NULL;
100 104
105/* Path to CA key when certifying keys. */
106char *ca_key_path = NULL;
107
108/* Key type when certifying */
109u_int cert_key_type = SSH2_CERT_TYPE_USER;
110
111/* "key ID" of signed key */
112char *cert_key_id = NULL;
113
114/* Comma-separated list of principal names for certifying keys */
115char *cert_principals = NULL;
116
117/* Validity period for certificates */
118u_int64_t cert_valid_from = 0;
119u_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)
130u_int32_t constraint_flags = CONSTRAINT_DEFAULT;
131char *constraint_command = NULL;
132char *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 */
102int convert_to_ssh2 = 0; 135int convert_to_ssh2 = 0;
103int convert_from_ssh2 = 0; 136int 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
459static void 495static void
460do_upload(struct passwd *pw, const char *sc_reader_id) 496do_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
485static void
486do_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
504static void 519static void
505do_fingerprint(struct passwd *pw) 520do_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
611static void 626static void
612print_host(FILE *f, const char *name, Key *public, int hash) 627printhost(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
640do_known_hosts(struct passwd *pw, const char *name) 655do_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
1068static const char *
1069fmt_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
1106static void
1107add_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
1114static void
1115add_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
1129static void
1130prepare_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
1150static void
1151do_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
1229static u_int64_t
1230parse_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
1243static u_int64_t
1244parse_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
1277static void
1278parse_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
1323static void
1324add_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
1370static void
1371do_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
1033static void 1453static void
1034usage(void) 1454usage(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
1078main(int argc, char **argv) 1502main(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");