diff options
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 292 |
1 files changed, 203 insertions, 89 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c index f17af036b..835f7d016 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.299 2017/03/10 04:26:06 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.307 2017/07/07 03:53:12 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 |
@@ -41,7 +41,6 @@ | |||
41 | 41 | ||
42 | #include "xmalloc.h" | 42 | #include "xmalloc.h" |
43 | #include "sshkey.h" | 43 | #include "sshkey.h" |
44 | #include "rsa.h" | ||
45 | #include "authfile.h" | 44 | #include "authfile.h" |
46 | #include "uuencode.h" | 45 | #include "uuencode.h" |
47 | #include "sshbuf.h" | 46 | #include "sshbuf.h" |
@@ -59,6 +58,7 @@ | |||
59 | #include "krl.h" | 58 | #include "krl.h" |
60 | #include "digest.h" | 59 | #include "digest.h" |
61 | #include "utf8.h" | 60 | #include "utf8.h" |
61 | #include "authfd.h" | ||
62 | 62 | ||
63 | #ifdef WITH_OPENSSL | 63 | #ifdef WITH_OPENSSL |
64 | # define DEFAULT_KEY_TYPE_NAME "rsa" | 64 | # define DEFAULT_KEY_TYPE_NAME "rsa" |
@@ -121,6 +121,9 @@ char *identity_comment = NULL; | |||
121 | /* Path to CA key when certifying keys. */ | 121 | /* Path to CA key when certifying keys. */ |
122 | char *ca_key_path = NULL; | 122 | char *ca_key_path = NULL; |
123 | 123 | ||
124 | /* Prefer to use agent keys for CA signing */ | ||
125 | int prefer_agent = 0; | ||
126 | |||
124 | /* Certificate serial number */ | 127 | /* Certificate serial number */ |
125 | unsigned long long cert_serial = 0; | 128 | unsigned long long cert_serial = 0; |
126 | 129 | ||
@@ -149,6 +152,15 @@ u_int32_t certflags_flags = CERTOPT_DEFAULT; | |||
149 | char *certflags_command = NULL; | 152 | char *certflags_command = NULL; |
150 | char *certflags_src_addr = NULL; | 153 | char *certflags_src_addr = NULL; |
151 | 154 | ||
155 | /* Arbitrary extensions specified by user */ | ||
156 | struct cert_userext { | ||
157 | char *key; | ||
158 | char *val; | ||
159 | int crit; | ||
160 | }; | ||
161 | struct cert_userext *cert_userext; | ||
162 | size_t ncert_userext; | ||
163 | |||
152 | /* Conversion to/from various formats */ | 164 | /* Conversion to/from various formats */ |
153 | int convert_to = 0; | 165 | int convert_to = 0; |
154 | int convert_from = 0; | 166 | int convert_from = 0; |
@@ -217,13 +229,21 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp) | |||
217 | OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; | 229 | OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; |
218 | if (*bitsp > maxbits) | 230 | if (*bitsp > maxbits) |
219 | fatal("key bits exceeds maximum %d", maxbits); | 231 | fatal("key bits exceeds maximum %d", maxbits); |
220 | if (type == KEY_DSA && *bitsp != 1024) | 232 | switch (type) { |
221 | fatal("DSA keys must be 1024 bits"); | 233 | case KEY_DSA: |
222 | else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 1024) | 234 | if (*bitsp != 1024) |
223 | fatal("Key must at least be 1024 bits"); | 235 | fatal("Invalid DSA key length: must be 1024 bits"); |
224 | else if (type == KEY_ECDSA && sshkey_ecdsa_bits_to_nid(*bitsp) == -1) | 236 | break; |
225 | fatal("Invalid ECDSA key length - valid lengths are " | 237 | case KEY_RSA: |
226 | "256, 384 or 521 bits"); | 238 | if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE) |
239 | fatal("Invalid RSA key length: minimum is %d bits", | ||
240 | SSH_RSA_MINIMUM_MODULUS_SIZE); | ||
241 | break; | ||
242 | case KEY_ECDSA: | ||
243 | if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1) | ||
244 | fatal("Invalid ECDSA key length: valid lengths are " | ||
245 | "256, 384 or 521 bits"); | ||
246 | } | ||
227 | #endif | 247 | #endif |
228 | } | 248 | } |
229 | 249 | ||
@@ -237,9 +257,6 @@ ask_filename(struct passwd *pw, const char *prompt) | |||
237 | name = _PATH_SSH_CLIENT_ID_RSA; | 257 | name = _PATH_SSH_CLIENT_ID_RSA; |
238 | else { | 258 | else { |
239 | switch (sshkey_type_from_name(key_type_name)) { | 259 | switch (sshkey_type_from_name(key_type_name)) { |
240 | case KEY_RSA1: | ||
241 | name = _PATH_SSH_CLIENT_IDENTITY; | ||
242 | break; | ||
243 | case KEY_DSA_CERT: | 260 | case KEY_DSA_CERT: |
244 | case KEY_DSA: | 261 | case KEY_DSA: |
245 | name = _PATH_SSH_CLIENT_ID_DSA; | 262 | name = _PATH_SSH_CLIENT_ID_DSA; |
@@ -311,8 +328,6 @@ do_convert_to_ssh2(struct passwd *pw, struct sshkey *k) | |||
311 | char comment[61]; | 328 | char comment[61]; |
312 | int r; | 329 | int r; |
313 | 330 | ||
314 | if (k->type == KEY_RSA1) | ||
315 | fatal("version 1 keys are not supported"); | ||
316 | if ((r = sshkey_to_blob(k, &blob, &len)) != 0) | 331 | if ((r = sshkey_to_blob(k, &blob, &len)) != 0) |
317 | fatal("key_to_blob failed: %s", ssh_err(r)); | 332 | fatal("key_to_blob failed: %s", ssh_err(r)); |
318 | /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ | 333 | /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ |
@@ -334,7 +349,6 @@ static void | |||
334 | do_convert_to_pkcs8(struct sshkey *k) | 349 | do_convert_to_pkcs8(struct sshkey *k) |
335 | { | 350 | { |
336 | switch (sshkey_type_plain(k->type)) { | 351 | switch (sshkey_type_plain(k->type)) { |
337 | case KEY_RSA1: | ||
338 | case KEY_RSA: | 352 | case KEY_RSA: |
339 | if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) | 353 | if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) |
340 | fatal("PEM_write_RSA_PUBKEY failed"); | 354 | fatal("PEM_write_RSA_PUBKEY failed"); |
@@ -359,7 +373,6 @@ static void | |||
359 | do_convert_to_pem(struct sshkey *k) | 373 | do_convert_to_pem(struct sshkey *k) |
360 | { | 374 | { |
361 | switch (sshkey_type_plain(k->type)) { | 375 | switch (sshkey_type_plain(k->type)) { |
362 | case KEY_RSA1: | ||
363 | case KEY_RSA: | 376 | case KEY_RSA: |
364 | if (!PEM_write_RSAPublicKey(stdout, k->rsa)) | 377 | if (!PEM_write_RSAPublicKey(stdout, k->rsa)) |
365 | fatal("PEM_write_RSAPublicKey failed"); | 378 | fatal("PEM_write_RSAPublicKey failed"); |
@@ -478,7 +491,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
478 | return NULL; | 491 | return NULL; |
479 | } | 492 | } |
480 | if ((key = sshkey_new_private(ktype)) == NULL) | 493 | if ((key = sshkey_new_private(ktype)) == NULL) |
481 | fatal("key_new_private failed"); | 494 | fatal("sshkey_new_private failed"); |
482 | free(type); | 495 | free(type); |
483 | 496 | ||
484 | switch (key->type) { | 497 | switch (key->type) { |
@@ -514,7 +527,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
514 | buffer_get_bignum_bits(b, key->rsa->iqmp); | 527 | buffer_get_bignum_bits(b, key->rsa->iqmp); |
515 | buffer_get_bignum_bits(b, key->rsa->q); | 528 | buffer_get_bignum_bits(b, key->rsa->q); |
516 | buffer_get_bignum_bits(b, key->rsa->p); | 529 | buffer_get_bignum_bits(b, key->rsa->p); |
517 | if ((r = rsa_generate_additional_parameters(key->rsa)) != 0) | 530 | if ((r = ssh_rsa_generate_additional_parameters(key)) != 0) |
518 | fatal("generate RSA parameters failed: %s", ssh_err(r)); | 531 | fatal("generate RSA parameters failed: %s", ssh_err(r)); |
519 | break; | 532 | break; |
520 | } | 533 | } |
@@ -760,7 +773,7 @@ do_print_public(struct passwd *pw) | |||
760 | fatal("%s: %s", identity_file, strerror(errno)); | 773 | fatal("%s: %s", identity_file, strerror(errno)); |
761 | prv = load_identity(identity_file); | 774 | prv = load_identity(identity_file); |
762 | if ((r = sshkey_write(prv, stdout)) != 0) | 775 | if ((r = sshkey_write(prv, stdout)) != 0) |
763 | error("key_write failed: %s", ssh_err(r)); | 776 | error("sshkey_write failed: %s", ssh_err(r)); |
764 | sshkey_free(prv); | 777 | sshkey_free(prv); |
765 | fprintf(stdout, "\n"); | 778 | fprintf(stdout, "\n"); |
766 | exit(0); | 779 | exit(0); |
@@ -816,13 +829,6 @@ try_read_key(char **cpp) | |||
816 | struct sshkey *ret; | 829 | struct sshkey *ret; |
817 | int r; | 830 | int r; |
818 | 831 | ||
819 | if ((ret = sshkey_new(KEY_RSA1)) == NULL) | ||
820 | fatal("sshkey_new failed"); | ||
821 | /* Try RSA1 */ | ||
822 | if ((r = sshkey_read(ret, cpp)) == 0) | ||
823 | return ret; | ||
824 | /* Try modern */ | ||
825 | sshkey_free(ret); | ||
826 | if ((ret = sshkey_new(KEY_UNSPEC)) == NULL) | 832 | if ((ret = sshkey_new(KEY_UNSPEC)) == NULL) |
827 | fatal("sshkey_new failed"); | 833 | fatal("sshkey_new failed"); |
828 | if ((r = sshkey_read(ret, cpp)) == 0) | 834 | if ((r = sshkey_read(ret, cpp)) == 0) |
@@ -978,9 +984,6 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
978 | char *path; | 984 | char *path; |
979 | } key_types[] = { | 985 | } key_types[] = { |
980 | #ifdef WITH_OPENSSL | 986 | #ifdef WITH_OPENSSL |
981 | #ifdef WITH_SSH1 | ||
982 | { "rsa1", "RSA1", _PATH_HOST_KEY_FILE }, | ||
983 | #endif /* WITH_SSH1 */ | ||
984 | { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, | 987 | { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, |
985 | { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, | 988 | { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, |
986 | #ifdef OPENSSL_HAS_ECC | 989 | #ifdef OPENSSL_HAS_ECC |
@@ -994,20 +997,38 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
994 | int first = 0; | 997 | int first = 0; |
995 | struct stat st; | 998 | struct stat st; |
996 | struct sshkey *private, *public; | 999 | struct sshkey *private, *public; |
997 | char comment[1024]; | 1000 | char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file; |
998 | int i, type, fd, r; | 1001 | int i, type, fd, r; |
999 | FILE *f; | 1002 | FILE *f; |
1000 | 1003 | ||
1001 | for (i = 0; key_types[i].key_type; i++) { | 1004 | for (i = 0; key_types[i].key_type; i++) { |
1002 | if (stat(key_types[i].path, &st) == 0) | 1005 | public = private = NULL; |
1003 | continue; | 1006 | prv_tmp = pub_tmp = prv_file = pub_file = NULL; |
1004 | if (errno != ENOENT) { | 1007 | |
1008 | xasprintf(&prv_file, "%s%s", | ||
1009 | identity_file, key_types[i].path); | ||
1010 | |||
1011 | /* Check whether private key exists and is not zero-length */ | ||
1012 | if (stat(prv_file, &st) == 0) { | ||
1013 | if (st.st_size != 0) | ||
1014 | goto next; | ||
1015 | } else if (errno != ENOENT) { | ||
1005 | error("Could not stat %s: %s", key_types[i].path, | 1016 | error("Could not stat %s: %s", key_types[i].path, |
1006 | strerror(errno)); | 1017 | strerror(errno)); |
1007 | first = 0; | 1018 | goto failnext; |
1008 | continue; | ||
1009 | } | 1019 | } |
1010 | 1020 | ||
1021 | /* | ||
1022 | * Private key doesn't exist or is invalid; proceed with | ||
1023 | * key generation. | ||
1024 | */ | ||
1025 | xasprintf(&prv_tmp, "%s%s.XXXXXXXXXX", | ||
1026 | identity_file, key_types[i].path); | ||
1027 | xasprintf(&pub_tmp, "%s%s.pub.XXXXXXXXXX", | ||
1028 | identity_file, key_types[i].path); | ||
1029 | xasprintf(&pub_file, "%s%s.pub", | ||
1030 | identity_file, key_types[i].path); | ||
1031 | |||
1011 | if (first == 0) { | 1032 | if (first == 0) { |
1012 | first = 1; | 1033 | first = 1; |
1013 | printf("%s: generating new host keys: ", __progname); | 1034 | printf("%s: generating new host keys: ", __progname); |
@@ -1015,56 +1036,76 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
1015 | printf("%s ", key_types[i].key_type_display); | 1036 | printf("%s ", key_types[i].key_type_display); |
1016 | fflush(stdout); | 1037 | fflush(stdout); |
1017 | type = sshkey_type_from_name(key_types[i].key_type); | 1038 | type = sshkey_type_from_name(key_types[i].key_type); |
1018 | strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); | 1039 | if ((fd = mkstemp(prv_tmp)) == -1) { |
1040 | error("Could not save your public key in %s: %s", | ||
1041 | prv_tmp, strerror(errno)); | ||
1042 | goto failnext; | ||
1043 | } | ||
1044 | close(fd); /* just using mkstemp() to generate/reserve a name */ | ||
1019 | bits = 0; | 1045 | bits = 0; |
1020 | type_bits_valid(type, NULL, &bits); | 1046 | type_bits_valid(type, NULL, &bits); |
1021 | if ((r = sshkey_generate(type, bits, &private)) != 0) { | 1047 | if ((r = sshkey_generate(type, bits, &private)) != 0) { |
1022 | error("key_generate failed: %s", ssh_err(r)); | 1048 | error("sshkey_generate failed: %s", ssh_err(r)); |
1023 | first = 0; | 1049 | goto failnext; |
1024 | continue; | ||
1025 | } | 1050 | } |
1026 | if ((r = sshkey_from_private(private, &public)) != 0) | 1051 | if ((r = sshkey_from_private(private, &public)) != 0) |
1027 | fatal("sshkey_from_private failed: %s", ssh_err(r)); | 1052 | fatal("sshkey_from_private failed: %s", ssh_err(r)); |
1028 | snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, | 1053 | snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, |
1029 | hostname); | 1054 | hostname); |
1030 | if ((r = sshkey_save_private(private, identity_file, "", | 1055 | if ((r = sshkey_save_private(private, prv_tmp, "", |
1031 | comment, use_new_format, new_format_cipher, rounds)) != 0) { | 1056 | comment, use_new_format, new_format_cipher, rounds)) != 0) { |
1032 | error("Saving key \"%s\" failed: %s", | 1057 | error("Saving key \"%s\" failed: %s", |
1033 | identity_file, ssh_err(r)); | 1058 | prv_tmp, ssh_err(r)); |
1034 | sshkey_free(private); | 1059 | goto failnext; |
1035 | sshkey_free(public); | ||
1036 | first = 0; | ||
1037 | continue; | ||
1038 | } | 1060 | } |
1039 | sshkey_free(private); | 1061 | if ((fd = mkstemp(pub_tmp)) == -1) { |
1040 | strlcat(identity_file, ".pub", sizeof(identity_file)); | 1062 | error("Could not save your public key in %s: %s", |
1041 | fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); | 1063 | pub_tmp, strerror(errno)); |
1042 | if (fd == -1) { | 1064 | goto failnext; |
1043 | error("Could not save your public key in %s", | ||
1044 | identity_file); | ||
1045 | sshkey_free(public); | ||
1046 | first = 0; | ||
1047 | continue; | ||
1048 | } | 1065 | } |
1066 | (void)fchmod(fd, 0644); | ||
1049 | f = fdopen(fd, "w"); | 1067 | f = fdopen(fd, "w"); |
1050 | if (f == NULL) { | 1068 | if (f == NULL) { |
1051 | error("fdopen %s failed", identity_file); | 1069 | error("fdopen %s failed: %s", pub_tmp, strerror(errno)); |
1052 | close(fd); | 1070 | close(fd); |
1053 | sshkey_free(public); | 1071 | goto failnext; |
1054 | first = 0; | ||
1055 | continue; | ||
1056 | } | 1072 | } |
1057 | if ((r = sshkey_write(public, f)) != 0) { | 1073 | if ((r = sshkey_write(public, f)) != 0) { |
1058 | error("write key failed: %s", ssh_err(r)); | 1074 | error("write key failed: %s", ssh_err(r)); |
1059 | fclose(f); | 1075 | fclose(f); |
1060 | sshkey_free(public); | 1076 | goto failnext; |
1061 | first = 0; | ||
1062 | continue; | ||
1063 | } | 1077 | } |
1064 | fprintf(f, " %s\n", comment); | 1078 | fprintf(f, " %s\n", comment); |
1065 | fclose(f); | 1079 | if (ferror(f) != 0) { |
1066 | sshkey_free(public); | 1080 | error("write key failed: %s", strerror(errno)); |
1081 | fclose(f); | ||
1082 | goto failnext; | ||
1083 | } | ||
1084 | if (fclose(f) != 0) { | ||
1085 | error("key close failed: %s", strerror(errno)); | ||
1086 | goto failnext; | ||
1087 | } | ||
1067 | 1088 | ||
1089 | /* Rename temporary files to their permanent locations. */ | ||
1090 | if (rename(pub_tmp, pub_file) != 0) { | ||
1091 | error("Unable to move %s into position: %s", | ||
1092 | pub_file, strerror(errno)); | ||
1093 | goto failnext; | ||
1094 | } | ||
1095 | if (rename(prv_tmp, prv_file) != 0) { | ||
1096 | error("Unable to move %s into position: %s", | ||
1097 | key_types[i].path, strerror(errno)); | ||
1098 | failnext: | ||
1099 | first = 0; | ||
1100 | goto next; | ||
1101 | } | ||
1102 | next: | ||
1103 | sshkey_free(private); | ||
1104 | sshkey_free(public); | ||
1105 | free(prv_tmp); | ||
1106 | free(pub_tmp); | ||
1107 | free(prv_file); | ||
1108 | free(pub_file); | ||
1068 | } | 1109 | } |
1069 | if (first != 0) | 1110 | if (first != 0) |
1070 | printf("\n"); | 1111 | printf("\n"); |
@@ -1436,9 +1477,8 @@ do_change_comment(struct passwd *pw) | |||
1436 | } | 1477 | } |
1437 | } | 1478 | } |
1438 | 1479 | ||
1439 | if (private->type != KEY_RSA1 && private->type != KEY_ED25519 && | 1480 | if (private->type != KEY_ED25519 && !use_new_format) { |
1440 | !use_new_format) { | 1481 | error("Comments are only supported for keys stored in " |
1441 | error("Comments are only supported for RSA1 or keys stored in " | ||
1442 | "the new format (-o)."); | 1482 | "the new format (-o)."); |
1443 | explicit_bzero(passphrase, strlen(passphrase)); | 1483 | explicit_bzero(passphrase, strlen(passphrase)); |
1444 | sshkey_free(private); | 1484 | sshkey_free(private); |
@@ -1476,7 +1516,7 @@ do_change_comment(struct passwd *pw) | |||
1476 | explicit_bzero(passphrase, strlen(passphrase)); | 1516 | explicit_bzero(passphrase, strlen(passphrase)); |
1477 | free(passphrase); | 1517 | free(passphrase); |
1478 | if ((r = sshkey_from_private(private, &public)) != 0) | 1518 | if ((r = sshkey_from_private(private, &public)) != 0) |
1479 | fatal("key_from_private failed: %s", ssh_err(r)); | 1519 | fatal("sshkey_from_private failed: %s", ssh_err(r)); |
1480 | sshkey_free(private); | 1520 | sshkey_free(private); |
1481 | 1521 | ||
1482 | strlcat(identity_file, ".pub", sizeof(identity_file)); | 1522 | strlcat(identity_file, ".pub", sizeof(identity_file)); |
@@ -1531,6 +1571,8 @@ add_string_option(struct sshbuf *c, const char *name, const char *value) | |||
1531 | static void | 1571 | static void |
1532 | prepare_options_buf(struct sshbuf *c, int which) | 1572 | prepare_options_buf(struct sshbuf *c, int which) |
1533 | { | 1573 | { |
1574 | size_t i; | ||
1575 | |||
1534 | sshbuf_reset(c); | 1576 | sshbuf_reset(c); |
1535 | if ((which & OPTIONS_CRITICAL) != 0 && | 1577 | if ((which & OPTIONS_CRITICAL) != 0 && |
1536 | certflags_command != NULL) | 1578 | certflags_command != NULL) |
@@ -1553,6 +1595,17 @@ prepare_options_buf(struct sshbuf *c, int which) | |||
1553 | if ((which & OPTIONS_CRITICAL) != 0 && | 1595 | if ((which & OPTIONS_CRITICAL) != 0 && |
1554 | certflags_src_addr != NULL) | 1596 | certflags_src_addr != NULL) |
1555 | add_string_option(c, "source-address", certflags_src_addr); | 1597 | add_string_option(c, "source-address", certflags_src_addr); |
1598 | for (i = 0; i < ncert_userext; i++) { | ||
1599 | if ((cert_userext[i].crit && (which & OPTIONS_EXTENSIONS)) || | ||
1600 | (!cert_userext[i].crit && (which & OPTIONS_CRITICAL))) | ||
1601 | continue; | ||
1602 | if (cert_userext[i].val == NULL) | ||
1603 | add_flag_option(c, cert_userext[i].key); | ||
1604 | else { | ||
1605 | add_string_option(c, cert_userext[i].key, | ||
1606 | cert_userext[i].val); | ||
1607 | } | ||
1608 | } | ||
1556 | } | 1609 | } |
1557 | 1610 | ||
1558 | static struct sshkey * | 1611 | static struct sshkey * |
@@ -1585,24 +1638,66 @@ load_pkcs11_key(char *path) | |||
1585 | #endif /* ENABLE_PKCS11 */ | 1638 | #endif /* ENABLE_PKCS11 */ |
1586 | } | 1639 | } |
1587 | 1640 | ||
1641 | /* Signer for sshkey_certify_custom that uses the agent */ | ||
1642 | static int | ||
1643 | agent_signer(const struct sshkey *key, u_char **sigp, size_t *lenp, | ||
1644 | const u_char *data, size_t datalen, | ||
1645 | const char *alg, u_int compat, void *ctx) | ||
1646 | { | ||
1647 | int *agent_fdp = (int *)ctx; | ||
1648 | |||
1649 | return ssh_agent_sign(*agent_fdp, key, sigp, lenp, | ||
1650 | data, datalen, alg, compat); | ||
1651 | } | ||
1652 | |||
1588 | static void | 1653 | static void |
1589 | do_ca_sign(struct passwd *pw, int argc, char **argv) | 1654 | do_ca_sign(struct passwd *pw, int argc, char **argv) |
1590 | { | 1655 | { |
1591 | int r, i, fd; | 1656 | int r, i, fd, found, agent_fd = -1; |
1592 | u_int n; | 1657 | u_int n; |
1593 | struct sshkey *ca, *public; | 1658 | struct sshkey *ca, *public; |
1594 | char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; | 1659 | char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; |
1595 | FILE *f; | 1660 | FILE *f; |
1661 | struct ssh_identitylist *agent_ids; | ||
1662 | size_t j; | ||
1596 | 1663 | ||
1597 | #ifdef ENABLE_PKCS11 | 1664 | #ifdef ENABLE_PKCS11 |
1598 | pkcs11_init(1); | 1665 | pkcs11_init(1); |
1599 | #endif | 1666 | #endif |
1600 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); | 1667 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); |
1601 | if (pkcs11provider != NULL) { | 1668 | if (pkcs11provider != NULL) { |
1669 | /* If a PKCS#11 token was specified then try to use it */ | ||
1602 | if ((ca = load_pkcs11_key(tmp)) == NULL) | 1670 | if ((ca = load_pkcs11_key(tmp)) == NULL) |
1603 | fatal("No PKCS#11 key matching %s found", ca_key_path); | 1671 | fatal("No PKCS#11 key matching %s found", ca_key_path); |
1604 | } else | 1672 | } else if (prefer_agent) { |
1673 | /* | ||
1674 | * Agent signature requested. Try to use agent after making | ||
1675 | * sure the public key specified is actually present in the | ||
1676 | * agent. | ||
1677 | */ | ||
1678 | if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) | ||
1679 | fatal("Cannot load CA public key %s: %s", | ||
1680 | tmp, ssh_err(r)); | ||
1681 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) | ||
1682 | fatal("Cannot use public key for CA signature: %s", | ||
1683 | ssh_err(r)); | ||
1684 | if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0) | ||
1685 | fatal("Retrieve agent key list: %s", ssh_err(r)); | ||
1686 | found = 0; | ||
1687 | for (j = 0; j < agent_ids->nkeys; j++) { | ||
1688 | if (sshkey_equal(ca, agent_ids->keys[j])) { | ||
1689 | found = 1; | ||
1690 | break; | ||
1691 | } | ||
1692 | } | ||
1693 | if (!found) | ||
1694 | fatal("CA key %s not found in agent", tmp); | ||
1695 | ssh_free_identitylist(agent_ids); | ||
1696 | ca->flags |= SSHKEY_FLAG_EXT; | ||
1697 | } else { | ||
1698 | /* CA key is assumed to be a private key on the filesystem */ | ||
1605 | ca = load_identity(tmp); | 1699 | ca = load_identity(tmp); |
1700 | } | ||
1606 | free(tmp); | 1701 | free(tmp); |
1607 | 1702 | ||
1608 | if (key_type_name != NULL && | 1703 | if (key_type_name != NULL && |
@@ -1650,10 +1745,18 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) | |||
1650 | OPTIONS_EXTENSIONS); | 1745 | OPTIONS_EXTENSIONS); |
1651 | if ((r = sshkey_from_private(ca, | 1746 | if ((r = sshkey_from_private(ca, |
1652 | &public->cert->signature_key)) != 0) | 1747 | &public->cert->signature_key)) != 0) |
1653 | fatal("key_from_private (ca key): %s", ssh_err(r)); | 1748 | fatal("sshkey_from_private (ca key): %s", ssh_err(r)); |
1654 | 1749 | ||
1655 | if ((r = sshkey_certify(public, ca, key_type_name)) != 0) | 1750 | if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { |
1656 | fatal("Couldn't certify key %s: %s", tmp, ssh_err(r)); | 1751 | if ((r = sshkey_certify_custom(public, ca, |
1752 | key_type_name, agent_signer, &agent_fd)) != 0) | ||
1753 | fatal("Couldn't certify key %s via agent: %s", | ||
1754 | tmp, ssh_err(r)); | ||
1755 | } else { | ||
1756 | if ((sshkey_certify(public, ca, key_type_name)) != 0) | ||
1757 | fatal("Couldn't certify key %s: %s", | ||
1758 | tmp, ssh_err(r)); | ||
1759 | } | ||
1657 | 1760 | ||
1658 | if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) | 1761 | if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) |
1659 | *cp = '\0'; | 1762 | *cp = '\0'; |
@@ -1789,7 +1892,8 @@ parse_cert_times(char *timespec) | |||
1789 | static void | 1892 | static void |
1790 | add_cert_option(char *opt) | 1893 | add_cert_option(char *opt) |
1791 | { | 1894 | { |
1792 | char *val; | 1895 | char *val, *cp; |
1896 | int iscrit = 0; | ||
1793 | 1897 | ||
1794 | if (strcasecmp(opt, "clear") == 0) | 1898 | if (strcasecmp(opt, "clear") == 0) |
1795 | certflags_flags = 0; | 1899 | certflags_flags = 0; |
@@ -1829,6 +1933,18 @@ add_cert_option(char *opt) | |||
1829 | if (addr_match_cidr_list(NULL, val) != 0) | 1933 | if (addr_match_cidr_list(NULL, val) != 0) |
1830 | fatal("Invalid source-address list"); | 1934 | fatal("Invalid source-address list"); |
1831 | certflags_src_addr = xstrdup(val); | 1935 | certflags_src_addr = xstrdup(val); |
1936 | } else if (strncasecmp(opt, "extension:", 10) == 0 || | ||
1937 | (iscrit = (strncasecmp(opt, "critical:", 9) == 0))) { | ||
1938 | val = xstrdup(strchr(opt, ':') + 1); | ||
1939 | if ((cp = strchr(val, '=')) != NULL) | ||
1940 | *cp++ = '\0'; | ||
1941 | cert_userext = xreallocarray(cert_userext, ncert_userext + 1, | ||
1942 | sizeof(*cert_userext)); | ||
1943 | cert_userext[ncert_userext].key = val; | ||
1944 | cert_userext[ncert_userext].val = cp == NULL ? | ||
1945 | NULL : xstrdup(cp); | ||
1946 | cert_userext[ncert_userext].crit = iscrit; | ||
1947 | ncert_userext++; | ||
1832 | } else | 1948 | } else |
1833 | fatal("Unsupported certificate option \"%s\"", opt); | 1949 | fatal("Unsupported certificate option \"%s\"", opt); |
1834 | } | 1950 | } |
@@ -1955,7 +2071,7 @@ do_show_cert(struct passwd *pw) | |||
1955 | if (*cp == '#' || *cp == '\0') | 2071 | if (*cp == '#' || *cp == '\0') |
1956 | continue; | 2072 | continue; |
1957 | if ((key = sshkey_new(KEY_UNSPEC)) == NULL) | 2073 | if ((key = sshkey_new(KEY_UNSPEC)) == NULL) |
1958 | fatal("key_new"); | 2074 | fatal("sshkey_new"); |
1959 | if ((r = sshkey_read(key, &cp)) != 0) { | 2075 | if ((r = sshkey_read(key, &cp)) != 0) { |
1960 | error("%s:%lu: invalid key: %s", path, | 2076 | error("%s:%lu: invalid key: %s", path, |
1961 | lnum, ssh_err(r)); | 2077 | lnum, ssh_err(r)); |
@@ -2101,7 +2217,7 @@ update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, | |||
2101 | */ | 2217 | */ |
2102 | } | 2218 | } |
2103 | if ((key = sshkey_new(KEY_UNSPEC)) == NULL) | 2219 | if ((key = sshkey_new(KEY_UNSPEC)) == NULL) |
2104 | fatal("key_new"); | 2220 | fatal("sshkey_new"); |
2105 | if ((r = sshkey_read(key, &cp)) != 0) | 2221 | if ((r = sshkey_read(key, &cp)) != 0) |
2106 | fatal("%s:%lu: invalid key: %s", | 2222 | fatal("%s:%lu: invalid key: %s", |
2107 | path, lnum, ssh_err(r)); | 2223 | path, lnum, ssh_err(r)); |
@@ -2209,17 +2325,11 @@ do_check_krl(struct passwd *pw, int argc, char **argv) | |||
2209 | exit(ret); | 2325 | exit(ret); |
2210 | } | 2326 | } |
2211 | 2327 | ||
2212 | #ifdef WITH_SSH1 | ||
2213 | # define RSA1_USAGE " | rsa1" | ||
2214 | #else | ||
2215 | # define RSA1_USAGE "" | ||
2216 | #endif | ||
2217 | |||
2218 | static void | 2328 | static void |
2219 | usage(void) | 2329 | usage(void) |
2220 | { | 2330 | { |
2221 | fprintf(stderr, | 2331 | fprintf(stderr, |
2222 | "usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa%s]\n" | 2332 | "usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa]\n" |
2223 | " [-N new_passphrase] [-C comment] [-f output_keyfile]\n" | 2333 | " [-N new_passphrase] [-C comment] [-f output_keyfile]\n" |
2224 | " ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]\n" | 2334 | " ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]\n" |
2225 | " ssh-keygen -i [-m key_format] [-f input_keyfile]\n" | 2335 | " ssh-keygen -i [-m key_format] [-f input_keyfile]\n" |
@@ -2227,7 +2337,7 @@ usage(void) | |||
2227 | " ssh-keygen -y [-f input_keyfile]\n" | 2337 | " ssh-keygen -y [-f input_keyfile]\n" |
2228 | " ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" | 2338 | " ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" |
2229 | " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n" | 2339 | " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n" |
2230 | " ssh-keygen -B [-f input_keyfile]\n", RSA1_USAGE); | 2340 | " ssh-keygen -B [-f input_keyfile]\n"); |
2231 | #ifdef ENABLE_PKCS11 | 2341 | #ifdef ENABLE_PKCS11 |
2232 | fprintf(stderr, | 2342 | fprintf(stderr, |
2233 | " ssh-keygen -D pkcs11\n"); | 2343 | " ssh-keygen -D pkcs11\n"); |
@@ -2242,8 +2352,9 @@ usage(void) | |||
2242 | " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" | 2352 | " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" |
2243 | " [-j start_line] [-K checkpt] [-W generator]\n" | 2353 | " [-j start_line] [-K checkpt] [-W generator]\n" |
2244 | #endif | 2354 | #endif |
2245 | " ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]\n" | 2355 | " ssh-keygen -s ca_key -I certificate_identity [-h] [-U]\n" |
2246 | " [-O option] [-V validity_interval] [-z serial_number] file ...\n" | 2356 | " [-D pkcs11_provider] [-n principals] [-O option]\n" |
2357 | " [-V validity_interval] [-z serial_number] file ...\n" | ||
2247 | " ssh-keygen -L [-f input_keyfile]\n" | 2358 | " ssh-keygen -L [-f input_keyfile]\n" |
2248 | " ssh-keygen -A\n" | 2359 | " ssh-keygen -A\n" |
2249 | " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" | 2360 | " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" |
@@ -2301,8 +2412,8 @@ main(int argc, char **argv) | |||
2301 | if (gethostname(hostname, sizeof(hostname)) < 0) | 2412 | if (gethostname(hostname, sizeof(hostname)) < 0) |
2302 | fatal("gethostname: %s", strerror(errno)); | 2413 | fatal("gethostname: %s", strerror(errno)); |
2303 | 2414 | ||
2304 | /* Remaining characters: UYdw */ | 2415 | /* Remaining characters: Ydw */ |
2305 | while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" | 2416 | while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvxy" |
2306 | "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" | 2417 | "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" |
2307 | "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { | 2418 | "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { |
2308 | switch (opt) { | 2419 | switch (opt) { |
@@ -2429,6 +2540,9 @@ main(int argc, char **argv) | |||
2429 | case 'D': | 2540 | case 'D': |
2430 | pkcs11provider = optarg; | 2541 | pkcs11provider = optarg; |
2431 | break; | 2542 | break; |
2543 | case 'U': | ||
2544 | prefer_agent = 1; | ||
2545 | break; | ||
2432 | case 'u': | 2546 | case 'u': |
2433 | update_krl = 1; | 2547 | update_krl = 1; |
2434 | break; | 2548 | break; |
@@ -2648,9 +2762,9 @@ main(int argc, char **argv) | |||
2648 | printf("Generating public/private %s key pair.\n", | 2762 | printf("Generating public/private %s key pair.\n", |
2649 | key_type_name); | 2763 | key_type_name); |
2650 | if ((r = sshkey_generate(type, bits, &private)) != 0) | 2764 | if ((r = sshkey_generate(type, bits, &private)) != 0) |
2651 | fatal("key_generate failed"); | 2765 | fatal("sshkey_generate failed"); |
2652 | if ((r = sshkey_from_private(private, &public)) != 0) | 2766 | if ((r = sshkey_from_private(private, &public)) != 0) |
2653 | fatal("key_from_private failed: %s\n", ssh_err(r)); | 2767 | fatal("sshkey_from_private failed: %s\n", ssh_err(r)); |
2654 | 2768 | ||
2655 | if (!have_identity) | 2769 | if (!have_identity) |
2656 | ask_filename(pw, "Enter file in which to save the key"); | 2770 | ask_filename(pw, "Enter file in which to save the key"); |