[PATCH 2/2] Keep number of rounds when changing passphrase or comment in private keep file
Loïc
loic at venez.fr
Fri Apr 10 00:08:45 AEST 2020
---
authfile.c | 16 ++++++++-------
authfile.h | 7 ++++---
ssh-keygen.c | 24 +++++++++++++++-------
ssh-keysign.c | 2 +-
sshconnect2.c | 2 +-
sshd.c | 2 +-
sshkey.c | 55 ++++++++++++++++++++++++++++++++++++++++++++-------
sshkey.h | 10 +++++++++-
8 files changed, 90 insertions(+), 28 deletions(-)
diff --git a/authfile.c b/authfile.c
index 6867c326d8f0..fbdc7103e8e9 100644
--- a/authfile.c
+++ b/authfile.c
@@ -116,7 +116,7 @@ sshkey_perm_ok(int fd, const char *filename)
int
sshkey_load_private_type(int type, const char *filename, const char *passphrase,
- struct sshkey **keyp, char **commentp)
+ struct sshkey **keyp, char **commentp, struct sshkey_vault **vault_infop)
{
int fd, r;
@@ -124,6 +124,8 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase,
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
+ if (vault_infop != NULL)
+ *vault_infop = NULL;
if ((fd = open(filename, O_RDONLY)) == -1)
return SSH_ERR_SYSTEM_ERROR;
@@ -132,7 +134,7 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase,
if (r != 0)
goto out;
- r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
+ r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp, vault_infop);
if (r == 0 && keyp && *keyp)
r = sshkey_set_filename(*keyp, filename);
out:
@@ -142,7 +144,7 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase,
int
sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
- struct sshkey **keyp, char **commentp)
+ struct sshkey **keyp, char **commentp, struct sshkey_vault **vault_infop)
{
struct sshbuf *buffer = NULL;
int r;
@@ -151,7 +153,7 @@ sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
*keyp = NULL;
if ((r = sshbuf_load_fd(fd, &buffer)) != 0 ||
(r = sshkey_parse_private_fileblob_type(buffer, type,
- passphrase, keyp, commentp)) != 0)
+ passphrase, keyp, commentp, vault_infop)) != 0)
goto out;
/* success */
@@ -164,9 +166,9 @@ sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
/* This is identical to sshkey_load_private_type() with KEY_UNSPEC as type */
int
sshkey_load_private(const char *filename, const char *passphrase,
- struct sshkey **keyp, char **commentp)
+ struct sshkey **keyp, char **commentp, struct sshkey_vault **vault_infop)
{
- return sshkey_load_private_type(KEY_UNSPEC, filename, passphrase, keyp, commentp);;
+ return sshkey_load_private_type(KEY_UNSPEC, filename, passphrase, keyp, commentp, vault_infop);;
}
/* Load a pubkey from the unencrypted envelope of a new-format private key */
@@ -334,7 +336,7 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
}
if ((r = sshkey_load_private_type(type, filename,
- passphrase, &key, NULL)) != 0 ||
+ passphrase, &key, NULL, NULL)) != 0 ||
(r = sshkey_load_cert(filename, &cert)) != 0)
goto out;
diff --git a/authfile.h b/authfile.h
index 1db067a813a1..85f78ac78edf 100644
--- a/authfile.h
+++ b/authfile.h
@@ -29,6 +29,7 @@
struct sshbuf;
struct sshkey;
+struct sshkey_vault;
/* XXX document these */
/* XXX some of these could probably be merged/retired */
@@ -37,13 +38,13 @@ int sshkey_save_private(struct sshkey *, const char *,
const char *, const char *, int, const char *, int);
int sshkey_load_cert(const char *, struct sshkey **);
int sshkey_load_public(const char *, struct sshkey **, char **);
-int sshkey_load_private(const char *, const char *, struct sshkey **, char **);
+int sshkey_load_private(const char *, const char *, struct sshkey **, char **, struct sshkey_vault **);
int sshkey_load_private_cert(int, const char *, const char *,
struct sshkey **);
int sshkey_load_private_type(int, const char *, const char *,
- struct sshkey **, char **);
+ struct sshkey **, char **, struct sshkey_vault **);
int sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
- struct sshkey **keyp, char **commentp);
+ struct sshkey **keyp, char **commentp, struct sshkey_vault **vault_infop);
int sshkey_perm_ok(int, const char *);
int sshkey_in_file(struct sshkey *, const char *, int, int);
int sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file);
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 802fd25c286f..134b01cc53c7 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -318,7 +318,7 @@ load_identity(const char *filename, char **commentp)
if (commentp != NULL)
*commentp = NULL;
- if ((r = sshkey_load_private(filename, "", &prv, commentp)) == 0)
+ if ((r = sshkey_load_private(filename, "", &prv, commentp, NULL)) == 0)
return prv;
if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal("Load key \"%s\": %s", filename, ssh_err(r));
@@ -326,7 +326,7 @@ load_identity(const char *filename, char **commentp)
pass = xstrdup(identity_passphrase);
else
pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN);
- r = sshkey_load_private(filename, pass, &prv, commentp);
+ r = sshkey_load_private(filename, pass, &prv, commentp, NULL);
freezero(pass, strlen(pass));
if (r != 0)
fatal("Load key \"%s\": %s", filename, ssh_err(r));
@@ -918,7 +918,7 @@ fingerprint_private(const char *path)
if ((r = sshkey_load_public(path, &public, &comment)) != 0) {
debug("load public \"%s\": %s", path, ssh_err(r));
if ((r = sshkey_load_private(path, NULL,
- &public, &comment)) != 0) {
+ &public, &comment, NULL)) != 0) {
debug("load private \"%s\": %s", path, ssh_err(r));
fatal("%s is not a key file.", path);
}
@@ -1406,6 +1406,7 @@ do_change_passphrase(struct passwd *pw)
char *old_passphrase, *passphrase1, *passphrase2;
struct stat st;
struct sshkey *private;
+ struct sshkey_vault *vault_info;
int r;
if (!have_identity)
@@ -1413,7 +1414,7 @@ do_change_passphrase(struct passwd *pw)
if (stat(identity_file, &st) == -1)
fatal("%s: %s", identity_file, strerror(errno));
/* Try to load the file with empty passphrase. */
- r = sshkey_load_private(identity_file, "", &private, &comment);
+ r = sshkey_load_private(identity_file, "", &private, &comment, &vault_info);
if (r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase);
@@ -1422,7 +1423,7 @@ do_change_passphrase(struct passwd *pw)
read_passphrase("Enter old passphrase: ",
RP_ALLOW_STDIN);
r = sshkey_load_private(identity_file, old_passphrase,
- &private, &comment);
+ &private, &comment, &vault_info);
freezero(old_passphrase, strlen(old_passphrase));
if (r != 0)
goto badkey;
@@ -1457,6 +1458,10 @@ do_change_passphrase(struct passwd *pw)
freezero(passphrase2, strlen(passphrase2));
}
+ if (vault_info != NULL && strcmp(vault_info->kdfname, "bcrypt") == 0 && rounds == 0) {
+ rounds = vault_info->rounds;
+ printf("Keeping existing rounds %d\n", rounds);
+ }
/* Save the file using the new passphrase. */
if ((r = sshkey_save_private(private, identity_file, passphrase1,
comment, private_key_format, openssh_format_cipher, rounds)) != 0) {
@@ -1513,6 +1518,7 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
char new_comment[1024], *comment, *passphrase;
struct sshkey *private;
struct sshkey *public;
+ struct sshkey *vault_info;
struct stat st;
FILE *f;
int r, fd;
@@ -1522,7 +1528,7 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
if (stat(identity_file, &st) == -1)
fatal("%s: %s", identity_file, strerror(errno));
if ((r = sshkey_load_private(identity_file, "",
- &private, &comment)) == 0)
+ &private, &comment, &vault_info)) == 0)
passphrase = xstrdup("");
else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal("Cannot load private key \"%s\": %s.",
@@ -1537,7 +1543,7 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
RP_ALLOW_STDIN);
/* Try to load using the passphrase. */
if ((r = sshkey_load_private(identity_file, passphrase,
- &private, &comment)) != 0) {
+ &private, &comment, &vault_info)) != 0) {
freezero(passphrase, strlen(passphrase));
fatal("Cannot load private key \"%s\": %s.",
identity_file, ssh_err(r));
@@ -1577,6 +1583,10 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
exit(0);
}
+ if (vault_info != NULL && strcmp(vault_info->kdfname, "bcrypt") == 0 && rounds == 0) {
+ rounds = vault_info->rounds;
+ printf("Keeping existing rounds %d\n", rounds);
+ }
/* Save the file using the new passphrase. */
if ((r = sshkey_save_private(private, identity_file, passphrase,
new_comment, private_key_format, openssh_format_cipher,
diff --git a/ssh-keysign.c b/ssh-keysign.c
index 3e3ea3e1481d..c9c20483b9a5 100644
--- a/ssh-keysign.c
+++ b/ssh-keysign.c
@@ -225,7 +225,7 @@ main(int argc, char **argv)
if (key_fd[i] == -1)
continue;
r = sshkey_load_private_type_fd(key_fd[i], KEY_UNSPEC,
- NULL, &key, NULL);
+ NULL, &key, NULL, NULL);
close(key_fd[i]);
if (r != 0)
debug("parse key %d: %s", i, ssh_err(r));
diff --git a/sshconnect2.c b/sshconnect2.c
index af00fb30c39b..f062e5316ae6 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1472,7 +1472,7 @@ load_identity_file(Identity *id)
}
}
switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename,
- passphrase, &private, &comment))) {
+ passphrase, &private, &comment, NULL))) {
case 0:
break;
case SSH_ERR_KEY_WRONG_PASSPHRASE:
diff --git a/sshd.c b/sshd.c
index 6f8f11a3bdac..42c19089a225 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1789,7 +1789,7 @@ main(int ac, char **av)
if (options.host_key_files[i] == NULL)
continue;
if ((r = sshkey_load_private(options.host_key_files[i], "",
- &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
+ &key, NULL, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
do_log2(ll, "Unable to load host key \"%s\": %s",
options.host_key_files[i], ssh_err(r));
if (sshkey_is_sk(key) &&
diff --git a/sshkey.c b/sshkey.c
index d6cc6365f0da..c57db193886d 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -679,6 +679,26 @@ sshkey_free(struct sshkey *k)
freezero(k, sizeof(*k));
}
+struct sshkey_vault *
+sshkey_vault_new()
+{
+ struct sshkey_vault *k = calloc(1, sizeof(*k));
+ if (k == NULL)
+ return NULL;
+ k->rounds = -1;
+ return k;
+}
+
+void
+sshkey_vault_free(struct sshkey_vault *k)
+{
+ if (k == NULL)
+ return;
+ free(k->kdfname);
+ free(k);
+ return;
+}
+
static int
cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
{
@@ -4136,7 +4156,7 @@ private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp)
static int
private2_decrypt(struct sshbuf *decoded, const char *passphrase,
- struct sshbuf **decryptedp, struct sshkey **pubkeyp)
+ struct sshbuf **decryptedp, struct sshkey **pubkeyp, struct sshkey_vault **vault_infop)
{
char *ciphername = NULL, *kdfname = NULL;
const struct sshcipher *cipher = NULL;
@@ -4145,11 +4165,20 @@ private2_decrypt(struct sshbuf *decoded, const char *passphrase,
struct sshbuf *kdf = NULL, *decrypted = NULL;
struct sshcipher_ctx *ciphercontext = NULL;
struct sshkey *pubkey = NULL;
+ struct sshkey_vault *vault_info = NULL;
u_char *key = NULL, *salt = NULL, *dp;
u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
if (decoded == NULL || decryptedp == NULL || pubkeyp == NULL)
return SSH_ERR_INVALID_ARGUMENT;
+
+ if (vault_infop != NULL) {
+ *vault_infop = NULL;
+ }
+ if ((vault_info = calloc(1, sizeof(*vault_info))) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
*decryptedp = NULL;
*pubkeyp = NULL;
@@ -4185,6 +4214,10 @@ private2_decrypt(struct sshbuf *decoded, const char *passphrase,
r = SSH_ERR_KEY_UNKNOWN_CIPHER;
goto out;
}
+ if ((vault_info->kdfname = strdup(kdfname)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
if (strcmp(kdfname, "none") == 0 && strcmp(ciphername, "none") != 0) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
@@ -4215,6 +4248,7 @@ private2_decrypt(struct sshbuf *decoded, const char *passphrase,
if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
(r = sshbuf_get_u32(kdf, &rounds)) != 0)
goto out;
+ vault_info->rounds = rounds;
if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
key, keylen + ivlen, rounds) < 0) {
r = SSH_ERR_INVALID_FORMAT;
@@ -4262,6 +4296,10 @@ private2_decrypt(struct sshbuf *decoded, const char *passphrase,
decrypted = NULL;
*pubkeyp = pubkey;
pubkey = NULL;
+ if (vault_infop != NULL) {
+ *vault_infop = vault_info;
+ vault_info = NULL;
+ }
r = 0;
out:
cipher_free(ciphercontext);
@@ -4278,6 +4316,7 @@ private2_decrypt(struct sshbuf *decoded, const char *passphrase,
}
sshbuf_free(kdf);
sshbuf_free(decrypted);
+ sshkey_vault_free(vault_info);
return r;
}
@@ -4308,7 +4347,7 @@ private2_check_padding(struct sshbuf *decrypted)
static int
sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
- struct sshkey **keyp, char **commentp)
+ struct sshkey **keyp, char **commentp, struct sshkey_vault **vault_infop)
{
char *comment = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
@@ -4323,7 +4362,7 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
/* Undo base64 encoding and decrypt the private section */
if ((r = private2_uudecode(blob, &decoded)) != 0 ||
(r = private2_decrypt(decoded, passphrase,
- &decrypted, &pubkey)) != 0)
+ &decrypted, &pubkey, vault_infop)) != 0)
goto out;
if (type != KEY_UNSPEC &&
@@ -4731,7 +4770,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
int
sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
- const char *passphrase, struct sshkey **keyp, char **commentp)
+ const char *passphrase, struct sshkey **keyp, char **commentp, struct sshkey_vault **vault_infop)
{
int r = SSH_ERR_INTERNAL_ERROR;
@@ -4739,16 +4778,18 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
+ if (vault_infop != NULL)
+ *vault_infop = NULL;
switch (type) {
case KEY_ED25519:
case KEY_XMSS:
/* No fallback for new-format-only keys */
return sshkey_parse_private2(blob, type, passphrase,
- keyp, commentp);
+ keyp, commentp, vault_infop);
default:
r = sshkey_parse_private2(blob, type, passphrase, keyp,
- commentp);
+ commentp, vault_infop);
/* Only fallback to PEM parser if a format error occurred. */
if (r != SSH_ERR_INVALID_FORMAT)
return r;
@@ -4771,7 +4812,7 @@ sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
*commentp = NULL;
return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
- passphrase, keyp, commentp);
+ passphrase, keyp, commentp, NULL);
}
void
diff --git a/sshkey.h b/sshkey.h
index 9c1d4f6372f6..70f855ac7e51 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -162,6 +162,14 @@ struct sshkey_sig_details {
uint8_t sk_flags; /* U2F signature flags; see ssh-sk.h */
};
+/* Key storage parameters in private key file */
+struct sshkey_vault {
+ char *kdfname;
+ int rounds;
+};
+struct sshkey_vault *sshkey_vault_new();
+void sshkey_vault_free(struct sshkey_vault *);
+
struct sshkey *sshkey_new(int);
void sshkey_free(struct sshkey *);
int sshkey_equal_public(const struct sshkey *,
@@ -258,7 +266,7 @@ int sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
int sshkey_parse_private_fileblob(struct sshbuf *buffer,
const char *passphrase, struct sshkey **keyp, char **commentp);
int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
- const char *passphrase, struct sshkey **keyp, char **commentp);
+ const char *passphrase, struct sshkey **keyp, char **commentp, struct sshkey_vault **vault_infop);
int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob,
int type, struct sshkey **pubkeyp);
--
2.17.1
More information about the openssh-unix-dev
mailing list