Skip to content

Commit

Permalink
add constant time DH key agreement APIs and related logic:
Browse files Browse the repository at this point in the history
* wc_DhAgree_ct()
* wolfSSL_DH_compute_key_padded()
* sp_read_unsigned_bin_ct()
* wolfcrypt/src/integer.c:mp_read_unsigned_bin_ct()
* fp_read_unsigned_bin_ct()
  • Loading branch information
douzzer committed Jul 28, 2024
1 parent b1765ca commit 6a6ec01
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 51 deletions.
83 changes: 65 additions & 18 deletions src/pk.c
Original file line number Diff line number Diff line change
Expand Up @@ -8645,20 +8645,8 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
}


/* Compute the shared key from the private key and peer's public key.
*
* Return code compliant with OpenSSL.
* OpenSSL returns 0 when number of bits in p are smaller than minimum
* supported.
*
* @param [out] key Buffer to place shared key.
* @param [in] otherPub Peer's public key.
* @param [in] dh DH key containing private key.
* @return -1 on error.
* @return Size of shared secret in bytes on success.
*/
int wolfSSL_DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub,
WOLFSSL_DH* dh)
static int _DH_compute_key_1(unsigned char* key, const WOLFSSL_BIGNUM* otherPub,
WOLFSSL_DH* dh, int ct)
{
int ret = 0;
word32 keySz = 0;
Expand All @@ -8680,6 +8668,12 @@ int wolfSSL_DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub,
WOLFSSL_ERROR_MSG("Bad function arguments");
ret = -1;
}
#ifdef HAVE_FIPS
if (ct) {
ret = -1;
}
#endif

