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
This commit is contained in:
djm@openbsd.org 2017-07-07 03:53:12 +00:00 committed by Damien Miller
parent 43616876ba
commit 853edbe057
2 changed files with 79 additions and 36 deletions

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.142 2017/06/28 01:09:22 djm Exp $ .\" $OpenBSD: ssh-keygen.1,v 1.143 2017/07/07 03:53:12 djm Exp $
.\" .\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi> .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd $Mdocdate: June 28 2017 $ .Dd $Mdocdate: July 7 2017 $
.Dt SSH-KEYGEN 1 .Dt SSH-KEYGEN 1
.Os .Os
.Sh NAME .Sh NAME
@ -126,6 +126,7 @@
.Op Fl f Ar input_keyfile .Op Fl f Ar input_keyfile
.Nm ssh-keygen .Nm ssh-keygen
.Fl A .Fl A
.Op Fl f Ar prefix_path
.Nm ssh-keygen .Nm ssh-keygen
.Fl k .Fl k
.Fl f Ar krl_file .Fl f Ar krl_file
@ -224,6 +225,10 @@ For each of the key types (rsa, dsa, ecdsa and ed25519)
for which host keys for which host keys
do not exist, generate the host keys with the default key file path, do not exist, generate the host keys with the default key file path,
an empty passphrase, default bits for the key type, and default comment. an empty passphrase, default bits for the key type, and default comment.
If a
.Fl f
option has been specified, then its argument is used as a prefix to the
default path for the resulting host key files.
This is used by This is used by
.Pa /etc/rc .Pa /etc/rc
to generate new host keys. to generate new host keys.

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.306 2017/07/01 13:50:45 djm Exp $ */ /* $OpenBSD: ssh-keygen.c,v 1.307 2017/07/07 03:53:12 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -997,20 +997,38 @@ do_gen_all_hostkeys(struct passwd *pw)
int first = 0; int first = 0;
struct stat st; struct stat st;
struct sshkey *private, *public; struct sshkey *private, *public;
char comment[1024]; char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file;
int i, type, fd, r; int i, type, fd, r;
FILE *f; FILE *f;
for (i = 0; key_types[i].key_type; i++) { for (i = 0; key_types[i].key_type; i++) {
if (stat(key_types[i].path, &st) == 0) public = private = NULL;
continue; prv_tmp = pub_tmp = prv_file = pub_file = NULL;
if (errno != ENOENT) {
xasprintf(&prv_file, "%s%s",
identity_file, key_types[i].path);
/* Check whether private key exists and is not zero-length */
if (stat(prv_file, &st) == 0) {
if (st.st_size != 0)
goto next;
} else if (errno != ENOENT) {
error("Could not stat %s: %s", key_types[i].path, error("Could not stat %s: %s", key_types[i].path,
strerror(errno)); strerror(errno));
first = 0; goto failnext;
continue;
} }
/*
* Private key doesn't exist or is invalid; proceed with
* key generation.
*/
xasprintf(&prv_tmp, "%s%s.XXXXXXXXXX",
identity_file, key_types[i].path);
xasprintf(&pub_tmp, "%s%s.pub.XXXXXXXXXX",
identity_file, key_types[i].path);
xasprintf(&pub_file, "%s%s.pub",
identity_file, key_types[i].path);
if (first == 0) { if (first == 0) {
first = 1; first = 1;
printf("%s: generating new host keys: ", __progname); printf("%s: generating new host keys: ", __progname);
@ -1018,56 +1036,76 @@ do_gen_all_hostkeys(struct passwd *pw)
printf("%s ", key_types[i].key_type_display); printf("%s ", key_types[i].key_type_display);
fflush(stdout); fflush(stdout);
type = sshkey_type_from_name(key_types[i].key_type); type = sshkey_type_from_name(key_types[i].key_type);
strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); if ((fd = mkstemp(prv_tmp)) == -1) {
error("Could not save your public key in %s: %s",
prv_tmp, strerror(errno));
goto failnext;
}
close(fd); /* just using mkstemp() to generate/reserve a name */
bits = 0; bits = 0;
type_bits_valid(type, NULL, &bits); type_bits_valid(type, NULL, &bits);
if ((r = sshkey_generate(type, bits, &private)) != 0) { if ((r = sshkey_generate(type, bits, &private)) != 0) {
error("sshkey_generate failed: %s", ssh_err(r)); error("sshkey_generate failed: %s", ssh_err(r));
first = 0; goto failnext;
continue;
} }
if ((r = sshkey_from_private(private, &public)) != 0) if ((r = sshkey_from_private(private, &public)) != 0)
fatal("sshkey_from_private failed: %s", ssh_err(r)); fatal("sshkey_from_private failed: %s", ssh_err(r));
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
hostname); hostname);
if ((r = sshkey_save_private(private, identity_file, "", if ((r = sshkey_save_private(private, prv_tmp, "",
comment, use_new_format, new_format_cipher, rounds)) != 0) { comment, use_new_format, new_format_cipher, rounds)) != 0) {
error("Saving key \"%s\" failed: %s", error("Saving key \"%s\" failed: %s",
identity_file, ssh_err(r)); prv_tmp, ssh_err(r));
sshkey_free(private); goto failnext;
sshkey_free(public);
first = 0;
continue;
} }
sshkey_free(private); if ((fd = mkstemp(pub_tmp)) == -1) {
strlcat(identity_file, ".pub", sizeof(identity_file)); error("Could not save your public key in %s: %s",
fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); pub_tmp, strerror(errno));
if (fd == -1) { goto failnext;
error("Could not save your public key in %s",
identity_file);
sshkey_free(public);
first = 0;
continue;
} }
(void)fchmod(fd, 0644);
f = fdopen(fd, "w"); f = fdopen(fd, "w");
if (f == NULL) { if (f == NULL) {
error("fdopen %s failed", identity_file); error("fdopen %s failed: %s", pub_tmp, strerror(errno));
close(fd); close(fd);
sshkey_free(public); goto failnext;
first = 0;
continue;
} }
if ((r = sshkey_write(public, f)) != 0) { if ((r = sshkey_write(public, f)) != 0) {
error("write key failed: %s", ssh_err(r)); error("write key failed: %s", ssh_err(r));
fclose(f); fclose(f);
sshkey_free(public); goto failnext;
first = 0;
continue;
} }
fprintf(f, " %s\n", comment); fprintf(f, " %s\n", comment);
fclose(f); if (ferror(f) != 0) {
sshkey_free(public); error("write key failed: %s", strerror(errno));
fclose(f);
goto failnext;
}
if (fclose(f) != 0) {
error("key close failed: %s", strerror(errno));
goto failnext;
}
/* Rename temporary files to their permanent locations. */
if (rename(pub_tmp, pub_file) != 0) {
error("Unable to move %s into position: %s",
pub_file, strerror(errno));
goto failnext;
}
if (rename(prv_tmp, prv_file) != 0) {
error("Unable to move %s into position: %s",
key_types[i].path, strerror(errno));
failnext:
first = 0;
goto next;
}
next:
sshkey_free(private);
sshkey_free(public);
free(prv_tmp);
free(pub_tmp);
free(prv_file);
free(pub_file);
} }
if (first != 0) if (first != 0)
printf("\n"); printf("\n");