Boundaries check for DoClientKeyExchange.

-- switched from totalSz to size in the function parameters
-- BUFFER_ERROR returned in case of message overflow (piece larger than the hello size)
-- OPAQUE16_LEN used whenever 2 bytes are needed.
This commit is contained in:
Moisés Guimarães
2014-02-24 12:41:50 -03:00
parent 78bab91615
commit d26b3bb445

View File

@ -3829,7 +3829,7 @@ static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx,
case client_key_exchange: case client_key_exchange:
CYASSL_MSG("processing client key exchange"); CYASSL_MSG("processing client key exchange");
ret = DoClientKeyExchange(ssl, input, inOutIdx, totalSz); ret = DoClientKeyExchange(ssl, input, inOutIdx, size);
break; break;
#if !defined(NO_RSA) || defined(HAVE_ECC) #if !defined(NO_RSA) || defined(HAVE_ECC)
@ -10547,18 +10547,19 @@ static void PickHashSigAlgo(CYASSL* ssl,
} }
#endif #endif
static int DoClientKeyExchange(CYASSL* ssl, byte* input, static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32* inOutIdx,
word32* inOutIdx, word32 totalSz) word32 size)
{ {
int ret = 0; int ret = 0;
word32 length = 0; word32 length = 0;
byte* out = NULL; byte* out = NULL;
word32 begin = *inOutIdx;
(void)length; /* shut up compiler warnings */ (void)length; /* shut up compiler warnings */
(void)out; (void)out;
(void)input; (void)input;
(void)inOutIdx; (void)inOutIdx;
(void)totalSz; (void)size;
if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
CYASSL_MSG("Client sending keyexchange at wrong time"); CYASSL_MSG("Client sending keyexchange at wrong time");
@ -10587,15 +10588,12 @@ static void PickHashSigAlgo(CYASSL* ssl,
{ {
word32 idx = 0; word32 idx = 0;
RsaKey key; RsaKey key;
byte* tmp = 0;
byte doUserRsa = 0; byte doUserRsa = 0;
#ifdef HAVE_PK_CALLBACKS #ifdef HAVE_PK_CALLBACKS
#ifndef NO_RSA if (ssl->ctx->RsaDecCb)
if (ssl->ctx->RsaDecCb) doUserRsa = 1;
doUserRsa = 1; #endif
#endif /* NO_RSA */
#endif /*HAVE_PK_CALLBACKS */
InitRsaKey(&key, ssl->heap); InitRsaKey(&key, ssl->heap);
@ -10611,28 +10609,31 @@ static void PickHashSigAlgo(CYASSL* ssl,
if (ssl->options.tls) { if (ssl->options.tls) {
word16 check; word16 check;
if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
return BUFFER_ERROR;
ato16(input + *inOutIdx, &check); ato16(input + *inOutIdx, &check);
if ((word32)check != length) { *inOutIdx += OPAQUE16_LEN;
if ((word32) check != length) {
CYASSL_MSG("RSA explicit size doesn't match"); CYASSL_MSG("RSA explicit size doesn't match");
FreeRsaKey(&key); FreeRsaKey(&key);
return RSA_PRIVATE_ERROR; return RSA_PRIVATE_ERROR;
} }
(*inOutIdx) += 2;
} }
tmp = input + *inOutIdx;
*inOutIdx += length;
if (*inOutIdx > totalSz) { if ((*inOutIdx - begin) + length > size) {
CYASSL_MSG("RSA message too big"); CYASSL_MSG("RSA message too big");
FreeRsaKey(&key); FreeRsaKey(&key);
return INCOMPLETE_DATA; return BUFFER_ERROR;
} }
if (doUserRsa) { if (doUserRsa) {
#ifdef HAVE_PK_CALLBACKS #ifdef HAVE_PK_CALLBACKS
#ifndef NO_RSA #ifndef NO_RSA
ret = ssl->ctx->RsaDecCb(ssl, ret = ssl->ctx->RsaDecCb(ssl,
tmp, length, &out, input + *inOutIdx, length, &out,
ssl->buffers.key.buffer, ssl->buffers.key.buffer,
ssl->buffers.key.length, ssl->buffers.key.length,
ssl->RsaDecCtx); ssl->RsaDecCtx);
@ -10640,9 +10641,12 @@ static void PickHashSigAlgo(CYASSL* ssl,
#endif /*HAVE_PK_CALLBACKS */ #endif /*HAVE_PK_CALLBACKS */
} }
else { else {
ret = RsaPrivateDecryptInline(tmp, length, &out, &key); ret = RsaPrivateDecryptInline(input + *inOutIdx, length,
&out, &key);
} }
*inOutIdx += length;
if (ret == SECRET_LEN) { if (ret == SECRET_LEN) {
XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN); XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN);
if (ssl->arrays->preMasterSecret[0] != if (ssl->arrays->preMasterSecret[0] !=
@ -10668,36 +10672,46 @@ static void PickHashSigAlgo(CYASSL* ssl,
byte* pms = ssl->arrays->preMasterSecret; byte* pms = ssl->arrays->preMasterSecret;
word16 ci_sz; word16 ci_sz;
ato16(&input[*inOutIdx], &ci_sz); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
if (ci_sz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR;
XMEMCPY(ssl->arrays->client_identity, &input[*inOutIdx], ci_sz); ato16(input + *inOutIdx, &ci_sz);
*inOutIdx += OPAQUE16_LEN;
if (ci_sz > MAX_PSK_ID_LEN)
return CLIENT_ID_ERROR;
if ((*inOutIdx - begin) + ci_sz > size)
return BUFFER_ERROR;
XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz);
*inOutIdx += ci_sz; *inOutIdx += ci_sz;
if (ci_sz < MAX_PSK_ID_LEN)
ssl->arrays->client_identity[ci_sz] = 0;
else
ssl->arrays->client_identity[MAX_PSK_ID_LEN-1] = 0;
ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0;
ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl,
ssl->arrays->client_identity, ssl->arrays->psk_key, ssl->arrays->client_identity, ssl->arrays->psk_key,
MAX_PSK_KEY_LEN); MAX_PSK_KEY_LEN);
if (ssl->arrays->psk_keySz == 0 || if (ssl->arrays->psk_keySz == 0 ||
ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN)
return PSK_KEY_ERROR; return PSK_KEY_ERROR;
/* make psk pre master secret */ /* make psk pre master secret */
/* length of key + length 0s + length of key + key */ /* length of key + length 0s + length of key + key */
c16toa((word16)ssl->arrays->psk_keySz, pms); c16toa((word16) ssl->arrays->psk_keySz, pms);
pms += 2; pms += OPAQUE16_LEN;
XMEMSET(pms, 0, ssl->arrays->psk_keySz); XMEMSET(pms, 0, ssl->arrays->psk_keySz);
pms += ssl->arrays->psk_keySz; pms += ssl->arrays->psk_keySz;
c16toa((word16)ssl->arrays->psk_keySz, pms);
pms += 2; c16toa((word16) ssl->arrays->psk_keySz, pms);
pms += OPAQUE16_LEN;
XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz);
ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4;
ret = MakeMasterSecret(ssl); ret = MakeMasterSecret(ssl);
/* No further need for PSK */ /* No further need for PSK */
XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz);
ssl->arrays->psk_keySz = 0; ssl->arrays->psk_keySz = 0;
@ -10707,26 +10721,34 @@ static void PickHashSigAlgo(CYASSL* ssl,
#ifdef HAVE_NTRU #ifdef HAVE_NTRU
case ntru_kea: case ntru_kea:
{ {
word32 rc;
word16 cipherLen; word16 cipherLen;
word16 plainLen = sizeof(ssl->arrays->preMasterSecret); word16 plainLen = sizeof(ssl->arrays->preMasterSecret);
byte* tmp;
if (!ssl->buffers.key.buffer) if (!ssl->buffers.key.buffer)
return NO_PRIVATE_KEY; return NO_PRIVATE_KEY;
ato16(&input[*inOutIdx], &cipherLen); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
ato16(input + *inOutIdx, &cipherLen);
*inOutIdx += OPAQUE16_LEN;
if (cipherLen > MAX_NTRU_ENCRYPT_SZ) if (cipherLen > MAX_NTRU_ENCRYPT_SZ)
return NTRU_KEY_ERROR; return NTRU_KEY_ERROR;
tmp = input + *inOutIdx; if ((*inOutIdx - begin) + cipherLen > size)
rc = crypto_ntru_decrypt((word16)ssl->buffers.key.length, return BUFFER_ERROR;
ssl->buffers.key.buffer, cipherLen, tmp, &plainLen,
ssl->arrays->preMasterSecret);
if (rc != NTRU_OK || plainLen != SECRET_LEN) if (NTRU_OK != crypto_ntru_decrypt(
(word16) ssl->buffers.key.length,
ssl->buffers.key.buffer, cipherLen,
input + *inOutIdx, &plainLen,
ssl->arrays->preMasterSecret))
return NTRU_DECRYPT_ERROR; return NTRU_DECRYPT_ERROR;
if (plainLen != SECRET_LEN)
return NTRU_DECRYPT_ERROR;
*inOutIdx += cipherLen; *inOutIdx += cipherLen;
ssl->arrays->preMasterSz = plainLen; ssl->arrays->preMasterSz = plainLen;
@ -10737,18 +10759,23 @@ static void PickHashSigAlgo(CYASSL* ssl,
#ifdef HAVE_ECC #ifdef HAVE_ECC
case ecc_diffie_hellman_kea: case ecc_diffie_hellman_kea:
{ {
word32 size; if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
word32 bLength = input[*inOutIdx]; /* one byte length */ return BUFFER_ERROR;
*inOutIdx += 1;
ret = ecc_import_x963(&input[*inOutIdx], length = input[*inOutIdx];
bLength, ssl->peerEccKey); *inOutIdx += OPAQUE8_LEN;
if (ret != 0)
if ((*inOutIdx - begin) + length > size)
return BUFFER_ERROR;
if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey))
return ECC_PEERKEY_ERROR; return ECC_PEERKEY_ERROR;
*inOutIdx += bLength;
*inOutIdx += length;
ssl->peerEccKeyPresent = 1; ssl->peerEccKeyPresent = 1;
size = sizeof(ssl->arrays->preMasterSecret); length = sizeof(ssl->arrays->preMasterSecret);
if (ssl->specs.static_ecdh) { if (ssl->specs.static_ecdh) {
ecc_key staticKey; ecc_key staticKey;
word32 i = 0; word32 i = 0;
@ -10756,17 +10783,21 @@ static void PickHashSigAlgo(CYASSL* ssl,
ecc_init(&staticKey); ecc_init(&staticKey);
ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i, ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
&staticKey, ssl->buffers.key.length); &staticKey, ssl->buffers.key.length);
if (ret == 0) if (ret == 0)
ret = ecc_shared_secret(&staticKey, ssl->peerEccKey, ret = ecc_shared_secret(&staticKey, ssl->peerEccKey,
ssl->arrays->preMasterSecret, &size); ssl->arrays->preMasterSecret, &length);
ecc_free(&staticKey); ecc_free(&staticKey);
} }
else else
ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey, ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey,
ssl->arrays->preMasterSecret, &size); ssl->arrays->preMasterSecret, &length);
if (ret != 0) if (ret != 0)
return ECC_SHARED_ERROR; return ECC_SHARED_ERROR;
ssl->arrays->preMasterSz = size;
ssl->arrays->preMasterSz = length;
ret = MakeMasterSecret(ssl); ret = MakeMasterSecret(ssl);
} }
break; break;
@ -10774,15 +10805,17 @@ static void PickHashSigAlgo(CYASSL* ssl,
#ifdef OPENSSL_EXTRA #ifdef OPENSSL_EXTRA
case diffie_hellman_kea: case diffie_hellman_kea:
{ {
byte* clientPub;
word16 clientPubSz; word16 clientPubSz;
DhKey dhKey; DhKey dhKey;
ato16(&input[*inOutIdx], &clientPubSz); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
clientPub = &input[*inOutIdx]; ato16(input + *inOutIdx, &clientPubSz);
*inOutIdx += clientPubSz; *inOutIdx += OPAQUE16_LEN;
if ((*inOutIdx - begin) + clientPubSz > size)
return BUFFER_ERROR;
InitDhKey(&dhKey); InitDhKey(&dhKey);
ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer,
@ -10794,8 +10827,11 @@ static void PickHashSigAlgo(CYASSL* ssl,
&ssl->arrays->preMasterSz, &ssl->arrays->preMasterSz,
ssl->buffers.serverDH_Priv.buffer, ssl->buffers.serverDH_Priv.buffer,
ssl->buffers.serverDH_Priv.length, ssl->buffers.serverDH_Priv.length,
clientPub, clientPubSz); input + *inOutIdx, clientPubSz);
FreeDhKey(&dhKey); FreeDhKey(&dhKey);
*inOutIdx += clientPubSz;
if (ret == 0) if (ret == 0)
ret = MakeMasterSecret(ssl); ret = MakeMasterSecret(ssl);
} }
@ -10808,6 +10844,7 @@ static void PickHashSigAlgo(CYASSL* ssl,
} }
break; break;
} }
/* No further need for PMS */ /* No further need for PMS */
XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz); XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz);
ssl->arrays->preMasterSz = 0; ssl->arrays->preMasterSz = 0;
@ -10824,5 +10861,3 @@ static void PickHashSigAlgo(CYASSL* ssl,
} }
#endif /* NO_CYASSL_SERVER */ #endif /* NO_CYASSL_SERVER */