mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Validate Argon2 parameters when loading a PPK file.
This prevents a couple of different possible crashes if a PPK file constructed by something other than PuTTYgen contains invalid parameters. If parallelism is 0 then the Argon2 code can divide by zero; if the memory requirement is too small for the parallelism then it can overrun a buffer. Signed-off-by: Martin Prikryl <martin@winscp.net> Source commit: e66db8e4bd600fd9d92467fb8b6cc31cd86fc0ad
This commit is contained in:
committed by
Martin Prikryl
parent
f4157b1cd4
commit
2b1419f914
@@ -7,6 +7,10 @@
|
||||
*
|
||||
* https://github.com/P-H-C/phc-winner-argon2
|
||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-argon2-13
|
||||
*
|
||||
* The latter was later published as RFC 9106:
|
||||
*
|
||||
* https://datatracker.ietf.org/doc/rfc9106
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
@@ -505,6 +509,33 @@ static void argon2_internal(uint32_t p, uint32_t T, uint32_t m, uint32_t t,
|
||||
sfree(B);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the Argon2 parameters, via the requirements in RFC 9106
|
||||
* section 3.1.
|
||||
*/
|
||||
bool argon2_params_valid(uint32_t mem, uint32_t passes,
|
||||
uint32_t parallel, uint32_t taglen,
|
||||
size_t Plen, size_t Slen, size_t Klen, size_t Xlen)
|
||||
{
|
||||
if (Plen > 0xFFFFFFFF)
|
||||
return false;
|
||||
if (Slen > 0xFFFFFFFF)
|
||||
return false;
|
||||
if (parallel < 1 || parallel > 0xFFFFFF)
|
||||
return false;
|
||||
if (taglen < 4) /* upper bound 2^32-1 enforced by data type */
|
||||
return false;
|
||||
if (mem < 8*parallel) /* upper bound 2^32-1 enforced by data type */
|
||||
return false;
|
||||
if (passes < 1) /* upper bound 2^32-1 enforced by data type */
|
||||
return false;
|
||||
if (Klen > 0xFFFFFFFF)
|
||||
return false;
|
||||
if (Xlen > 0xFFFFFFFF)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper function that appends to a strbuf (which sshpubk.c will want).
|
||||
*/
|
||||
@@ -512,6 +543,8 @@ void argon2(Argon2Flavour flavour, uint32_t mem, uint32_t passes,
|
||||
uint32_t parallel, uint32_t taglen,
|
||||
ptrlen P, ptrlen S, ptrlen K, ptrlen X, strbuf *out)
|
||||
{
|
||||
assert(argon2_params_valid(mem, passes, parallel, taglen,
|
||||
P.len, S.len, K.len, X.len));
|
||||
argon2_internal(parallel, taglen, mem, passes, flavour,
|
||||
P, S, K, X, strbuf_append(out, taglen));
|
||||
}
|
||||
|
||||
@@ -1134,6 +1134,9 @@ struct ssh2_userkey {
|
||||
|
||||
/* Argon2 password hashing function */
|
||||
typedef enum { Argon2d = 0, Argon2i = 1, Argon2id = 2 } Argon2Flavour;
|
||||
bool argon2_params_valid(uint32_t mem, uint32_t passes,
|
||||
uint32_t parallel, uint32_t taglen,
|
||||
size_t Plen, size_t Slen, size_t Klen, size_t Xlen);
|
||||
void argon2(Argon2Flavour, uint32_t mem, uint32_t passes,
|
||||
uint32_t parallel, uint32_t taglen,
|
||||
ptrlen P, ptrlen S, ptrlen K, ptrlen X, strbuf *out);
|
||||
|
||||
@@ -707,6 +707,7 @@ ssh2_userkey *ppk_load_s(BinarySource *src, const char *passphrase,
|
||||
const ssh_keyalg *alg;
|
||||
ssh2_userkey *ukey;
|
||||
strbuf *public_blob, *private_blob, *cipher_mac_keys_blob;
|
||||
ptrlen passphrase_pl = ptrlen_from_asciz(passphrase ? passphrase : "");
|
||||
strbuf *passphrase_salt = strbuf_new();
|
||||
ptrlen cipherkey, cipheriv, mackey;
|
||||
const struct ppk_cipher *ciphertype;
|
||||
@@ -855,6 +856,14 @@ ssh2_userkey *ppk_load_s(BinarySource *src, const char *passphrase,
|
||||
}
|
||||
}
|
||||
sfree(b);
|
||||
|
||||
/* Check the Argon2 parameters make sense */
|
||||
uint32_t taglen = ciphertype->keylen + ciphertype->ivlen + 32;
|
||||
if (!argon2_params_valid(
|
||||
params.argon2_mem, params.argon2_passes,
|
||||
params.argon2_parallelism, taglen,
|
||||
passphrase_pl.len, passphrase_salt->len, 0, 0))
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Read the Private-Lines header line and the Private blob. */
|
||||
@@ -885,8 +894,7 @@ ssh2_userkey *ppk_load_s(BinarySource *src, const char *passphrase,
|
||||
goto error;
|
||||
|
||||
cipher_mac_keys_blob = strbuf_new();
|
||||
ssh2_ppk_derive_keys(fmt_version, ciphertype,
|
||||
ptrlen_from_asciz(passphrase ? passphrase : ""),
|
||||
ssh2_ppk_derive_keys(fmt_version, ciphertype, passphrase_pl,
|
||||
cipher_mac_keys_blob, &cipherkey, &cipheriv, &mackey,
|
||||
ptrlen_from_strbuf(passphrase_salt), ¶ms);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user