version 1.102, 2020/03/06 18:23:17 |
version 1.103, 2020/04/08 00:01:52 |
|
|
} |
} |
|
|
static int |
static int |
sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, |
private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp) |
struct sshkey **keyp, char **commentp) |
|
{ |
{ |
char *comment = NULL, *ciphername = NULL, *kdfname = NULL; |
|
const struct sshcipher *cipher = NULL; |
|
const u_char *cp; |
const u_char *cp; |
int r = SSH_ERR_INTERNAL_ERROR; |
|
size_t encoded_len; |
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 *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) |
if (blob == NULL || decodedp == NULL) |
*keyp = NULL; |
return SSH_ERR_INVALID_ARGUMENT; |
if (commentp != NULL) |
|
*commentp = NULL; |
|
|
|
|
*decodedp = NULL; |
|
|
if ((encoded = sshbuf_new()) == NULL || |
if ((encoded = sshbuf_new()) == NULL || |
(decoded = sshbuf_new()) == NULL || |
(decoded = sshbuf_new()) == NULL) { |
(decrypted = sshbuf_new()) == NULL) { |
|
r = SSH_ERR_ALLOC_FAIL; |
r = SSH_ERR_ALLOC_FAIL; |
goto out; |
goto out; |
} |
} |
|
|
r = SSH_ERR_INVALID_FORMAT; |
r = SSH_ERR_INVALID_FORMAT; |
goto out; |
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 */ |
/* parse public portion of key */ |
if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || |
if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || |
(r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || |
(r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || |
(r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || |
(r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || |
(r = sshbuf_froms(decoded, &kdf)) != 0 || |
(r = sshbuf_froms(decoded, &kdf)) != 0 || |
(r = sshbuf_get_u32(decoded, &nkeys)) != 0 || |
(r = sshbuf_get_u32(decoded, &nkeys)) != 0) |
(r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */ |
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) |
(r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) |
goto out; |
goto out; |
|
|
|
|
r = SSH_ERR_KEY_WRONG_PASSPHRASE; |
r = SSH_ERR_KEY_WRONG_PASSPHRASE; |
goto out; |
goto out; |
} |
} |
if (nkeys != 1) { |
|
/* XXX only one key supported */ |
|
r = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
|
|
/* check size of encrypted key blob */ |
/* check size of encrypted key blob */ |
blocksize = cipher_blocksize(cipher); |
blocksize = cipher_blocksize(cipher); |
|
|
r = SSH_ERR_KEY_WRONG_PASSPHRASE; |
r = SSH_ERR_KEY_WRONG_PASSPHRASE; |
goto out; |
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 */ |
/* Check deterministic padding after private key */ |
if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 || |
static int |
(r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0) |
private2_check_padding(struct sshbuf *decrypted) |
goto out; |
{ |
|
u_char pad; |
|
size_t i; |
|
int r = SSH_ERR_INTERNAL_ERROR; |
|
|
/* Check deterministic padding */ |
|
i = 0; |
i = 0; |
while (sshbuf_len(decrypted)) { |
while (sshbuf_len(decrypted)) { |
if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) |
if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) |
|
|
goto out; |
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 */ |
/* XXX decode pubkey and check against private */ |
|
|
/* success */ |
/* success */ |
|
|
comment = NULL; |
comment = NULL; |
} |
} |
out: |
out: |
pad = 0; |
|
cipher_free(ciphercontext); |
|
free(ciphername); |
|
free(kdfname); |
|
free(comment); |
free(comment); |
if (salt != NULL) |
|
freezero(salt, slen); |
|
if (key != NULL) |
|
freezero(key, keylen + ivlen); |
|
sshbuf_free(encoded); |
|
sshbuf_free(decoded); |
sshbuf_free(decoded); |
sshbuf_free(kdf); |
|
sshbuf_free(decrypted); |
sshbuf_free(decrypted); |
sshkey_free(k); |
sshkey_free(k); |
return r; |
return r; |