summaryrefslogtreecommitdiff
path: root/ssh-keygen.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-02-27 07:55:05 +1100
committerDamien Miller <djm@mindrot.org>2010-02-27 07:55:05 +1100
commit0a80ca190a39943029719facf7edb990def7ae62 (patch)
treee423e30d8412de67170b8240ba919df10ed8e391 /ssh-keygen.c
parentd27d85d5320bb946d4bb734dcf45a8d20bad6020 (diff)
- OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/02/26 20:29:54 [PROTOCOL PROTOCOL.agent PROTOCOL.certkeys addrmatch.c auth-options.c] [auth-options.h auth.h auth2-pubkey.c authfd.c dns.c dns.h hostfile.c] [hostfile.h kex.h kexdhs.c kexgexs.c key.c key.h match.h monitor.c] [myproposal.h servconf.c servconf.h ssh-add.c ssh-agent.c ssh-dss.c] [ssh-keygen.1 ssh-keygen.c ssh-rsa.c ssh.1 ssh.c ssh2.h sshconnect.c] [sshconnect2.c sshd.8 sshd.c sshd_config.5] Add support for certificate key types for users and hosts. OpenSSH certificate key types are not X.509 certificates, but a much simpler format that encodes a public key, identity information and some validity constraints and signs it with a CA key. CA keys are regular SSH keys. This certificate style avoids the attack surface of X.509 certificates and is very easy to deploy. Certified host keys allow automatic acceptance of new host keys when a CA certificate is marked as sh/known_hosts. see VERIFYING HOST KEYS in ssh(1) for details. Certified user keys allow authentication of users when the signing CA key is marked as trusted in authorized_keys. See "AUTHORIZED_KEYS FILE FORMAT" in sshd(8) for details. Certificates are minted using ssh-keygen(1), documentation is in the "CERTIFICATES" section of that manpage. Documentation on the format of certificates is in the file PROTOCOL.certkeys feedback and ok markus@
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)