summaryrefslogtreecommitdiff
path: root/ssh-keygen.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r--ssh-keygen.c433
1 files changed, 404 insertions, 29 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c
index b6b7a2d9f..60261c210 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.178 2010/02/09 00:50:59 djm Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.179 2010/02/26 20:29:54 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,6 +48,7 @@
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 ENABLE_PKCS11 53#ifdef ENABLE_PKCS11
53#include "ssh-pkcs11.h" 54#include "ssh-pkcs11.h"
@@ -98,6 +99,35 @@ char *identity_new_passphrase = NULL;
98/* This is set to the new comment if given on the command line. */ 99/* This is set to the new comment if given on the command line. */
99char *identity_comment = NULL; 100char *identity_comment = NULL;
100 101
102/* Path to CA key when certifying keys. */
103char *ca_key_path = NULL;
104
105/* Key type when certifying */
106u_int cert_key_type = SSH2_CERT_TYPE_USER;
107
108/* "key ID" of signed key */
109char *cert_key_id = NULL;
110
111/* Comma-separated list of principal names for certifying keys */
112char *cert_principals = NULL;
113
114/* Validity period for certificates */
115u_int64_t cert_valid_from = 0;
116u_int64_t cert_valid_to = ~0ULL;
117
118/* Certificate constraints */
119#define CONSTRAINT_X_FWD (1)
120#define CONSTRAINT_AGENT_FWD (1<<1)
121#define CONSTRAINT_PORT_FWD (1<<2)
122#define CONSTRAINT_PTY (1<<3)
123#define CONSTRAINT_USER_RC (1<<4)
124#define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \
125 CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \
126 CONSTRAINT_USER_RC)
127u_int32_t constraint_flags = CONSTRAINT_DEFAULT;
128char *constraint_command = NULL;
129char *constraint_src_addr = NULL;
130
101/* Dump public key file in format used by real and the original SSH 2 */ 131/* Dump public key file in format used by real and the original SSH 2 */
102int convert_to_ssh2 = 0; 132int convert_to_ssh2 = 0;
103int convert_from_ssh2 = 0; 133int convert_from_ssh2 = 0;
@@ -591,7 +621,7 @@ do_fingerprint(struct passwd *pw)
591} 621}
592 622
593static void 623static void
594print_host(FILE *f, const char *name, Key *public, int hash) 624printhost(FILE *f, const char *name, Key *public, int ca, int hash)
595{ 625{
596 if (print_fingerprint) { 626 if (print_fingerprint) {
597 enum fp_rep rep; 627 enum fp_rep rep;
@@ -611,7 +641,7 @@ print_host(FILE *f, const char *name, Key *public, int hash)
611 } else { 641 } else {
612 if (hash && (name = host_hash(name, NULL, 0)) == NULL) 642 if (hash && (name = host_hash(name, NULL, 0)) == NULL)
613 fatal("hash_host failed"); 643 fatal("hash_host failed");
614 fprintf(f, "%s ", name); 644 fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name);
615 if (!key_write(public, f)) 645 if (!key_write(public, f))
616 fatal("key_write failed"); 646 fatal("key_write failed");
617 fprintf(f, "\n"); 647 fprintf(f, "\n");
@@ -622,10 +652,11 @@ static void
622do_known_hosts(struct passwd *pw, const char *name) 652do_known_hosts(struct passwd *pw, const char *name)
623{ 653{
624 FILE *in, *out = stdout; 654 FILE *in, *out = stdout;
625 Key *public; 655 Key *pub;
626 char *cp, *cp2, *kp, *kp2; 656 char *cp, *cp2, *kp, *kp2;
627 char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; 657 char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
628 int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; 658 int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
659 int ca;
629 660
630 if (!have_identity) { 661 if (!have_identity) {
631 cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); 662 cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
@@ -681,9 +712,19 @@ do_known_hosts(struct passwd *pw, const char *name)
681 fprintf(out, "%s\n", cp); 712 fprintf(out, "%s\n", cp);
682 continue; 713 continue;
683 } 714 }
715 /* Check whether this is a CA key */
716 if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 &&
717 (cp[sizeof(CA_MARKER) - 1] == ' ' ||
718 cp[sizeof(CA_MARKER) - 1] == '\t')) {
719 ca = 1;
720 cp += sizeof(CA_MARKER);
721 } else
722 ca = 0;
723
684 /* Find the end of the host name portion. */ 724 /* Find the end of the host name portion. */
685 for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) 725 for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
686 ; 726 ;
727
687 if (*kp == '\0' || *(kp + 1) == '\0') { 728 if (*kp == '\0' || *(kp + 1) == '\0') {
688 error("line %d missing key: %.40s...", 729 error("line %d missing key: %.40s...",
689 num, line); 730 num, line);
@@ -693,15 +734,15 @@ do_known_hosts(struct passwd *pw, const char *name)
693 *kp++ = '\0'; 734 *kp++ = '\0';
694 kp2 = kp; 735 kp2 = kp;
695 736
696 public = key_new(KEY_RSA1); 737 pub = key_new(KEY_RSA1);
697 if (key_read(public, &kp) != 1) { 738 if (key_read(pub, &kp) != 1) {
698 kp = kp2; 739 kp = kp2;
699 key_free(public); 740 key_free(pub);
700 public = key_new(KEY_UNSPEC); 741 pub = key_new(KEY_UNSPEC);
701 if (key_read(public, &kp) != 1) { 742 if (key_read(pub, &kp) != 1) {
702 error("line %d invalid key: %.40s...", 743 error("line %d invalid key: %.40s...",
703 num, line); 744 num, line);
704 key_free(public); 745 key_free(pub);
705 invalid = 1; 746 invalid = 1;
706 continue; 747 continue;
707 } 748 }
@@ -719,43 +760,52 @@ do_known_hosts(struct passwd *pw, const char *name)
719 c = (strcmp(cp2, cp) == 0); 760 c = (strcmp(cp2, cp) == 0);
720 if (find_host && c) { 761 if (find_host && c) {
721 printf("# Host %s found: " 762 printf("# Host %s found: "
722 "line %d type %s\n", name, 763 "line %d type %s%s\n", name,
723 num, key_type(public)); 764 num, key_type(pub),
724 print_host(out, cp, public, 0); 765 ca ? " (CA key)" : "");
766 printhost(out, cp, pub, ca, 0);
725 } 767 }
726 if (delete_host && !c) 768 if (delete_host && !c && !ca)
727 print_host(out, cp, public, 0); 769 printhost(out, cp, pub, ca, 0);
728 } else if (hash_hosts) 770 } else if (hash_hosts)
729 print_host(out, cp, public, 0); 771 printhost(out, cp, pub, ca, 0);
730 } else { 772 } else {
731 if (find_host || delete_host) { 773 if (find_host || delete_host) {
732 c = (match_hostname(name, cp, 774 c = (match_hostname(name, cp,
733 strlen(cp)) == 1); 775 strlen(cp)) == 1);
734 if (find_host && c) { 776 if (find_host && c) {
735 printf("# Host %s found: " 777 printf("# Host %s found: "
736 "line %d type %s\n", name, 778 "line %d type %s%s\n", name,
737 num, key_type(public)); 779 num, key_type(pub),
738 print_host(out, name, public, 780 ca ? " (CA key)" : "");
739 hash_hosts); 781 printhost(out, name, pub,
782 ca, hash_hosts && !ca);
740 } 783 }
741 if (delete_host && !c) 784 if (delete_host && !c && !ca)
742 print_host(out, cp, public, 0); 785 printhost(out, cp, pub, ca, 0);
743 } else if (hash_hosts) { 786 } else if (hash_hosts) {
744 for (cp2 = strsep(&cp, ","); 787 for (cp2 = strsep(&cp, ",");
745 cp2 != NULL && *cp2 != '\0'; 788 cp2 != NULL && *cp2 != '\0';
746 cp2 = strsep(&cp, ",")) { 789 cp2 = strsep(&cp, ",")) {
747 if (strcspn(cp2, "*?!") != strlen(cp2)) 790 if (ca) {
791 fprintf(stderr, "Warning: "
792 "ignoring CA key for host: "
793 "%.64s\n", cp2);
794 printhost(out, cp2, pub, ca, 0);
795 } else if (strcspn(cp2, "*?!") !=
796 strlen(cp2)) {
748 fprintf(stderr, "Warning: " 797 fprintf(stderr, "Warning: "
749 "ignoring host name with " 798 "ignoring host name with "
750 "metacharacters: %.64s\n", 799 "metacharacters: %.64s\n",
751 cp2); 800 cp2);
752 else 801 printhost(out, cp2, pub, ca, 0);
753 print_host(out, cp2, public, 1); 802 } else
803 printhost(out, cp2, pub, ca, 1);
754 } 804 }
755 has_unhashed = 1; 805 has_unhashed = 1;
756 } 806 }
757 } 807 }
758 key_free(public); 808 key_free(pub);
759 } 809 }
760 fclose(in); 810 fclose(in);
761 811
@@ -1012,6 +1062,293 @@ do_change_comment(struct passwd *pw)
1012 exit(0); 1062 exit(0);
1013} 1063}
1014 1064
1065static const char *
1066fmt_validity(void)
1067{
1068 char from[32], to[32];
1069 static char ret[64];
1070 time_t tt;
1071 struct tm *tm;
1072
1073 *from = *to = '\0';
1074 if (cert_valid_from == 0 &&
1075 cert_valid_to == 0xffffffffffffffffULL)
1076 return "forever";
1077
1078 if (cert_valid_from != 0) {
1079 /* XXX revisit INT_MAX in 2038 :) */
1080 tt = cert_valid_from > INT_MAX ? INT_MAX : cert_valid_from;
1081 tm = localtime(&tt);
1082 strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
1083 }
1084 if (cert_valid_to != 0xffffffffffffffffULL) {
1085 /* XXX revisit INT_MAX in 2038 :) */
1086 tt = cert_valid_to > INT_MAX ? INT_MAX : cert_valid_to;
1087 tm = localtime(&tt);
1088 strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
1089 }
1090
1091 if (cert_valid_from == 0) {
1092 snprintf(ret, sizeof(ret), "before %s", to);
1093 return ret;
1094 }
1095 if (cert_valid_to == 0xffffffffffffffffULL) {
1096 snprintf(ret, sizeof(ret), "after %s", from);
1097 return ret;
1098 }
1099
1100 snprintf(ret, sizeof(ret), "from %s to %s", from, to);
1101 return ret;
1102}
1103
1104static void
1105add_flag_constraint(Buffer *c, const char *name)
1106{
1107 debug3("%s: %s", __func__, name);
1108 buffer_put_cstring(c, name);
1109 buffer_put_string(c, NULL, 0);
1110}
1111
1112static void
1113add_string_constraint(Buffer *c, const char *name, const char *value)
1114{
1115 Buffer b;
1116
1117 debug3("%s: %s=%s", __func__, name, value);
1118 buffer_init(&b);
1119 buffer_put_cstring(&b, value);
1120
1121 buffer_put_cstring(c, name);
1122 buffer_put_string(c, buffer_ptr(&b), buffer_len(&b));
1123
1124 buffer_free(&b);
1125}
1126
1127static void
1128prepare_constraint_buf(Buffer *c)
1129{
1130
1131 buffer_clear(c);
1132 if ((constraint_flags & CONSTRAINT_X_FWD) != 0)
1133 add_flag_constraint(c, "permit-X11-forwarding");
1134 if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0)
1135 add_flag_constraint(c, "permit-agent-forwarding");
1136 if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0)
1137 add_flag_constraint(c, "permit-port-forwarding");
1138 if ((constraint_flags & CONSTRAINT_PTY) != 0)
1139 add_flag_constraint(c, "permit-pty");
1140 if ((constraint_flags & CONSTRAINT_USER_RC) != 0)
1141 add_flag_constraint(c, "permit-user-rc");
1142 if (constraint_command != NULL)
1143 add_string_constraint(c, "forced-command", constraint_command);
1144 if (constraint_src_addr != NULL)
1145 add_string_constraint(c, "source-address", constraint_src_addr);
1146}
1147
1148static void
1149do_ca_sign(struct passwd *pw, int argc, char **argv)
1150{
1151 int i, fd;
1152 u_int n;
1153 Key *ca, *public;
1154 char *otmp, *tmp, *cp, *out, *comment, **plist = NULL;
1155 FILE *f;
1156
1157 tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
1158 if ((ca = load_identity(tmp)) == NULL)
1159 fatal("Couldn't load CA key \"%s\"", tmp);
1160 xfree(tmp);
1161
1162 for (i = 0; i < argc; i++) {
1163 /* Split list of principals */
1164 n = 0;
1165 if (cert_principals != NULL) {
1166 otmp = tmp = xstrdup(cert_principals);
1167 plist = NULL;
1168 for (; (cp = strsep(&tmp, ",")) != NULL; n++) {
1169 plist = xrealloc(plist, n + 1, sizeof(*plist));
1170 if (*(plist[n] = xstrdup(cp)) == '\0')
1171 fatal("Empty principal name");
1172 }
1173 xfree(otmp);
1174 }
1175
1176 tmp = tilde_expand_filename(argv[i], pw->pw_uid);
1177 if ((public = key_load_public(tmp, &comment)) == NULL)
1178 fatal("%s: unable to open \"%s\"", __func__, tmp);
1179 if (public->type != KEY_RSA && public->type != KEY_DSA)
1180 fatal("%s: key \"%s\" type %s cannot be certified",
1181 __func__, tmp, key_type(public));
1182
1183 /* Prepare certificate to sign */
1184 if (key_to_certified(public) != 0)
1185 fatal("Could not upgrade key %s to certificate", tmp);
1186 public->cert->type = cert_key_type;
1187 public->cert->key_id = xstrdup(cert_key_id);
1188 public->cert->nprincipals = n;
1189 public->cert->principals = plist;
1190 public->cert->valid_after = cert_valid_from;
1191 public->cert->valid_before = cert_valid_to;
1192 prepare_constraint_buf(&public->cert->constraints);
1193 public->cert->signature_key = key_from_private(ca);
1194
1195 if (key_certify(public, ca) != 0)
1196 fatal("Couldn't not certify key %s", tmp);
1197
1198 if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0)
1199 *cp = '\0';
1200 xasprintf(&out, "%s-cert.pub", tmp);
1201 xfree(tmp);
1202
1203 if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
1204 fatal("Could not open \"%s\" for writing: %s", out,
1205 strerror(errno));
1206 if ((f = fdopen(fd, "w")) == NULL)
1207 fatal("%s: fdopen: %s", __func__, strerror(errno));
1208 if (!key_write(public, f))
1209 fatal("Could not write certified key to %s", out);
1210 fprintf(f, " %s\n", comment);
1211 fclose(f);
1212
1213 if (!quiet)
1214 logit("Signed %s key %s: id \"%s\"%s%s valid %s",
1215 cert_key_type == SSH2_CERT_TYPE_USER?"user":"host",
1216 out, cert_key_id,
1217 cert_principals != NULL ? " for " : "",
1218 cert_principals != NULL ? cert_principals : "",
1219 fmt_validity());
1220
1221 key_free(public);
1222 xfree(out);
1223 }
1224 exit(0);
1225}
1226
1227static u_int64_t
1228parse_relative_time(const char *s, time_t now)
1229{
1230 int64_t mul, secs;
1231
1232 mul = *s == '-' ? -1 : 1;
1233
1234 if ((secs = convtime(s + 1)) == -1)
1235 fatal("Invalid relative certificate time %s", s);
1236 if (mul == -1 && secs > now)
1237 fatal("Certificate time %s cannot be represented", s);
1238 return now + (u_int64_t)(secs * mul);
1239}
1240
1241static u_int64_t
1242parse_absolute_time(const char *s)
1243{
1244 struct tm tm;
1245 time_t tt;
1246
1247 if (strlen(s) != 8 && strlen(s) != 14)
1248 fatal("Invalid certificate time format %s", s);
1249
1250 bzero(&tm, sizeof(tm));
1251 if (strptime(s,
1252 strlen(s) == 8 ? "%Y%m%d" : "%Y%m%d%H%M%S", &tm) == NULL)
1253 fatal("Invalid certificate time %s", s);
1254 if ((tt = mktime(&tm)) < 0)
1255 fatal("Certificate time %s cannot be represented", s);
1256 return (u_int64_t)tt;
1257}
1258
1259static void
1260parse_cert_times(char *timespec)
1261{
1262 char *from, *to;
1263 time_t now = time(NULL);
1264 int64_t secs;
1265
1266 /* +timespec relative to now */
1267 if (*timespec == '+' && strchr(timespec, ':') == NULL) {
1268 if ((secs = convtime(timespec + 1)) == -1)
1269 fatal("Invalid relative certificate life %s", timespec);
1270 cert_valid_to = now + secs;
1271 /*
1272 * Backdate certificate one minute to avoid problems on hosts
1273 * with poorly-synchronised clocks.
1274 */
1275 cert_valid_from = ((now - 59)/ 60) * 60;
1276 return;
1277 }
1278
1279 /*
1280 * from:to, where
1281 * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
1282 * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
1283 */
1284 from = xstrdup(timespec);
1285 to = strchr(from, ':');
1286 if (to == NULL || from == to || *(to + 1) == '\0')
1287 fatal("Invalid certificate life specification %s", optarg);
1288 *to++ = '\0';
1289
1290 if (*from == '-' || *from == '+')
1291 cert_valid_from = parse_relative_time(from, now);
1292 else
1293 cert_valid_from = parse_absolute_time(from);
1294
1295 if (*to == '-' || *to == '+')
1296 cert_valid_to = parse_relative_time(to, cert_valid_from);
1297 else
1298 cert_valid_to = parse_absolute_time(to);
1299
1300 if (cert_valid_to <= cert_valid_from)
1301 fatal("Empty certificate validity interval");
1302 xfree(from);
1303}
1304
1305static void
1306add_cert_constraint(char *opt)
1307{
1308 char *val;
1309
1310 if (strcmp(opt, "clear") == 0)
1311 constraint_flags = 0;
1312 else if (strcasecmp(opt, "no-x11-forwarding") == 0)
1313 constraint_flags &= ~CONSTRAINT_X_FWD;
1314 else if (strcasecmp(opt, "permit-x11-forwarding") == 0)
1315 constraint_flags |= CONSTRAINT_X_FWD;
1316 else if (strcasecmp(opt, "no-agent-forwarding") == 0)
1317 constraint_flags &= ~CONSTRAINT_AGENT_FWD;
1318 else if (strcasecmp(opt, "permit-agent-forwarding") == 0)
1319 constraint_flags |= CONSTRAINT_AGENT_FWD;
1320 else if (strcasecmp(opt, "no-port-forwarding") == 0)
1321 constraint_flags &= ~CONSTRAINT_PORT_FWD;
1322 else if (strcasecmp(opt, "permit-port-forwarding") == 0)
1323 constraint_flags |= CONSTRAINT_PORT_FWD;
1324 else if (strcasecmp(opt, "no-pty") == 0)
1325 constraint_flags &= ~CONSTRAINT_PTY;
1326 else if (strcasecmp(opt, "permit-pty") == 0)
1327 constraint_flags |= CONSTRAINT_PTY;
1328 else if (strcasecmp(opt, "no-user-rc") == 0)
1329 constraint_flags &= ~CONSTRAINT_USER_RC;
1330 else if (strcasecmp(opt, "permit-user-rc") == 0)
1331 constraint_flags |= CONSTRAINT_USER_RC;
1332 else if (strncasecmp(opt, "force-command=", 14) == 0) {
1333 val = opt + 14;
1334 if (*val == '\0')
1335 fatal("Empty force-command constraint");
1336 if (constraint_command != NULL)
1337 fatal("force-command already specified");
1338 constraint_command = xstrdup(val);
1339 } else if (strncasecmp(opt, "source-address=", 15) == 0) {
1340 val = opt + 15;
1341 if (*val == '\0')
1342 fatal("Empty source-address constraint");
1343 if (constraint_src_addr != NULL)
1344 fatal("source-address already specified");
1345 if (addr_match_cidr_list(NULL, val) != 0)
1346 fatal("Invalid source-address list");
1347 constraint_src_addr = xstrdup(val);
1348 } else
1349 fatal("Unsupported certificate constraint \"%s\"", opt);
1350}
1351
1015static void 1352static void
1016usage(void) 1353usage(void)
1017{ 1354{
@@ -1031,18 +1368,24 @@ usage(void)
1031 fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); 1368 fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n");
1032 fprintf(stderr, " -g Use generic DNS resource record format.\n"); 1369 fprintf(stderr, " -g Use generic DNS resource record format.\n");
1033 fprintf(stderr, " -H Hash names in known_hosts file.\n"); 1370 fprintf(stderr, " -H Hash names in known_hosts file.\n");
1371 fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n");
1372 fprintf(stderr, " -I key_id Key identifier to include in certificate.\n");
1034 fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); 1373 fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n");
1035 fprintf(stderr, " -l Show fingerprint of key file.\n"); 1374 fprintf(stderr, " -l Show fingerprint of key file.\n");
1036 fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); 1375 fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n");
1376 fprintf(stderr, " -n name,... User/host principal names to include in certificate\n");
1037 fprintf(stderr, " -N phrase Provide new passphrase.\n"); 1377 fprintf(stderr, " -N phrase Provide new passphrase.\n");
1378 fprintf(stderr, " -O cnstr Specify a certificate constraint.\n");
1038 fprintf(stderr, " -P phrase Provide old passphrase.\n"); 1379 fprintf(stderr, " -P phrase Provide old passphrase.\n");
1039 fprintf(stderr, " -p Change passphrase of private key file.\n"); 1380 fprintf(stderr, " -p Change passphrase of private key file.\n");
1040 fprintf(stderr, " -q Quiet.\n"); 1381 fprintf(stderr, " -q Quiet.\n");
1041 fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); 1382 fprintf(stderr, " -R hostname Remove host from known_hosts file.\n");
1042 fprintf(stderr, " -r hostname Print DNS resource record.\n"); 1383 fprintf(stderr, " -r hostname Print DNS resource record.\n");
1384 fprintf(stderr, " -s ca_key Certify keys with CA key.\n");
1043 fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); 1385 fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n");
1044 fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); 1386 fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n");
1045 fprintf(stderr, " -t type Specify type of key to create.\n"); 1387 fprintf(stderr, " -t type Specify type of key to create.\n");
1388 fprintf(stderr, " -V from:to Specify certificate validity interval.\n");
1046 fprintf(stderr, " -v Verbose.\n"); 1389 fprintf(stderr, " -v Verbose.\n");
1047 fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); 1390 fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n");
1048 fprintf(stderr, " -y Read private key file and print public key.\n"); 1391 fprintf(stderr, " -y Read private key file and print public key.\n");
@@ -1094,8 +1437,8 @@ main(int argc, char **argv)
1094 exit(1); 1437 exit(1);
1095 } 1438 }
1096 1439
1097 while ((opt = getopt(argc, argv, 1440 while ((opt = getopt(argc, argv, "degiqpclBHhvxXyF:b:f:t:D:I:P:N:n:"
1098 "degiqpclBHvxXyF:b:f:t:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { 1441 "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) {
1099 switch (opt) { 1442 switch (opt) {
1100 case 'b': 1443 case 'b':
1101 bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); 1444 bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
@@ -1110,6 +1453,9 @@ main(int argc, char **argv)
1110 case 'H': 1453 case 'H':
1111 hash_hosts = 1; 1454 hash_hosts = 1;
1112 break; 1455 break;
1456 case 'I':
1457 cert_key_id = optarg;
1458 break;
1113 case 'R': 1459 case 'R':
1114 delete_host = 1; 1460 delete_host = 1;
1115 rr_hostname = optarg; 1461 rr_hostname = optarg;
@@ -1120,6 +1466,9 @@ main(int argc, char **argv)
1120 case 'B': 1466 case 'B':
1121 print_bubblebabble = 1; 1467 print_bubblebabble = 1;
1122 break; 1468 break;
1469 case 'n':
1470 cert_principals = optarg;
1471 break;
1123 case 'p': 1472 case 'p':
1124 change_passphrase = 1; 1473 change_passphrase = 1;
1125 break; 1474 break;
@@ -1141,6 +1490,9 @@ main(int argc, char **argv)
1141 case 'N': 1490 case 'N':
1142 identity_new_passphrase = optarg; 1491 identity_new_passphrase = optarg;
1143 break; 1492 break;
1493 case 'O':
1494 add_cert_constraint(optarg);
1495 break;
1144 case 'C': 1496 case 'C':
1145 identity_comment = optarg; 1497 identity_comment = optarg;
1146 break; 1498 break;
@@ -1152,6 +1504,10 @@ main(int argc, char **argv)
1152 /* export key */ 1504 /* export key */
1153 convert_to_ssh2 = 1; 1505 convert_to_ssh2 = 1;
1154 break; 1506 break;
1507 case 'h':
1508 cert_key_type = SSH2_CERT_TYPE_HOST;
1509 constraint_flags = 0;
1510 break;
1155 case 'i': 1511 case 'i':
1156 case 'X': 1512 case 'X':
1157 /* import key */ 1513 /* import key */
@@ -1163,6 +1519,9 @@ main(int argc, char **argv)
1163 case 'd': 1519 case 'd':
1164 key_type_name = "dsa"; 1520 key_type_name = "dsa";
1165 break; 1521 break;
1522 case 's':
1523 ca_key_path = optarg;
1524 break;
1166 case 't': 1525 case 't':
1167 key_type_name = optarg; 1526 key_type_name = optarg;
1168 break; 1527 break;
@@ -1217,6 +1576,9 @@ main(int argc, char **argv)
1217 if (BN_hex2bn(&start, optarg) == 0) 1576 if (BN_hex2bn(&start, optarg) == 0)
1218 fatal("Invalid start point."); 1577 fatal("Invalid start point.");
1219 break; 1578 break;
1579 case 'V':
1580 parse_cert_times(optarg);
1581 break;
1220 case '?': 1582 case '?':
1221 default: 1583 default:
1222 usage(); 1584 usage();
@@ -1226,7 +1588,15 @@ main(int argc, char **argv)
1226 /* reinit */ 1588 /* reinit */
1227 log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); 1589 log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
1228 1590
1229 if (optind < argc) { 1591 argv += optind;
1592 argc -= optind;
1593
1594 if (ca_key_path != NULL) {
1595 if (argc < 1) {
1596 printf("Too few arguments.\n");
1597 usage();
1598 }
1599 } else if (argc > 0) {
1230 printf("Too many arguments.\n"); 1600 printf("Too many arguments.\n");
1231 usage(); 1601 usage();
1232 } 1602 }
@@ -1238,6 +1608,11 @@ main(int argc, char **argv)
1238 printf("Cannot use -l with -D or -R.\n"); 1608 printf("Cannot use -l with -D or -R.\n");
1239 usage(); 1609 usage();
1240 } 1610 }
1611 if (ca_key_path != NULL) {
1612 if (cert_key_id == NULL)
1613 fatal("Must specify key id (-I) when certifying");
1614 do_ca_sign(pw, argc, argv);
1615 }
1241 if (delete_host || hash_hosts || find_host) 1616 if (delete_host || hash_hosts || find_host)
1242 do_known_hosts(pw, rr_hostname); 1617 do_known_hosts(pw, rr_hostname);
1243 if (print_fingerprint || print_bubblebabble) 1618 if (print_fingerprint || print_bubblebabble)