/* Get the maximum size of computed DH key. */
if ((ret == 0) && ((keySz = (word32)DH_size(dh)) == 0)) {
WOLFSSL_ERROR_MSG("Bad DH_size");
Expand Down Expand Up @@ -8746,10 +8740,24 @@ int wolfSSL_DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub,

PRIVATE_KEY_UNLOCK();
/* Calculate shared secret from private and public keys. */
if ((ret == 0) && (wc_DhAgree((DhKey*)dh->internal, key, &keySz, priv,
(word32)privSz, pub, (word32)pubSz) < 0)) {
WOLFSSL_ERROR_MSG("wc_DhAgree failed");
ret = -1;
if (ret == 0) {
#ifndef HAVE_FIPS
if (ct) {
if (wc_DhAgree_ct((DhKey*)dh->internal, key, &keySz, priv,
(word32)privSz, pub, (word32)pubSz) < 0) {
WOLFSSL_ERROR_MSG("wc_DhAgree_ct failed");
ret = -1;
}
}
else
#endif /* !HAVE_FIPS */
{
if (wc_DhAgree((DhKey*)dh->internal, key, &keySz, priv,
(word32)privSz, pub, (word32)pubSz) < 0) {
WOLFSSL_ERROR_MSG("wc_DhAgree failed");
ret = -1;
}
}
}
if (ret == 0) {
/* Return actual length. */
Expand All @@ -8773,6 +8781,45 @@ int wolfSSL_DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub,

return ret;
}

/* Compute the shared key from the private key and peer's public key.
*
* Return code compliant with OpenSSL.
* OpenSSL returns 0 when number of bits in p are smaller than minimum
* supported.
*
* @param [out] key Buffer to place shared key.
* @param [in] otherPub Peer's public key.
* @param [in] dh DH key containing private key.
* @return -1 on error.
* @return Size of shared secret in bytes on success.
*/
int wolfSSL_DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub,
WOLFSSL_DH* dh)
{
return _DH_compute_key_1(key, otherPub, dh, 0);
}

/* Compute the shared key from the private key and peer's public key as in
* wolfSSL_DH_compute_key, but using constant time processing, with an output
* key length fixed at the nominal DH key size. Leading zeros are retained.
*
* Return code compliant with OpenSSL.
* OpenSSL returns 0 when number of bits in p are smaller than minimum
* supported.
*
* @param [out] key Buffer to place shared key.
* @param [in] otherPub Peer's public key.
* @param [in] dh DH key containing private key.
* @return -1 on error.
* @return Size of shared secret in bytes on success.
*/
int wolfSSL_DH_compute_key_padded(unsigned char* key,
const WOLFSSL_BIGNUM* otherPub, WOLFSSL_DH* dh)
{
return _DH_compute_key_1(key, otherPub, dh, 1);
}

#endif /* !HAVE_FIPS || (HAVE_FIPS && !WOLFSSL_DH_EXTRA) ||
* HAVE_FIPS_VERSION > 2 */

Expand Down
103 changes: 86 additions & 17 deletions wolfcrypt/src/dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1981,7 +1981,7 @@ int wc_DhGenerateKeyPair(DhKey* key, WC_RNG* rng,

#ifndef WOLFSSL_KCAPI_DH
static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
const byte* priv, word32 privSz, const byte* otherPub, word32 pubSz)
const byte* priv, word32 privSz, const byte* otherPub, word32 pubSz, int ct)
{
int ret = 0;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
Expand Down Expand Up @@ -2040,8 +2040,18 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,

SAVE_VECTOR_REGISTERS(ret = _svr_ret;);

if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
ret = MP_READ_E;
if (ret == 0) {
if (ct)
ret = mp_read_unsigned_bin_ct(y, otherPub, pubSz);
else
ret = mp_read_unsigned_bin(y, otherPub, pubSz);
if (ret != MP_OKAY)
ret = MP_READ_E;
#if MP_OKAY != 0
else
ret = 0;
#endif
}

if (ret == 0)
ret = sp_DhExp_2048(y, priv, privSz, &key->p, agree, agreeSz);
Expand Down Expand Up @@ -2074,8 +2084,18 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,

SAVE_VECTOR_REGISTERS(ret = _svr_ret;);

if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
ret = MP_READ_E;
if (ret == 0) {
if (ct)
ret = mp_read_unsigned_bin_ct(y, otherPub, pubSz);
else
ret = mp_read_unsigned_bin(y, otherPub, pubSz);
if (ret != MP_OKAY)
ret = MP_READ_E;
#if MP_OKAY != 0
else
ret = 0;
#endif
}

if (ret == 0)
ret = sp_DhExp_3072(y, priv, privSz, &key->p, agree, agreeSz);
Expand Down Expand Up @@ -2108,8 +2128,18 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,

SAVE_VECTOR_REGISTERS(ret = _svr_ret;);

if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
ret = MP_READ_E;
if (ret == 0) {
if (ct)
ret = mp_read_unsigned_bin_ct(y, otherPub, pubSz);
else
ret = mp_read_unsigned_bin(y, otherPub, pubSz);
if (ret != MP_OKAY)
ret = MP_READ_E;
#if MP_OKAY != 0
else
ret = 0;
#endif
}

if (ret == 0)
ret = sp_DhExp_4096(y, priv, privSz, &key->p, agree, agreeSz);
Expand Down Expand Up @@ -2149,15 +2179,34 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,

SAVE_VECTOR_REGISTERS(ret = _svr_ret;);

if (mp_read_unsigned_bin(x, priv, privSz) != MP_OKAY)
if (ct)
ret = mp_read_unsigned_bin_ct(x, priv, privSz);
else
ret = mp_read_unsigned_bin(x, priv, privSz);
if (ret != MP_OKAY)
ret = MP_READ_E;
#if MP_OKAY != 0
else
ret = 0;
#endif

#ifdef WOLFSSL_CHECK_MEM_ZERO
if (ret == 0)
mp_memzero_add("wc_DhAgree_Sync x", x);
#endif

if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
ret = MP_READ_E;
if (ret == 0) {
if (ct)
ret = mp_read_unsigned_bin_ct(y, otherPub, pubSz);
else
ret = mp_read_unsigned_bin(y, otherPub, pubSz);
if (ret != MP_OKAY)
ret = MP_READ_E;
#if MP_OKAY != 0
else
ret = 0;
#endif
}

if (ret == 0 && mp_exptmod(y, x, &key->p, z) != MP_OKAY)
ret = MP_EXPTMOD_E;
Expand All @@ -2170,11 +2219,17 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
if (ret == 0 && (mp_cmp_d(z, 1) == MP_EQ))
ret = MP_VAL;

if (ret == 0 && mp_to_unsigned_bin(z, agree) != MP_OKAY)
ret = MP_TO_E;

if (ret == 0)
*agreeSz = (word32)mp_unsigned_bin_size(z);
if (ret == 0) {
if (ct) {
if (mp_to_unsigned_bin_len_ct(z, agree, (int)*agreeSz) != MP_OKAY)
ret = MP_TO_E;
} else {
if (mp_to_unsigned_bin(z, agree) != MP_OKAY)
ret = MP_TO_E;
if (ret == 0)
*agreeSz = (word32)mp_unsigned_bin_size(z);
}
}

mp_forcezero(z);
mp_clear(y);
Expand Down Expand Up @@ -2238,7 +2293,8 @@ static int wc_DhAgree_Async(DhKey* key, byte* agree, word32* agreeSz,
#endif

/* otherwise use software DH */
ret = wc_DhAgree_Sync(key, agree, agreeSz, priv, privSz, otherPub, pubSz);
ret = wc_DhAgree_Sync(key, agree, agreeSz, priv, privSz, otherPub, pubSz,
0);

return ret;
}
Expand Down Expand Up @@ -2267,13 +2323,26 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
else
#endif
{
ret = wc_DhAgree_Sync(key, agree, agreeSz, priv, privSz, otherPub, pubSz);
ret = wc_DhAgree_Sync(key, agree, agreeSz, priv, privSz, otherPub,
pubSz, 0);
}
#endif /* WOLFSSL_KCAPI_DH */

return ret;
}

