[PATCH 1/3] Add private key protection information extraction to ssh-keygen
Loïc
loic at venez.fr
Sat Apr 25 10:58:53 AEST 2020
Add private key protection information extraction to shh-keygen using -v
option on top of -y option which is already parsing the private key.
Technically, the passphrase isn't necessary to do this, but it is the
most logical thing to do for me.
Adding this to -l option is not appropriate because fingerprinting is
using the .pub file when available.
An other idea is to add a new option, I can do it if you prefer.
Also, I'm laking information for information extraction from PEM and
PKCS8 file format, I'm OK to have a pointer to implement this correctly.
This patch is also adding a regression test for the functionnality.
---
authfile.c | 16 ++--
authfile.h | 7 +-
regress/Makefile | 3 +-
regress/keygen-private-information.sh | 81 +++++++++++++++++++++
ssh-keygen.c | 44 +++++++----
ssh-keysign.c | 2 +-
sshconnect2.c | 2 +-
sshd.c | 2 +-
sshkey.c | 101 +++++++++++++++++++++++---
sshkey.h | 14 +++-
10 files changed, 234 insertions(+), 38 deletions(-)
create mode 100644 regress/keygen-private-information.sh
diff --git a/authfile.c b/authfile.c
index 35ccf576c2b5..6c79369ebfc1 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,15 +144,15 @@ sshkey_load_private_type(int type, const char
*filename, const char *passphrase,
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);
+ keyp, commentp, vault_infop);
}
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;
@@ -159,7 +161,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 */
@@ -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/regress/Makefile b/regress/Makefile
index 62794d25fc42..ae6f4dd09edc 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -92,7 +92,8 @@ LTESTS= connect \
allow-deny-users \
authinfo \
sshsig \
- keygen-comment
+ keygen-comment \
+ keygen-private-information
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
diff --git a/regress/keygen-private-information.sh
b/regress/keygen-private-information.sh
new file mode 100644
index 000000000000..a9959e919fd1
--- /dev/null
+++ b/regress/keygen-private-information.sh
@@ -0,0 +1,81 @@
+# Placed in the Public Domain.
+
+tid="Test information extraction from private key"
+
+check_private_key () {
+ file="$1"
+ format="$2"
+ comment="$3"
+ secret="$4"
+ rounds="$5"
+
+ # construct expected output in $exp file
+ exp=$OBJ/$t-expected
+ # default format is RFC4716
+ test -z "$format" && format="RFC4716"
+ # Currently PKCS8 is detected as PEM, should be fixed in ssh-keygen
+ test "$format" = "PKCS8" && format="PEM"
+ cat > $exp << EOF
+$comment
+Key protection details:
+File format: $format
+EOF
+ if [ -z "$secret" -o "$format" = "PEM" ]; then
+ # For PEM format, passphrase is not detected yet, should be
fixed in ssh-keygen
+ echo "no passphrase" >> $exp
+ else
+ cat >> $exp << EOF
+cipher: aes256-ctr
+kdf: bcrypt
+rounds: $rounds
+EOF
+ fi
+
+ if ! ${SSHKEYGEN} -yv -P "${secret}" -f $file > $OBJ/$t-pub ; then
+ fail "ssh-keygen -y failed for $t-key"
+ fi
+ if ! sed '1 s/[^ ]* [^ ]* \?//' $OBJ/$t-pub > $OBJ/$t-tmp ; then
+ fail "sed failed for $t-key"
+ fi
+ if ! cmp $OBJ/$t-tmp $exp > /dev/null 2>&1; then
+ fail "ssh-keygen -yv output is not the expected value for $t-key"
+ diff $exp $OBJ/$t-tmp
+ fi
+ rm -f $OBJ/$t-pub $OBJ/$t-tmp $exp
+}
+
+for fmt in '' PKCS8 PEM ; do
+ for secret in '' 'secret1'; do
+ rounds_list="0"
+ test -n "$secret" -a -z "$fmt" && rounds_list="2 16"
+ for rounds in $rounds_list; do
+ for t in $SSH_KEYTYPES; do
+ trace "generating $t key in '$fmt' format with
'$secret' passphrase and '$rounds' rounds"
+ rm -f $OBJ/$t-key*
+ oldfmt=""
+ case "$fmt" in
+ PKCS8|PEM) oldfmt=1 ;;
+ esac
+ # Some key types like ssh-ed25519 and *@openssh.com are
never
+ # stored in old formats.
+ case "$t" in
+ ssh-ed25519|*openssh.com) test -z "$oldfmt" || continue ;;
+ esac
+ comment="foo bar"
+ fmtarg=""
+ test -z "$fmt" || fmtarg="-m $fmt"
+ test "$rounds" = "0" || roundarg="-a $rounds"
+ ${SSHKEYGEN} $fmtarg $roundarg -N "${secret}" -C
"${comment}" \
+ -t $t -f $OBJ/$t-key >/dev/null 2>&1 || \
+ fatal "keygen of $t in format $fmt failed"
+ rm -f $OBJ/$t-key.pub # .pub file not used, remove it
to be sure it is not used
+ if [ ! -z "$oldfmt" ] ; then
+ # Comment cannot be recovered from old format keys.
+ comment=""
+ fi
+ check_private_key $OBJ/$t-key "${fmt}" "${comment}"
"${secret}" "${rounds}"
+ rm -f $OBJ/$t-key*
+ done
+ done
+ done
+done
diff --git a/ssh-keygen.c b/ssh-keygen.c
index d50ca5f28c51..6dd17c48be5e 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -310,7 +310,7 @@ ask_filename(struct passwd *pw, const char *prompt)
}
static struct sshkey *
-load_identity(const char *filename, char **commentp)
+load_identity(const char *filename, char **commentp, struct
sshkey_vault **vault_infop)
{
char *pass;
struct sshkey *prv;
@@ -318,7 +318,9 @@ load_identity(const char *filename, char **commentp)
if (commentp != NULL)
*commentp = NULL;
- if ((r = sshkey_load_private(filename, "", &prv, commentp)) == 0)
+ if (vault_infop != NULL)
+ *vault_infop = NULL;
+ if ((r = sshkey_load_private(filename, "", &prv, commentp,
vault_infop)) == 0)
return prv;
if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal("Load key \"%s\": %s", filename, ssh_err(r));
@@ -326,7 +328,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, vault_infop);
freezero(pass, strlen(pass));
if (r != 0)
fatal("Load key \"%s\": %s", filename, ssh_err(r));
@@ -429,7 +431,7 @@ do_convert_to(struct passwd *pw)
if (stat(identity_file, &st) == -1)
fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
if ((r = sshkey_load_public(identity_file, &k, NULL)) != 0)
- k = load_identity(identity_file, NULL);
+ k = load_identity(identity_file, NULL, NULL);
switch (convert_format) {
case FMT_RFC4716:
do_convert_to_ssh2(pw, k);
@@ -806,19 +808,33 @@ do_print_public(struct passwd *pw)
struct stat st;
int r;
char *comment = NULL;
+ struct sshkey_vault *vault_info = NULL;
if (!have_identity)
ask_filename(pw, "Enter file in which the key is");
if (stat(identity_file, &st) == -1)
fatal("%s: %s", identity_file, strerror(errno));
- prv = load_identity(identity_file, &comment);
+ prv = load_identity(identity_file, &comment, &vault_info);
if ((r = sshkey_write(prv, stdout)) != 0)
error("sshkey_write failed: %s", ssh_err(r));
sshkey_free(prv);
if (comment != NULL && *comment != '\0')
- fprintf(stdout, " %s", comment);
- fprintf(stdout, "\n");
+ printf(" %s", comment);
+ printf("\n");
+ if (log_level_get() >= SYSLOG_LEVEL_VERBOSE) {
+ printf("Key protection details:\n");
+ printf("File format: %s\n",
sshkey_format_name(vault_info->format));
+ if ( (vault_info->ciphername == NULL ||
strcmp(vault_info->ciphername, "none") == 0)
+ || (vault_info->kdfname == NULL ||
strcmp(vault_info->kdfname, "none") == 0)) {
+ printf("no passphrase\n");
+ } else {
+ printf("cipher: %s\n", vault_info->ciphername);
+ printf("kdf: %s\n", vault_info->kdfname);
+ printf("rounds: %d\n", vault_info->rounds);
+ }
+ }
free(comment);
+ sshkey_vault_free(vault_info);
exit(0);
}
@@ -920,7 +936,7 @@ fingerprint_private(const char *path)
if (pubkey == NULL || comment == NULL || *comment == '\0') {
free(comment);
if ((r = sshkey_load_private(path, NULL,
- &privkey, &comment)) != 0)
+ &privkey, &comment, NULL)) != 0)
debug("load private \"%s\": %s", path, ssh_err(r));
}
if (pubkey == NULL && privkey == NULL)
@@ -1416,7 +1432,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, NULL);
if (r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
if (identity_passphrase)
old_passphrase = xstrdup(identity_passphrase);
@@ -1425,7 +1441,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, NULL);
freezero(old_passphrase, strlen(old_passphrase));
if (r != 0)
goto badkey;
@@ -1525,7 +1541,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, NULL)) == 0)
passphrase = xstrdup("");
else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal("Cannot load private key \"%s\": %s.",
@@ -1540,7 +1556,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, NULL)) != 0) {
freezero(passphrase, strlen(passphrase));
fatal("Cannot load private key \"%s\": %s.",
identity_file, ssh_err(r));
@@ -1785,7 +1801,7 @@ do_ca_sign(struct passwd *pw, const char
*ca_key_path, int prefer_agent,
ca->flags |= SSHKEY_FLAG_EXT;
} else {
/* CA key is assumed to be a private key on the filesystem */
- ca = load_identity(tmp, NULL);
+ ca = load_identity(tmp, NULL, NULL);
}
free(tmp);
@@ -2494,7 +2510,7 @@ load_sign_key(const char *keypath, const struct
sshkey *pubkey)
debug("%s: %s looks like a public key, using private key "
"path %s instead", __func__, keypath, privpath);
}
- if ((privkey = load_identity(privpath, NULL)) == NULL) {
+ if ((privkey = load_identity(privpath, NULL, NULL)) == NULL) {
error("Couldn't load identity %s", keypath);
goto done;
}
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 1a6545edf026..7947f2da6584 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 1571e3d93878..4c1948a3752e 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -93,6 +93,26 @@ int sshkey_private_serialize_opt(struct sshkey *key,
static int sshkey_from_blob_internal(struct sshbuf *buf,
struct sshkey **keyp, int allow_cert);
+/* Supported format types */
+const char *
+sshkey_format_name(enum sshkey_private_format format) {
+ const char *format_str;
+ switch (format) {
+ case SSHKEY_PRIVATE_OPENSSH:
+ format_str = "RFC4716";
+ break;
+ case SSHKEY_PRIVATE_PKCS8:
+ format_str = "PKCS8";
+ break;
+ case SSHKEY_PRIVATE_PEM:
+ format_str = "PEM";
+ break;
+ default:
+ format_str = "unknown";
+ }
+ return format_str;
+}
+
/* Supported key types */
struct keytype {
const char *name;
@@ -679,6 +699,29 @@ 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->format = SSHKEY_PRIVATE_OPENSSH;
+ k->ciphername = NULL;
+ k->kdfname = 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)
{
@@ -4029,7 +4072,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;
@@ -4038,12 +4081,21 @@ 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 = sshkey_vault_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+
*decryptedp = NULL;
*pubkeyp = NULL;
@@ -4074,10 +4126,18 @@ private2_decrypt(struct sshbuf *decoded, const
char *passphrase,
r = SSH_ERR_KEY_UNKNOWN_CIPHER;
goto out;
}
+ if ((vault_info->ciphername = strdup(ciphername)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
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;
@@ -4108,6 +4168,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;
@@ -4155,6 +4216,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);
@@ -4171,6 +4236,7 @@ private2_decrypt(struct sshbuf *decoded, const
char *passphrase,
}
sshbuf_free(kdf);
sshbuf_free(decrypted);
+ sshkey_vault_free(vault_info);
return r;
}
@@ -4201,7 +4267,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;
@@ -4216,7 +4282,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 &&
@@ -4521,15 +4587,18 @@ pem_passphrase_cb(char *buf, int size, int
rwflag, void *u)
static int
sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
- const char *passphrase, struct sshkey **keyp)
+ const char *passphrase, struct sshkey **keyp, struct sshkey_vault
**vault_infop)
{
EVP_PKEY *pk = NULL;
struct sshkey *prv = NULL;
+ struct sshkey_vault *vault_info = NULL;
BIO *bio = NULL;
int r;
if (keyp != NULL)
*keyp = NULL;
+ if (vault_infop != NULL)
+ *vault_infop = NULL;
if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
return SSH_ERR_ALLOC_FAIL;
@@ -4538,6 +4607,13 @@ sshkey_parse_private_pem_fileblob(struct sshbuf
*blob, int type,
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
+ if ((vault_info = sshkey_vault_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ // TODO: identify correctly PEM and PKCS8 format
+ vault_info->format = SSHKEY_PRIVATE_PEM;
+ // TODO: put the correct ciphername, kdfname and round if a
passphrase is used
clear_libcrypto_errors();
if ((pk = PEM_read_bio_PrivateKey(bio, NULL, pem_passphrase_cb,
@@ -4614,17 +4690,22 @@ sshkey_parse_private_pem_fileblob(struct sshbuf
*blob, int type,
*keyp = prv;
prv = NULL;
}
+ if (vault_infop != NULL) {
+ *vault_infop = vault_info;
+ vault_info = NULL;
+ }
out:
BIO_free(bio);
EVP_PKEY_free(pk);
sshkey_free(prv);
+ sshkey_vault_free(vault_info);
return r;
}
#endif /* WITH_OPENSSL */
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;
@@ -4632,22 +4713,24 @@ 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;
#ifdef WITH_OPENSSL
return sshkey_parse_private_pem_fileblob(blob, type,
- passphrase, keyp);
+ passphrase, keyp, vault_infop);
#else
return SSH_ERR_INVALID_FORMAT;
#endif /* WITH_OPENSSL */
@@ -4664,7 +4747,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..7b7de828d9ce 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -99,6 +99,8 @@ enum sshkey_private_format {
SSHKEY_PRIVATE_PEM = 1,
SSHKEY_PRIVATE_PKCS8 = 2,
};
+const char *
+sshkey_format_name(enum sshkey_private_format);
/* key is stored in external hardware */
#define SSHKEY_FLAG_EXT 0x0001
@@ -162,6 +164,16 @@ 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 {
+ enum sshkey_private_format format;
+ char *ciphername;
+ 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 +270,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