Boundaries check for DoCertificateVerify.

-- added size in the function parameters;
-- BUFFER_ERROR returned in case of message overflow (piece larger than the hello size);
-- ENUM_LEN and OPAQUE8_LEN used whenever 1 byte is needed;
-- OPAQUE16_LEN used whenever 2 bytes are needed;
-- removed unnecessary variables (signature, sigLen);
-- removed unnecessary #ifdef HAVE_ECC.
This commit is contained in:
Moisés Guimarães
2014-03-10 16:34:33 -03:00
parent eba36226dc
commit 2d2d1341cf

View File

@ -72,7 +72,8 @@ CYASSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*, static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*,
word32); word32);
static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32); static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32);
static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*); static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*,
word32);
#ifndef NO_CERTS #ifndef NO_CERTS
static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*, static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*,
word32); word32);
@ -3808,7 +3809,7 @@ static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx,
case server_key_exchange: case server_key_exchange:
CYASSL_MSG("processing server key exchange"); CYASSL_MSG("processing server key exchange");
ret = DoServerKeyExchange(ssl, input, inOutIdx); ret = DoServerKeyExchange(ssl, input, inOutIdx, size);
break; break;
#endif #endif
@ -7731,18 +7732,16 @@ static void PickHashSigAlgo(CYASSL* ssl,
static int DoServerKeyExchange(CYASSL* ssl, const byte* input, static int DoServerKeyExchange(CYASSL* ssl, const byte* input,
word32* inOutIdx) word32* inOutIdx, word32 size)
{ {
#if defined(OPENSSL_EXTRA) || defined(HAVE_ECC) word16 length = 0;
word16 length = 0; word32 begin = *inOutIdx;
word16 sigLen = 0;
word16 verifySz = (word16)*inOutIdx; /* keep start idx */
byte* signature = 0;
#endif
(void)length; /* shut up compiler warnings */
(void)begin;
(void)ssl; (void)ssl;
(void)input; (void)input;
(void)inOutIdx; (void)size;
#ifdef CYASSL_CALLBACKS #ifdef CYASSL_CALLBACKS
if (ssl->hsInfoOn) if (ssl->hsInfoOn)
@ -7753,16 +7752,21 @@ static void PickHashSigAlgo(CYASSL* ssl,
#ifndef NO_PSK #ifndef NO_PSK
if (ssl->specs.kea == psk_kea) { if (ssl->specs.kea == psk_kea) {
word16 pskLen = 0;
ato16(&input[*inOutIdx], &pskLen); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
XMEMCPY(ssl->arrays->server_hint, &input[*inOutIdx],
min(pskLen, MAX_PSK_ID_LEN)); ato16(input + *inOutIdx, &length);
if (pskLen < MAX_PSK_ID_LEN) *inOutIdx += OPAQUE16_LEN;
ssl->arrays->server_hint[pskLen] = 0;
else if ((*inOutIdx - begin) + length > size)
ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = 0; return BUFFER_ERROR;
*inOutIdx += pskLen;
XMEMCPY(ssl->arrays->server_hint, input + *inOutIdx,
min(length, MAX_PSK_ID_LEN));
ssl->arrays->server_hint[min(length, MAX_PSK_ID_LEN - 1)] = 0;
*inOutIdx += length;
return 0; return 0;
} }
@ -7771,42 +7775,66 @@ static void PickHashSigAlgo(CYASSL* ssl,
if (ssl->specs.kea == diffie_hellman_kea) if (ssl->specs.kea == diffie_hellman_kea)
{ {
/* p */ /* p */
ato16(&input[*inOutIdx], &length); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
ato16(input + *inOutIdx, &length);
*inOutIdx += OPAQUE16_LEN;
if ((*inOutIdx - begin) + length > size)
return BUFFER_ERROR;
ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap, ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap,
DYNAMIC_TYPE_DH); DYNAMIC_TYPE_DH);
if (ssl->buffers.serverDH_P.buffer) if (ssl->buffers.serverDH_P.buffer)
ssl->buffers.serverDH_P.length = length; ssl->buffers.serverDH_P.length = length;
else else
return MEMORY_ERROR; return MEMORY_ERROR;
XMEMCPY(ssl->buffers.serverDH_P.buffer, &input[*inOutIdx], length);
XMEMCPY(ssl->buffers.serverDH_P.buffer, input + *inOutIdx, length);
*inOutIdx += length; *inOutIdx += length;
/* g */ /* g */
ato16(&input[*inOutIdx], &length); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
ato16(input + *inOutIdx, &length);
*inOutIdx += OPAQUE16_LEN;
if ((*inOutIdx - begin) + length > size)
return BUFFER_ERROR;
ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap, ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
DYNAMIC_TYPE_DH); DYNAMIC_TYPE_DH);
if (ssl->buffers.serverDH_G.buffer) if (ssl->buffers.serverDH_G.buffer)
ssl->buffers.serverDH_G.length = length; ssl->buffers.serverDH_G.length = length;
else else
return MEMORY_ERROR; return MEMORY_ERROR;
XMEMCPY(ssl->buffers.serverDH_G.buffer, &input[*inOutIdx], length);
XMEMCPY(ssl->buffers.serverDH_G.buffer, input + *inOutIdx, length);
*inOutIdx += length; *inOutIdx += length;
/* pub */ /* pub */
ato16(&input[*inOutIdx], &length); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
ato16(input + *inOutIdx, &length);
*inOutIdx += OPAQUE16_LEN;
if ((*inOutIdx - begin) + length > size)
return BUFFER_ERROR;
ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap, ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
DYNAMIC_TYPE_DH); DYNAMIC_TYPE_DH);
if (ssl->buffers.serverDH_Pub.buffer) if (ssl->buffers.serverDH_Pub.buffer)
ssl->buffers.serverDH_Pub.length = length; ssl->buffers.serverDH_Pub.length = length;
else else
return MEMORY_ERROR; return MEMORY_ERROR;
XMEMCPY(ssl->buffers.serverDH_Pub.buffer, &input[*inOutIdx], length);
XMEMCPY(ssl->buffers.serverDH_Pub.buffer, input + *inOutIdx, length);
*inOutIdx += length; *inOutIdx += length;
} /* dh_kea */ } /* dh_kea */
#endif /* OPENSSL_EXTRA */ #endif /* OPENSSL_EXTRA */
@ -7814,24 +7842,29 @@ static void PickHashSigAlgo(CYASSL* ssl,
#ifdef HAVE_ECC #ifdef HAVE_ECC
if (ssl->specs.kea == ecc_diffie_hellman_kea) if (ssl->specs.kea == ecc_diffie_hellman_kea)
{ {
byte b = input[*inOutIdx]; byte b;
*inOutIdx += 1;
if ((*inOutIdx - begin) + ENUM_LEN + OPAQUE16_LEN + OPAQUE8_LEN > size)
return BUFFER_ERROR;
b = input[(*inOutIdx)++];
if (b != named_curve) if (b != named_curve)
return ECC_CURVETYPE_ERROR; return ECC_CURVETYPE_ERROR;
*inOutIdx += 1; /* curve type, eat leading 0 */ *inOutIdx += 1; /* curve type, eat leading 0 */
b = input[*inOutIdx]; b = input[(*inOutIdx)++];
*inOutIdx += 1;
if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b != if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b !=
secp160r1 && b != secp192r1 && b != secp224r1) secp160r1 && b != secp192r1 && b != secp224r1)
return ECC_CURVE_ERROR; return ECC_CURVE_ERROR;
length = input[*inOutIdx]; length = input[(*inOutIdx)++];
*inOutIdx += 1;
if (ecc_import_x963(&input[*inOutIdx], length, ssl->peerEccKey) != 0) if ((*inOutIdx - begin) + length > size)
return BUFFER_ERROR;
if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey) != 0)
return ECC_PEERKEY_ERROR; return ECC_PEERKEY_ERROR;
*inOutIdx += length; *inOutIdx += length;
@ -7844,42 +7877,46 @@ static void PickHashSigAlgo(CYASSL* ssl,
#ifndef NO_OLD_TLS #ifndef NO_OLD_TLS
Md5 md5; Md5 md5;
Sha sha; Sha sha;
#endif
#ifndef NO_SHA256
Sha256 sha256;
byte hash256[SHA256_DIGEST_SIZE];
#endif
#ifdef CYASSL_SHA384
Sha384 sha384;
byte hash384[SHA384_DIGEST_SIZE];
#endif #endif
byte hash[FINISHED_SZ]; byte hash[FINISHED_SZ];
#ifndef NO_SHA256
Sha256 sha256;
byte hash256[SHA256_DIGEST_SIZE];
#endif
#ifdef CYASSL_SHA384
Sha384 sha384;
byte hash384[SHA384_DIGEST_SIZE];
#endif
byte messageVerify[MAX_DH_SZ]; byte messageVerify[MAX_DH_SZ];
byte hashAlgo = sha_mac; byte hashAlgo = sha_mac;
byte sigAlgo = ssl->specs.sig_algo; byte sigAlgo = ssl->specs.sig_algo;
word16 verifySz = (word16) (*inOutIdx - begin);
/* adjust from start idx */
verifySz = (word16)(*inOutIdx - verifySz);
/* save message for hash verify */ /* save message for hash verify */
if (verifySz > sizeof(messageVerify)) if (verifySz > sizeof(messageVerify))
return BUFFER_ERROR; return BUFFER_ERROR;
XMEMCPY(messageVerify, &input[*inOutIdx - verifySz], verifySz);
XMEMCPY(messageVerify, input + begin, verifySz);
if (IsAtLeastTLSv1_2(ssl)) { if (IsAtLeastTLSv1_2(ssl)) {
hashAlgo = input[*inOutIdx]; if ((*inOutIdx - begin) + ENUM_LEN + ENUM_LEN > size)
*inOutIdx += 1; return BUFFER_ERROR;
sigAlgo = input[*inOutIdx];
*inOutIdx += 1; hashAlgo = input[(*inOutIdx)++];
sigAlgo = input[(*inOutIdx)++];
} }
/* signature */ /* signature */
ato16(&input[*inOutIdx], &length); if ((*inOutIdx - begin) + OPAQUE16_LEN > size)
*inOutIdx += LENGTH_SZ; return BUFFER_ERROR;
signature = (byte*)&input[*inOutIdx]; ato16(input + *inOutIdx, &length);
*inOutIdx += length; *inOutIdx += OPAQUE16_LEN;
sigLen = length;
if ((*inOutIdx - begin) + length > size)
return BUFFER_ERROR;
/* inOutIdx updated at the end of the function */
/* verify signature */ /* verify signature */
#ifndef NO_OLD_TLS #ifndef NO_OLD_TLS
@ -7895,23 +7932,25 @@ static void PickHashSigAlgo(CYASSL* ssl,
ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN); ShaUpdate(&sha, ssl->arrays->clientRandom, RAN_LEN);
ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN); ShaUpdate(&sha, ssl->arrays->serverRandom, RAN_LEN);
ShaUpdate(&sha, messageVerify, verifySz); ShaUpdate(&sha, messageVerify, verifySz);
ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); ShaFinal(&sha, hash + MD5_DIGEST_SIZE);
#endif
#ifndef NO_SHA256
InitSha256(&sha256);
Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN);
Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN);
Sha256Update(&sha256, messageVerify, verifySz);
Sha256Final(&sha256, hash256);
#endif
#ifdef CYASSL_SHA384
InitSha384(&sha384);
Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN);
Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN);
Sha384Update(&sha384, messageVerify, verifySz);
Sha384Final(&sha384, hash384);
#endif #endif
#ifndef NO_SHA256
InitSha256(&sha256);
Sha256Update(&sha256, ssl->arrays->clientRandom, RAN_LEN);
Sha256Update(&sha256, ssl->arrays->serverRandom, RAN_LEN);
Sha256Update(&sha256, messageVerify, verifySz);
Sha256Final(&sha256, hash256);
#endif
#ifdef CYASSL_SHA384
InitSha384(&sha384);
Sha384Update(&sha384, ssl->arrays->clientRandom, RAN_LEN);
Sha384Update(&sha384, ssl->arrays->serverRandom, RAN_LEN);
Sha384Update(&sha384, messageVerify, verifySz);
Sha384Final(&sha384, hash384);
#endif
#ifndef NO_RSA #ifndef NO_RSA
/* rsa */ /* rsa */
if (sigAlgo == rsa_sa_algo) if (sigAlgo == rsa_sa_algo)
@ -7930,7 +7969,7 @@ static void PickHashSigAlgo(CYASSL* ssl,
if (doUserRsa) { if (doUserRsa) {
#ifdef HAVE_PK_CALLBACKS #ifdef HAVE_PK_CALLBACKS
ret = ssl->ctx->RsaVerifyCb(ssl, signature, sigLen, ret = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, length,
&out, &out,
ssl->buffers.peerRsaKey.buffer, ssl->buffers.peerRsaKey.buffer,
ssl->buffers.peerRsaKey.length, ssl->buffers.peerRsaKey.length,
@ -7938,8 +7977,8 @@ static void PickHashSigAlgo(CYASSL* ssl,
#endif /*HAVE_PK_CALLBACKS */ #endif /*HAVE_PK_CALLBACKS */
} }
else { else {
ret = RsaSSL_VerifyInline(signature, sigLen,&out, ret = RsaSSL_VerifyInline((byte *) input + *inOutIdx, length,
ssl->peerRsaKey); &out, ssl->peerRsaKey);
} }
if (IsAtLeastTLSv1_2(ssl)) { if (IsAtLeastTLSv1_2(ssl)) {
@ -8004,11 +8043,9 @@ static void PickHashSigAlgo(CYASSL* ssl,
byte doUserEcc = 0; byte doUserEcc = 0;
#ifdef HAVE_PK_CALLBACKS #ifdef HAVE_PK_CALLBACKS
#ifdef HAVE_ECC if (ssl->ctx->EccVerifyCb)
if (ssl->ctx->EccVerifyCb) doUserEcc = 1;
doUserEcc = 1; #endif
#endif /* HAVE_ECC */
#endif /*HAVE_PK_CALLBACKS */
if (!ssl->peerEccDsaKeyPresent) if (!ssl->peerEccDsaKeyPresent)
return NO_PEER_KEY; return NO_PEER_KEY;
@ -8035,18 +8072,16 @@ static void PickHashSigAlgo(CYASSL* ssl,
} }
if (doUserEcc) { if (doUserEcc) {
#ifdef HAVE_PK_CALLBACKS #ifdef HAVE_PK_CALLBACKS
#ifdef HAVE_ECC ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, length,
ret = ssl->ctx->EccVerifyCb(ssl, signature, sigLen, digest, digestSz,
digest, digestSz, ssl->buffers.peerEccDsaKey.buffer,
ssl->buffers.peerEccDsaKey.buffer, ssl->buffers.peerEccDsaKey.length,
ssl->buffers.peerEccDsaKey.length, &verify, ssl->EccVerifyCtx);
&verify, ssl->EccVerifyCtx); #endif
#endif /* HAVE_ECC */
#endif /*HAVE_PK_CALLBACKS */
} }
else { else {
ret = ecc_verify_hash(signature, sigLen, digest, digestSz, ret = ecc_verify_hash(input + *inOutIdx, length,
&verify, ssl->peerEccDsaKey); digest, digestSz, &verify, ssl->peerEccDsaKey);
} }
if (ret != 0 || verify == 0) if (ret != 0 || verify == 0)
return VERIFY_SIGN_ERROR; return VERIFY_SIGN_ERROR;
@ -8055,10 +8090,12 @@ static void PickHashSigAlgo(CYASSL* ssl,
#endif /* HAVE_ECC */ #endif /* HAVE_ECC */
return ALGO_ID_E; return ALGO_ID_E;
/* signature length */
*inOutIdx += length;
ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
return 0; return 0;
} }
#else /* HAVE_OPENSSL or HAVE_ECC */ #else /* HAVE_OPENSSL or HAVE_ECC */
return NOT_COMPILED_IN; /* not supported by build */ return NOT_COMPILED_IN; /* not supported by build */
@ -10621,7 +10658,6 @@ static void PickHashSigAlgo(CYASSL* ssl,
(void)length; /* shut up compiler warnings */ (void)length; /* shut up compiler warnings */
(void)out; (void)out;
(void)input; (void)input;
(void)inOutIdx;
(void)size; (void)size;
if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
@ -10823,8 +10859,7 @@ static void PickHashSigAlgo(CYASSL* ssl,
if ((*inOutIdx - begin) + OPAQUE8_LEN > size) if ((*inOutIdx - begin) + OPAQUE8_LEN > size)
return BUFFER_ERROR; return BUFFER_ERROR;
length = input[*inOutIdx]; length = input[(*inOutIdx)++];
*inOutIdx += OPAQUE8_LEN;
if ((*inOutIdx - begin) + length > size) if ((*inOutIdx - begin) + length > size)
return BUFFER_ERROR; return BUFFER_ERROR;