int wc_DhAgree_ct(DhKey* key, byte* agree, word32 *agreeSz, const byte* priv,
word32 privSz, const byte* otherPub, word32 pubSz)
{
if (key == NULL || agree == NULL || agreeSz == NULL || priv == NULL ||
otherPub == NULL) {
return BAD_FUNC_ARG;
}

return wc_DhAgree_Sync(key, agree, agreeSz, priv, privSz, otherPub, pubSz,
1);
}

#ifdef WOLFSSL_DH_EXTRA
WOLFSSL_LOCAL int wc_DhKeyCopy(DhKey* src, DhKey* dst)
{
Expand Down
15 changes: 13 additions & 2 deletions wolfcrypt/src/integer.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,8 @@ int mp_mod_2d (mp_int * a, int b, mp_int * c)


/* reads a unsigned char array, assumes the msb is stored first [big endian] */
int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
static int _read_unsigned_bin_1(mp_int * a, const unsigned char *b, int c,
int ct)
{
int res;
int digits_needed;
Expand Down Expand Up @@ -773,10 +774,20 @@ int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
a->used = 2;
#endif
}
mp_clamp (a);
if (! ct)
mp_clamp (a);
return MP_OKAY;
}

int mp_read_unsigned_bin(mp_int * a, const unsigned char *b, int c)
{
return _read_unsigned_bin_1(a, b, c, 0);
}

int mp_read_unsigned_bin_ct(mp_int * a, const unsigned char *b, int c)
{
return _read_unsigned_bin_1(a, b, c, 1);
}

/* shift left by a certain bit count */
int mp_mul_2d (mp_int * a, int b, mp_int * c)
Expand Down
45 changes: 33 additions & 12 deletions wolfcrypt/src/sp_int.c
Original file line number Diff line number Diff line change
Expand Up @@ -17794,17 +17794,7 @@ int sp_unsigned_bin_size(const sp_int* a)
return cnt;
}

/* Convert a number as an array of bytes in big-endian format to a
* multi-precision number.
*
* @param [out] a SP integer.
* @param [in] in Array of bytes.
* @param [in] inSz Number of data bytes in array.
*
* @return MP_OKAY on success.
* @return MP_VAL when the number is too big to fit in an SP.
*/
int sp_read_unsigned_bin(sp_int* a, const byte* in, word32 inSz)
static int _read_unsigned_bin_1(sp_int* a, const byte* in, word32 inSz, int ct)
{
int err = MP_OKAY;

Expand Down Expand Up @@ -17888,12 +17878,43 @@ int sp_read_unsigned_bin(sp_int* a, const byte* in, word32 inSz)
#endif /* LITTLE_ENDIAN_ORDER */
}
#endif
sp_clamp_ct(a);
if (! ct)
sp_clamp_ct(a);
}

return err;
}

/* Convert a number as an array of bytes in big-endian format to a
* multi-precision number.
*
* @param [out] a SP integer.
* @param [in] in Array of bytes.
* @param [in] inSz Number of data bytes in array.
*
* @return MP_OKAY on success.
* @return MP_VAL when the number is too big to fit in an SP.
*/
int sp_read_unsigned_bin(sp_int* a, const byte* in, word32 inSz)
{
return _read_unsigned_bin_1(a, in, inSz, 0);
}

/* Convert a number as an array of bytes in big-endian format to a
* multi-precision number, retaining leading zeros (if any).
*
* @param [out] a SP integer.
* @param [in] in Array of bytes.
* @param [in] inSz Number of data bytes in array.
*
* @return MP_OKAY on success.
* @return MP_VAL when the number is too big to fit in an SP.
*/
int sp_read_unsigned_bin_ct(sp_int* a, const byte* in, word32 inSz)
{
return _read_unsigned_bin_1(a, in, inSz, 1);
}

/* Convert the multi-precision number to an array of bytes in big-endian format.
*
* The array must be large enough for encoded number - use mp_unsigned_bin_size
Expand Down
Loading

0 comments on commit 6a6ec01

Please sign in to comment.