diff options
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 433 |
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. */ |
99 | char *identity_comment = NULL; | 100 | char *identity_comment = NULL; |
100 | 101 | ||
102 | /* Path to CA key when certifying keys. */ | ||
103 | char *ca_key_path = NULL; | ||
104 | |||
105 | /* Key type when certifying */ | ||
106 | u_int cert_key_type = SSH2_CERT_TYPE_USER; | ||
107 | |||
108 | /* "key ID" of signed key */ | ||
109 | char *cert_key_id = NULL; | ||
110 | |||
111 | /* Comma-separated list of principal names for certifying keys */ | ||
112 | char *cert_principals = NULL; | ||
113 | |||
114 | /* Validity period for certificates */ | ||
115 | u_int64_t cert_valid_from = 0; | ||
116 | u_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) | ||
127 | u_int32_t constraint_flags = CONSTRAINT_DEFAULT; | ||
128 | char *constraint_command = NULL; | ||
129 | char *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 */ |
102 | int convert_to_ssh2 = 0; | 132 | int convert_to_ssh2 = 0; |
103 | int convert_from_ssh2 = 0; | 133 | int convert_from_ssh2 = 0; |
@@ -591,7 +621,7 @@ do_fingerprint(struct passwd *pw) | |||
591 | } | 621 | } |
592 | 622 | ||
593 | static void | 623 | static void |
594 | print_host(FILE *f, const char *name, Key *public, int hash) | 624 | printhost(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 | |||
622 | do_known_hosts(struct passwd *pw, const char *name) | 652 | do_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 | ||
1065 | static const char * | ||
1066 | fmt_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 | |||
1104 | static void | ||
1105 | add_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 | |||
1112 | static void | ||
1113 | add_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 | |||
1127 | static void | ||
1128 | prepare_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 | |||
1148 | static void | ||
1149 | do_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 | |||
1227 | static u_int64_t | ||
1228 | parse_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 | |||
1241 | static u_int64_t | ||
1242 | parse_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 | |||
1259 | static void | ||
1260 | parse_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 | |||
1305 | static void | ||
1306 | add_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 | |||
1015 | static void | 1352 | static void |
1016 | usage(void) | 1353 | usage(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) |