Merge pull request #1426 from cconlon/dh186

DH - Use q parameter when available, add wc_DhSetKey_ex()
pull/1429/head
toddouska 2018-03-08 13:57:54 -08:00 committed by GitHub
commit 200077c62c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 215 additions and 35 deletions

View File

@ -504,7 +504,7 @@ int wc_InitDhKey_ex(DhKey* key, void* heap, int devId)
key->heap = heap; /* for XMALLOC/XFREE in future */
if (mp_init_multi(&key->p, &key->g, NULL, NULL, NULL, NULL) != MP_OKAY)
if (mp_init_multi(&key->p, &key->g, &key->q, NULL, NULL, NULL) != MP_OKAY)
return MEMORY_E;
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
@ -529,6 +529,7 @@ void wc_FreeDhKey(DhKey* key)
if (key) {
mp_clear(&key->p);
mp_clear(&key->g);
mp_clear(&key->q);
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
wolfAsync_DevCtxFree(&key->asyncDev, WOLFSSL_ASYNC_MARKER_DH);
@ -567,41 +568,186 @@ void wc_FreeDhKey(DhKey* key)
#endif
static int GeneratePrivateDh(DhKey* key, WC_RNG* rng, byte* priv, word32* privSz)
/* validate that (L,N) match allowed sizes from SP 800-56A, Section 5.5.1.1.
* modLen - represents L, the size of p in bits
* divLen - represents N, the size of q in bits
* return 0 on success, -1 on error */
static int CheckDhLN(int modLen, int divLen)
{
int ret = 0;
word32 sz = mp_unsigned_bin_size(&key->p);
int ret = -1;
/* Table of predetermined values from the operation
2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) / WOLFSSL_BIT_SIZE + 1
Sizes in table checked against RFC 3526
*/
WOLFSSL_DH_ROUND(sz); /* if using fixed points only, then round up */
switch (sz) {
case 128: sz = 21; break;
case 256: sz = 29; break;
case 384: sz = 34; break;
case 512: sz = 39; break;
case 640: sz = 42; break;
case 768: sz = 46; break;
case 896: sz = 49; break;
case 1024: sz = 52; break;
default:
#ifndef WOLFSSL_DH_CONST
/* if using floating points and size of p is not in table */
sz = min(sz, 2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
WOLFSSL_BIT_SIZE + 1);
switch (modLen) {
/* FA */
case 1024:
if (divLen == 160)
ret = 0;
break;
/* FB, FC */
case 2048:
if (divLen == 224 || divLen == 256)
ret = 0;
break;
default:
break;
#else
return BAD_FUNC_ARG;
#endif
}
ret = wc_RNG_GenerateBlock(rng, priv, sz);
return ret;
}
if (ret == 0) {
priv[0] |= 0x0C;
*privSz = sz;
/* Create DH private key
*
* Based on NIST FIPS 186-4,
* "B.1.1 Key Pair Generation Using Extra Random Bits"
*
* dh - pointer to initialized DhKey structure, needs to have dh->q
* rng - pointer to initialized WC_RNG structure
* priv - output location for generated private key
* privSz - IN/OUT, size of priv buffer, size of generated private key
*
* return 0 on success, negative on error */
static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
word32* privSz)
{
byte* cBuf;
int qSz, pSz, cSz, err;
mp_int tmpQ, tmpX;
if (key == NULL || rng == NULL || priv == NULL || privSz == NULL)
return BAD_FUNC_ARG;
if (mp_iszero(&key->q) == MP_YES) {
WOLFSSL_MSG("DH q parameter needed for FIPS 186-4 key generation");
return BAD_FUNC_ARG;
}
qSz = mp_unsigned_bin_size(&key->q);
pSz = mp_unsigned_bin_size(&key->p);
/* verify (L,N) pair bit lengths */
if (CheckDhLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0) {
WOLFSSL_MSG("DH param sizes do not match SP 800-56A requirements");
return BAD_FUNC_ARG;
}
/* generate extra 64 bits so that bias from mod function is negligible */
cSz = qSz + (64 / WOLFSSL_BIT_SIZE);
cBuf = (byte*)XMALLOC(cSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (cBuf == NULL) {
return MEMORY_E;
}
if ((err = mp_init_multi(&tmpX, &tmpQ, NULL, NULL, NULL, NULL))
!= MP_OKAY) {
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
do {
/* generate N+64 bits (c) from RBG into &tmpX, making sure positive.
* Hash_DRBG uses SHA-256 which matches maximum
* requested_security_strength of (L,N) */
err = wc_RNG_GenerateBlock(rng, cBuf, cSz);
if (err != MP_OKAY) {
mp_clear(&tmpX);
mp_clear(&tmpQ);
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
err = mp_read_unsigned_bin(&tmpX, cBuf, cSz);
if (err != MP_OKAY) {
mp_clear(&tmpX);
mp_clear(&tmpQ);
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return err;
}
} while (mp_cmp_d(&tmpX, 1) != MP_GT);
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
/* tmpQ = q - 1 */
if (err == MP_OKAY)
err = mp_copy(&key->q, &tmpQ);
if (err == MP_OKAY)
err = mp_sub_d(&tmpQ, 1, &tmpQ);
/* x = c mod (q-1), &tmpX holds c */
if (err == MP_OKAY)
err = mp_mod(&tmpX, &tmpQ, &tmpX);
/* x = c mod (q-1) + 1 */
if (err == MP_OKAY)
err = mp_add_d(&tmpX, 1, &tmpX);
/* copy tmpX into priv */
if (err == MP_OKAY) {
pSz = mp_unsigned_bin_size(&tmpX);
if (pSz > (int)*privSz) {
WOLFSSL_MSG("DH private key output buffer too small");
err = BAD_FUNC_ARG;
} else {
*privSz = pSz;
err = mp_to_unsigned_bin(&tmpX, priv);
}
}
mp_clear(&tmpX);
mp_clear(&tmpQ);
return err;
}
static int GeneratePrivateDh(DhKey* key, WC_RNG* rng, byte* priv,
word32* privSz)
{
int ret = 0;
word32 sz = 0;
if (mp_iszero(&key->q) == MP_NO) {
/* q param available, use NIST FIPS 186-4, "B.1.1 Key Pair
* Generation Using Extra Random Bits" */
ret = GeneratePrivateDh186(key, rng, priv, privSz);
} else {
sz = mp_unsigned_bin_size(&key->p);
/* Table of predetermined values from the operation
2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
WOLFSSL_BIT_SIZE + 1
Sizes in table checked against RFC 3526
*/
WOLFSSL_DH_ROUND(sz); /* if using fixed points only, then round up */
switch (sz) {
case 128: sz = 21; break;
case 256: sz = 29; break;
case 384: sz = 34; break;
case 512: sz = 39; break;
case 640: sz = 42; break;
case 768: sz = 46; break;
case 896: sz = 49; break;
case 1024: sz = 52; break;
default:
#ifndef WOLFSSL_DH_CONST
/* if using floating points and size of p is not in table */
sz = min(sz, 2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
WOLFSSL_BIT_SIZE + 1);
break;
#else
return BAD_FUNC_ARG;
#endif
}
ret = wc_RNG_GenerateBlock(rng, priv, sz);
if (ret == 0) {
priv[0] |= 0x0C;
*privSz = sz;
}
}
return ret;
@ -762,6 +908,11 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
if (ret == 0 && prime != NULL) {
if (mp_read_unsigned_bin(&q, prime, primeSz) != MP_OKAY)
ret = MP_READ_E;
} else if (mp_iszero(&key->q) == MP_NO) {
/* use q available in DhKey */
if (mp_copy(&key->q, &q) != MP_OKAY)
ret = MP_INIT_E;
}
/* pub (y) should not be 0 or 1 */
@ -780,7 +931,7 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
ret = MP_CMP_E;
}
if (ret == 0 && prime != NULL) {
if (ret == 0 && (prime != NULL || (mp_iszero(&key->q) == MP_NO) )) {
/* restore key->p into p */
if (mp_copy(&key->p, &p) != MP_OKAY)
@ -1002,9 +1153,8 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
}
/* not in asn anymore since no actual asn types used */
int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
word32 gSz)
int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g,
word32 gSz, const byte* q, word32 qSz)
{
if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0) {
return BAD_FUNC_ARG;
@ -1019,6 +1169,12 @@ int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
gSz--; g++;
}
if (q != NULL) {
if (q[0] == 0) {
qSz--; q++;
}
}
if (mp_init(&key->p) != MP_OKAY)
return MP_INIT_E;
if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) {
@ -1036,7 +1192,29 @@ int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
return ASN_DH_KEY_E;
}
if (q != NULL) {
if (mp_init(&key->q) != MP_OKAY) {
mp_clear(&key->g);
mp_clear(&key->p);
return MP_INIT_E;
}
if (mp_read_unsigned_bin(&key->q, q, qSz) != 0) {
mp_clear(&key->g);
mp_clear(&key->p);
mp_clear(&key->q);
return MP_INIT_E;
}
}
return 0;
}
/* not in asn anymore since no actual asn types used */
int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
word32 gSz)
{
return wc_DhSetKey_ex(key, p, pSz, g, gSz, NULL, 0);
}
#endif /* NO_DH */

View File

@ -46,7 +46,7 @@ typedef struct DhParams {
/* Diffie-Hellman Key */
typedef struct DhKey {
mp_int p, g; /* group parameters */
mp_int p, g, q; /* group parameters */
void* heap;
#ifdef WOLFSSL_ASYNC_CRYPT
WC_ASYNC_DEV asyncDev;
@ -84,6 +84,8 @@ WOLFSSL_API int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key,
word32);
WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
word32 gSz);
WOLFSSL_API int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz,
const byte* g, word32 gSz, const byte* q, word32 qSz);
WOLFSSL_API int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p,
word32* pInOutSz, byte* g, word32* gInOutSz);
WOLFSSL_API int wc_DhCheckPubKey(DhKey* key, const byte* pub, word32 pubSz);