@@ -14011,6 +14011,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1401114011 byte* aadCopy;
1401214012 byte* readBuf_p = (byte*)readBuf;
1401314013 word16 tmpVal16;
14014+ word16 localEncLen;
1401414015
1401514016 WOLFSSL_MSG("TLSX_ECH_Parse");
1401614017 if (ssl->options.disableECH) {
@@ -14019,6 +14020,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1401914020 }
1402014021 if (size == 0)
1402114022 return BAD_FUNC_ARG;
14023+
1402214024 /* retry configs */
1402314025 if (msgType == encrypted_extensions) {
1402414026 ret = wolfSSL_SetEchConfigs(ssl, readBuf, size);
@@ -14027,16 +14029,17 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1402714029 ret = 0;
1402814030 }
1402914031 /* HRR with special confirmation */
14030- else if (msgType == hello_retry_request && ssl->echConfigs != NULL &&
14031- !ssl->options.disableECH) {
14032+ else if (msgType == hello_retry_request && ssl->echConfigs != NULL) {
1403214033 /* length must be 8 */
1403314034 if (size != ECH_ACCEPT_CONFIRMATION_SZ)
1403414035 return BAD_FUNC_ARG;
14036+
1403514037 /* get extension */
1403614038 echX = TLSX_Find(ssl->extensions, TLSX_ECH);
1403714039 if (echX == NULL)
1403814040 return BAD_FUNC_ARG;
1403914041 ech = (WOLFSSL_ECH*)echX->data;
14042+
1404014043 ech->confBuf = (byte*)readBuf;
1404114044 }
1404214045 else if (msgType == client_hello && ssl->ctx->echConfigs != NULL) {
@@ -14045,6 +14048,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1404514048 if (echX == NULL)
1404614049 return BAD_FUNC_ARG;
1404714050 ech = (WOLFSSL_ECH*)echX->data;
14051+
1404814052 /* read the ech parameters before the payload */
1404914053 ech->type = *readBuf_p;
1405014054 readBuf_p++;
@@ -14057,9 +14061,10 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1405714061 SendAlert(ssl, alert_fatal, illegal_parameter);
1405814062 return INVALID_PARAMETER;
1405914063 }
14060- /* technically the payload would only be 1 byte at this length */
14061- if (size < 11 + ech->encLen)
14062- return BAD_FUNC_ARG;
14064+
14065+ if (size < 11)
14066+ return BUFFER_ERROR;
14067+
1406314068 /* only get enc if we don't already have the hpke context */
1406414069 if (ech->hpkeContext == NULL) {
1406514070 /* kdfId */
@@ -14076,9 +14081,14 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1407614081 readBuf_p += 2;
1407714082 if (ech->encLen > HPKE_Npk_MAX)
1407814083 return BAD_FUNC_ARG;
14084+
14085+ if (size < 11 + ech->encLen)
14086+ return BUFFER_ERROR;
14087+
1407914088 /* read enc */
1408014089 XMEMCPY(ech->enc, readBuf_p, ech->encLen);
1408114090 readBuf_p += ech->encLen;
14091+ localEncLen = ech->encLen;
1408214092 }
1408314093 else {
1408414094 /* kdfId, aeadId, and configId must be the same as last time */
@@ -14102,34 +14112,40 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1410214112 return INVALID_PARAMETER;
1410314113 }
1410414114 readBuf_p++;
14105- /* on an HRR the enc value MUST be empty */
14106- ato16(readBuf_p, &tmpVal16 );
14107- if (tmpVal16 != 0) {
14115+ /* on the second client hello the enc value MUST be empty */
14116+ ato16(readBuf_p, &localEncLen );
14117+ if (localEncLen != 0) {
1410814118 SendAlert(ssl, alert_fatal, illegal_parameter);
1410914119 return INVALID_PARAMETER;
1411014120 }
1411114121 readBuf_p += 2;
1411214122 }
14113- /* read hello inner len */
14123+
14124+ /* read payload (encrypted CH) len */
1411414125 ato16(readBuf_p, &ech->innerClientHelloLen);
14115- if (ech->innerClientHelloLen < WC_AES_BLOCK_SIZE) {
14126+ if (ech->innerClientHelloLen < WC_AES_BLOCK_SIZE ||
14127+ 10 + localEncLen + ech->innerClientHelloLen != size) {
1411614128 return BUFFER_ERROR;
1411714129 }
1411814130 ech->innerClientHelloLen -= WC_AES_BLOCK_SIZE;
1411914131 readBuf_p += 2;
1412014132 ech->outerClientPayload = readBuf_p;
14133+
1412114134 /* make a copy of the aad */
1412214135 aadCopy = (byte*)XMALLOC(ech->aadLen, ssl->heap,
1412314136 DYNAMIC_TYPE_TMP_BUFFER);
1412414137 if (aadCopy == NULL)
1412514138 return MEMORY_E;
1412614139 XMEMCPY(aadCopy, ech->aad, ech->aadLen);
14140+
1412714141 /* set the ech payload of the copy to zeros */
1412814142 XMEMSET(aadCopy + (readBuf_p - ech->aad), 0,
1412914143 ech->innerClientHelloLen + WC_AES_BLOCK_SIZE);
14130- /* free the old ech in case this is our second client hello */
14144+
14145+ /* free the old ech when this is the second client hello */
1413114146 if (ech->innerClientHello != NULL)
1413214147 XFREE(ech->innerClientHello, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
14148+
1413314149 /* allocate the inner payload buffer */
1413414150 ech->innerClientHello =
1413514151 (byte*)XMALLOC(ech->innerClientHelloLen + HANDSHAKE_HEADER_SZ,
@@ -14138,24 +14154,24 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size,
1413814154 XFREE(aadCopy, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
1413914155 return MEMORY_E;
1414014156 }
14141- /* first check if the config id matches */
14157+
14158+ /* try to decrypt with matching configId */
1414214159 echConfig = ssl->ctx->echConfigs;
1414314160 while (echConfig != NULL) {
14144- /* decrypt with this config */
1414514161 if (echConfig->configId == ech->configId) {
1414614162 ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
1414714163 ssl->heap);
1414814164 break;
1414914165 }
1415014166 echConfig = echConfig->next;
1415114167 }
14152- /* try to decrypt with all configs */
14168+ /* otherwise, try to decrypt with all configs */
1415314169 if (echConfig == NULL || ret != 0) {
1415414170 echConfig = ssl->ctx->echConfigs;
1415514171 while (echConfig != NULL) {
1415614172 ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen,
1415714173 ssl->heap);
14158- if (ret== 0)
14174+ if (ret == 0)
1415914175 break;
1416014176 echConfig = echConfig->next;
1416114177 }
0 commit comments