summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2017-07-07 03:53:12 +0000
committerDamien Miller <djm@mindrot.org>2017-07-21 14:17:32 +1000
commit853edbe057a84ebd0024c8003e4da21bf2b469f7 (patch)
tree2f7010fb3e1a780ba438b06753c1be99fab3abe9
parent43616876ba68a2ffaece6a6c792def4b039f2d6e (diff)
upstream commit
When generating all hostkeys (ssh-keygen -A), clobber existing keys if they exist but are zero length. zero-length keys could previously be made if ssh-keygen failed part way through generating them, so avoid that case too. bz#2561 reported by Krzysztof Cieplucha; ok dtucker@ Upstream-ID: f662201c28ab8e1f086b5d43c59cddab5ade4044
-rw-r--r--ssh-keygen.19
-rw-r--r--ssh-keygen.c106
2 files changed, 79 insertions, 36 deletions
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 66f8321c5..2bc61639a 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keygen.1,v 1.142 2017/06/28 01:09:22 djm Exp $ 1.\" $OpenBSD: ssh-keygen.1,v 1.143 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) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -35,7 +35,7 @@
35.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37.\" 37.\"
38.Dd $Mdocdate: June 28 2017 $ 38.Dd $Mdocdate: July 7 2017 $
39.Dt SSH-KEYGEN 1 39.Dt SSH-KEYGEN 1
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -126,6 +126,7 @@
126.Op Fl f Ar input_keyfile 126.Op Fl f Ar input_keyfile
127.Nm ssh-keygen 127.Nm ssh-keygen
128.Fl A 128.Fl A
129.Op Fl f Ar prefix_path
129.Nm ssh-keygen 130.Nm ssh-keygen
130.Fl k 131.Fl k
131.Fl f Ar krl_file 132.Fl f Ar krl_file
@@ -224,6 +225,10 @@ For each of the key types (rsa, dsa, ecdsa and ed25519)
224for which host keys 225for which host keys
225do not exist, generate the host keys with the default key file path, 226do not exist, generate the host keys with the default key file path,
226an empty passphrase, default bits for the key type, and default comment. 227an empty passphrase, default bits for the key type, and default comment.
228If a
229.Fl f
230option has been specified, then its argument is used as a prefix to the
231default path for the resulting host key files.
227This is used by 232This is used by
228.Pa /etc/rc 233.Pa /etc/rc
229to generate new host keys. 234to generate new host keys.
diff --git a/ssh-keygen.c b/ssh-keygen.c
index d8f942f5a..835f7d016 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.306 2017/07/01 13:50:45 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
@@ -997,20 +997,38 @@ do_gen_all_hostkeys(struct passwd *pw)
997 int first = 0; 997 int first = 0;
998 struct stat st; 998 struct stat st;
999 struct sshkey *private, *public; 999 struct sshkey *private, *public;
1000 char comment[1024]; 1000 char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file;
1001 int i, type, fd, r; 1001 int i, type, fd, r;
1002 FILE *f; 1002 FILE *f;
1003 1003
1004 for (i = 0; key_types[i].key_type; i++) { 1004 for (i = 0; key_types[i].key_type; i++) {
1005 if (stat(key_types[i].path, &st) == 0) 1005 public = private = NULL;
1006 continue; 1006 prv_tmp = pub_tmp = prv_file = pub_file = NULL;
1007 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) {
1008 error("Could not stat %s: %s", key_types[i].path, 1016 error("Could not stat %s: %s", key_types[i].path,
1009 strerror(errno)); 1017 strerror(errno));
1010 first = 0; 1018 goto failnext;
1011 continue;
1012 } 1019 }
1013 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
1014 if (first == 0) { 1032 if (first == 0) {
1015 first = 1; 1033 first = 1;
1016 printf("%s: generating new host keys: ", __progname); 1034 printf("%s: generating new host keys: ", __progname);
@@ -1018,56 +1036,76 @@ do_gen_all_hostkeys(struct passwd *pw)
1018 printf("%s ", key_types[i].key_type_display); 1036 printf("%s ", key_types[i].key_type_display);
1019 fflush(stdout); 1037 fflush(stdout);
1020 type = sshkey_type_from_name(key_types[i].key_type); 1038 type = sshkey_type_from_name(key_types[i].key_type);
1021 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 */
1022 bits = 0; 1045 bits = 0;
1023 type_bits_valid(type, NULL, &bits); 1046 type_bits_valid(type, NULL, &bits);
1024 if ((r = sshkey_generate(type, bits, &private)) != 0) { 1047 if ((r = sshkey_generate(type, bits, &private)) != 0) {
1025 error("sshkey_generate failed: %s", ssh_err(r)); 1048 error("sshkey_generate failed: %s", ssh_err(r));
1026 first = 0; 1049 goto failnext;
1027 continue;
1028 } 1050 }
1029 if ((r = sshkey_from_private(private, &public)) != 0) 1051 if ((r = sshkey_from_private(private, &public)) != 0)
1030 fatal("sshkey_from_private failed: %s", ssh_err(r)); 1052 fatal("sshkey_from_private failed: %s", ssh_err(r));
1031 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, 1053 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
1032 hostname); 1054 hostname);
1033 if ((r = sshkey_save_private(private, identity_file, "", 1055 if ((r = sshkey_save_private(private, prv_tmp, "",
1034 comment, use_new_format, new_format_cipher, rounds)) != 0) { 1056 comment, use_new_format, new_format_cipher, rounds)) != 0) {
1035 error("Saving key \"%s\" failed: %s", 1057 error("Saving key \"%s\" failed: %s",
1036 identity_file, ssh_err(r)); 1058 prv_tmp, ssh_err(r));
1037 sshkey_free(private); 1059 goto failnext;
1038 sshkey_free(public);
1039 first = 0;
1040 continue;
1041 } 1060 }
1042 sshkey_free(private); 1061 if ((fd = mkstemp(pub_tmp)) == -1) {
1043 strlcat(identity_file, ".pub", sizeof(identity_file)); 1062 error("Could not save your public key in %s: %s",
1044 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 1063 pub_tmp, strerror(errno));
1045 if (fd == -1) { 1064 goto failnext;
1046 error("Could not save your public key in %s",
1047 identity_file);
1048 sshkey_free(public);
1049 first = 0;
1050 continue;
1051 } 1065 }
1066 (void)fchmod(fd, 0644);
1052 f = fdopen(fd, "w"); 1067 f = fdopen(fd, "w");
1053 if (f == NULL) { 1068 if (f == NULL) {
1054 error("fdopen %s failed", identity_file); 1069 error("fdopen %s failed: %s", pub_tmp, strerror(errno));
1055 close(fd); 1070 close(fd);
1056 sshkey_free(public); 1071 goto failnext;
1057 first = 0;
1058 continue;
1059 } 1072 }
1060 if ((r = sshkey_write(public, f)) != 0) { 1073 if ((r = sshkey_write(public, f)) != 0) {
1061 error("write key failed: %s", ssh_err(r)); 1074 error("write key failed: %s", ssh_err(r));
1062 fclose(f); 1075 fclose(f);
1063 sshkey_free(public); 1076 goto failnext;
1064 first = 0;
1065 continue;
1066 } 1077 }
1067 fprintf(f, " %s\n", comment); 1078 fprintf(f, " %s\n", comment);
1068 fclose(f); 1079 if (ferror(f) != 0) {
1069 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 }
1070 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);
1071 } 1109 }
1072 if (first != 0) 1110 if (first != 0)
1073 printf("\n"); 1111 printf("\n");