summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sshkey.c154
1 files changed, 114 insertions, 40 deletions
diff --git a/sshkey.c b/sshkey.c
index 6eba16ec..0fc0f97c 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.102 2020/03/06 18:23:17 markus Exp $ */
+/* $OpenBSD: sshkey.c,v 1.103 2020/04/08 00:01:52 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -4060,30 +4060,21 @@ sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob,
}
static int
-sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
- struct sshkey **keyp, char **commentp)
+private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp)
{
- char *comment = NULL, *ciphername = NULL, *kdfname = NULL;
- const struct sshcipher *cipher = NULL;
const u_char *cp;
- int r = SSH_ERR_INTERNAL_ERROR;
size_t encoded_len;
- size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0;
+ int r;
+ u_char last;
struct sshbuf *encoded = NULL, *decoded = NULL;
- struct sshbuf *kdf = NULL, *decrypted = NULL;
- struct sshcipher_ctx *ciphercontext = NULL;
- struct sshkey *k = NULL;
- u_char *key = NULL, *salt = NULL, *dp, pad, last;
- u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
- if (keyp != NULL)
- *keyp = NULL;
- if (commentp != NULL)
- *commentp = NULL;
+ if (blob == NULL || decodedp == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+
+ *decodedp = NULL;
if ((encoded = sshbuf_new()) == NULL ||
- (decoded = sshbuf_new()) == NULL ||
- (decrypted = sshbuf_new()) == NULL) {
+ (decoded = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
@@ -4133,13 +4124,54 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
+ /* success */
+ *decodedp = decoded;
+ decoded = NULL;
+ r = 0;
+ out:
+ sshbuf_free(encoded);
+ sshbuf_free(decoded);
+ return r;
+}
+
+static int
+private2_decrypt(struct sshbuf *decoded, struct sshbuf **decryptedp,
+ const char *passphrase)
+{
+ char *ciphername = NULL, *kdfname = NULL;
+ const struct sshcipher *cipher = NULL;
+ int r = SSH_ERR_INTERNAL_ERROR;
+ size_t keylen = 0, ivlen = 0, authlen = 0, slen = 0;
+ struct sshbuf *kdf = NULL, *decrypted = NULL;
+ struct sshcipher_ctx *ciphercontext = NULL;
+ u_char *key = NULL, *salt = NULL, *dp;
+ u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
+
+ if (decoded == NULL || decryptedp == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+
+ *decryptedp = NULL;
+
+ if ((decrypted = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+
/* parse public portion of key */
if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
(r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
(r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
(r = sshbuf_froms(decoded, &kdf)) != 0 ||
- (r = sshbuf_get_u32(decoded, &nkeys)) != 0 ||
- (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */
+ (r = sshbuf_get_u32(decoded, &nkeys)) != 0)
+ goto out;
+
+ if (nkeys != 1) {
+ /* XXX only one key supported at present */
+ r = SSH_ERR_INVALID_FORMAT;
+ goto out;
+ }
+
+ if ((r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */
(r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
goto out;
@@ -4161,11 +4193,6 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
goto out;
}
- if (nkeys != 1) {
- /* XXX only one key supported */
- r = SSH_ERR_INVALID_FORMAT;
- goto out;
- }
/* check size of encrypted key blob */
blocksize = cipher_blocksize(cipher);
@@ -4228,13 +4255,35 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
goto out;
}
+ /* success */
+ *decryptedp = decrypted;
+ decrypted = NULL;
+ r = 0;
+ out:
+ cipher_free(ciphercontext);
+ free(ciphername);
+ free(kdfname);
+ if (salt != NULL) {
+ explicit_bzero(salt, slen);
+ free(salt);
+ }
+ if (key != NULL) {
+ explicit_bzero(key, keylen + ivlen);
+ free(key);
+ }
+ sshbuf_free(kdf);
+ sshbuf_free(decrypted);
+ return r;
+}
- /* Load the private key and comment */
- if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
- (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
- goto out;
+/* Check deterministic padding after private key */
+static int
+private2_check_padding(struct sshbuf *decrypted)
+{
+ u_char pad;
+ size_t i;
+ int r = SSH_ERR_INTERNAL_ERROR;
- /* Check deterministic padding */
i = 0;
while (sshbuf_len(decrypted)) {
if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
@@ -4244,6 +4293,41 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
goto out;
}
}
+ /* success */
+ r = 0;
+ out:
+ explicit_bzero(&pad, sizeof(pad));
+ explicit_bzero(&i, sizeof(i));
+ return r;
+}
+
+static int
+sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
+ struct sshkey **keyp, char **commentp)
+{
+ char *comment = NULL;
+ int r = SSH_ERR_INTERNAL_ERROR;
+ struct sshbuf *decoded = NULL, *decrypted = NULL;
+ struct sshkey *k = NULL;
+
+ if (keyp != NULL)
+ *keyp = NULL;
+ if (commentp != NULL)
+ *commentp = NULL;
+
+ /* Undo base64 encoding and decrypt the private section */
+ if ((r = private2_uudecode(blob, &decoded)) != 0 ||
+ (r = private2_decrypt(decoded, &decrypted, passphrase)) != 0)
+ goto out;
+
+ /* Load the private key and comment */
+ if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
+ (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
+ goto out;
+
+ /* Check deterministic padding after private section */
+ if ((r = private2_check_padding(decrypted)) != 0)
+ goto out;
/* XXX decode pubkey and check against private */
@@ -4258,18 +4342,8 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
comment = NULL;
}
out:
- pad = 0;
- cipher_free(ciphercontext);
- free(ciphername);
- free(kdfname);
free(comment);
- if (salt != NULL)
- freezero(salt, slen);
- if (key != NULL)
- freezero(key, keylen + ivlen);
- sshbuf_free(encoded);
sshbuf_free(decoded);
- sshbuf_free(kdf);
sshbuf_free(decrypted);
sshkey_free(k);
return r;