diff --git a/src/bio.c b/src/bio.c index b9dfe6b7dd..9d94144f57 100644 --- a/src/bio.c +++ b/src/bio.c @@ -631,6 +631,16 @@ static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data, if (len <= 0) return 0; /* Nothing to write */ + /* Reject sizes that would overflow the buffer growth calculation, which + * rounds the requested size up to the next multiple of 4/3 via + * (size + 3) / 3 * 4. The extra rounding slack means the safe ceiling is + * one below (INT_MAX / 4) * 3. Without this an oversized length grows a + * short buffer and copies past the source. */ + if (len > ((INT_MAX / 4) * 3) - 1 - bio->wrSz) { + WOLFSSL_MSG("write length too large"); + return WOLFSSL_BIO_ERROR; + } + if (wolfSSL_BUF_MEM_grow_ex(bio->mem_buf, ((size_t)bio->wrSz) + ((size_t)len), 0) == 0) { WOLFSSL_MSG("Error growing memory area"); diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 2b7c25f01b..7badd8e5f5 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -2222,6 +2222,7 @@ WOLFSSL_ASN1_OBJECT *wolfSSL_d2i_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT **a, WOLFSSL_ASN1_OBJECT* ret = NULL; int len = 0; word32 idx = 0; + word32 maxIdx; WOLFSSL_ENTER("wolfSSL_d2i_ASN1_OBJECT"); @@ -2231,7 +2232,17 @@ WOLFSSL_ASN1_OBJECT *wolfSSL_d2i_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT **a, return NULL; } - if (GetASNHeader(*der, ASN_OBJECT_ID, &idx, &len, (word32)length) < 0) { + /* An ASN.1 OBJECT is an OID, whose DER encoding cannot exceed the OID + * ceiling: a tag byte, a single short-form length byte (content is at + * most MAX_OID_SZ, which is below the long-form threshold) and the OID + * content. Cap the parse window so an oversized length argument cannot + * drive the header decode to read past the end of the actual buffer. */ + maxIdx = (word32)length; + if (maxIdx > (word32)(MAX_OID_SZ + 2)) { + maxIdx = (word32)(MAX_OID_SZ + 2); + } + + if (GetASNHeader(*der, ASN_OBJECT_ID, &idx, &len, maxIdx) < 0) { WOLFSSL_MSG("error getting tag"); return NULL; } @@ -3163,42 +3174,52 @@ int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data, int sz) * when sz == INT_MAX. By this point sz >= 0 (negative sz is * handled above as OpenSSL -1/strlen compat). */ size_t allocSz = (size_t)sz + 1; + char* oldData = asn1->data; + int oldDynamic = asn1->isDynamic; + char* dst; - /* Dispose of any existing dynamic data. */ - if (asn1->isDynamic) { - XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); - asn1->data = NULL; - } - - /* Check string will fit - including NUL. */ + /* Select the destination buffer WITHOUT disposing of the existing + * data yet. Deferring the free keeps the copy below safe even when + * the source aliases the object's own buffer (data == asn1->data), + * avoiding a use-after-free or clear-before-copy without needing an + * ephemeral allocation. */ if (allocSz > CTC_NAME_SIZE) { /* Allocate new buffer. */ - asn1->data = (char*)XMALLOC(allocSz, NULL, - DYNAMIC_TYPE_OPENSSL); - if (asn1->data == NULL) { + dst = (char*)XMALLOC(allocSz, NULL, DYNAMIC_TYPE_OPENSSL); + if (dst == NULL) { ret = 0; } - else { - /* Ensure buffer will be freed. */ - asn1->isDynamic = 1; - } } else { - /* Clear out fixed array and use it for data. */ - XMEMSET(asn1->strData, 0, CTC_NAME_SIZE); - asn1->data = asn1->strData; - asn1->isDynamic = 0; + /* Use the fixed array for data. */ + dst = asn1->strData; } - } - if (ret == 1) { - /* Check if there is a string to copy. */ - if (data != NULL) { - /* Copy string and append NUL. */ - XMEMCPY(asn1->data, data, (size_t)sz); - asn1->data[sz] = '\0'; + + if (ret == 1) { + /* Copy string and append NUL. XMEMMOVE handles the case where + * data aliases the fixed array (source and destination overlap). */ + if (data != NULL) { + XMEMMOVE(dst, data, (size_t)sz); + } + dst[sz] = '\0'; + + /* Clear any remainder of the fixed array (matches prior behavior + * of zeroing the whole array). Done after the copy so it never + * disturbs an aliased source. */ + if (dst == asn1->strData) { + XMEMSET(dst + sz + 1, 0, CTC_NAME_SIZE - (size_t)sz - 1); + } + + /* Dispose of any old dynamic buffer now the copy is complete. */ + if (oldDynamic && (oldData != dst)) { + XFREE(oldData, NULL, DYNAMIC_TYPE_OPENSSL); + } + + /* Commit the new buffer and its properties. */ + asn1->data = dst; + asn1->isDynamic = (allocSz > CTC_NAME_SIZE) ? 1 : 0; + asn1->length = sz; } - /* Set size of string. */ - asn1->length = sz; } return ret; diff --git a/src/tls13.c b/src/tls13.c index c5d767617e..dd1e8926f5 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -13590,6 +13590,16 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) case key_update: /* Valid on both sides. */ +#ifdef WOLFSSL_QUIC + /* RFC 9001 Section 6: QUIC performs key updates at the QUIC + * packet-protection layer, so a TLS KeyUpdate message must be + * rejected as a fatal unexpected_message connection error. */ + if (WOLFSSL_IS_QUIC(ssl)) { + WOLFSSL_MSG("KeyUpdate received over QUIC"); + WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E); + return SANITY_MSG_E; + } +#endif /* Check state. * Client and server must have received finished message from other * side. @@ -14976,6 +14986,13 @@ int Tls13UpdateKeys(WOLFSSL* ssl) if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version)) return BAD_FUNC_ARG; +#ifdef WOLFSSL_QUIC + /* RFC 9001 Section 6: a QUIC connection must not send a TLS KeyUpdate; + * key updates are handled at the QUIC packet-protection layer. */ + if (WOLFSSL_IS_QUIC(ssl)) + return BAD_FUNC_ARG; +#endif + #ifdef WOLFSSL_DTLS13 /* we are already waiting for the ack of a sent key update message. We can't send another one before receiving its ack. Either wolfSSL_update_keys() @@ -14995,7 +15012,8 @@ int Tls13UpdateKeys(WOLFSSL* ssl) * calling wolfSSL_write() will have the message sent when ready. * * ssl The SSL/TLS object. - * returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3, + * returns BAD_FUNC_ARG when ssl is NULL, not using TLS v1.3, or running over + * QUIC (RFC 9001 handles key updates at the QUIC packet-protection layer), * WOLFSSL_ERROR_WANT_WRITE when non-blocking I/O is not ready to write, * WOLFSSL_SUCCESS on success and otherwise failure. */ diff --git a/tests/api/test_camellia.c b/tests/api/test_camellia.c index cc1845e5ed..a5ef9e90cf 100644 --- a/tests/api/test_camellia.c +++ b/tests/api/test_camellia.c @@ -254,6 +254,48 @@ int test_wc_CamelliaCbcEncryptDecrypt(void) } /* END test_wc_CamelliaCbcEncryptDecrypt */ +/* + * Cipher operations must fail safely when no key has been configured. + */ +int test_wc_Camellia_MissingKey(void) +{ + EXPECT_DECLS; +#ifdef HAVE_CAMELLIA + wc_Camellia camellia; + static const byte plainT[] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A + }; + byte out[WC_CAMELLIA_BLOCK_SIZE]; + + XMEMSET(out, 0, sizeof(out)); + + /* Zeroed context, never keyed: every op must reject with MISSING_KEY + * rather than silently emitting unencrypted output. */ + XMEMSET(&camellia, 0, sizeof(camellia)); + + ExpectIntEQ(wc_CamelliaEncryptDirect(&camellia, out, plainT), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_CamelliaDecryptDirect(&camellia, out, plainT), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_CamelliaCbcEncrypt(&camellia, out, plainT, + WC_CAMELLIA_BLOCK_SIZE), WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_CamelliaCbcDecrypt(&camellia, out, plainT, + WC_CAMELLIA_BLOCK_SIZE), WC_NO_ERR_TRACE(MISSING_KEY)); + + /* Garbage key size that is not 128/192/256 must also be rejected. */ + XMEMSET(&camellia, 0, sizeof(camellia)); + camellia.keySz = 64; + + ExpectIntEQ(wc_CamelliaEncryptDirect(&camellia, out, plainT), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_CamelliaCbcEncrypt(&camellia, out, plainT, + WC_CAMELLIA_BLOCK_SIZE), WC_NO_ERR_TRACE(MISSING_KEY)); +#endif + return EXPECT_RESULT(); +} /* END test_wc_Camellia_MissingKey */ + + #include #define MC_CIPHER_TEST_COUNT 100 diff --git a/tests/api/test_camellia.h b/tests/api/test_camellia.h index 387faf73cc..d440810f10 100644 --- a/tests/api/test_camellia.h +++ b/tests/api/test_camellia.h @@ -29,6 +29,7 @@ int test_wc_CamelliaSetIV(void); int test_wc_CamelliaFree(void); int test_wc_CamelliaEncryptDecryptDirect(void); int test_wc_CamelliaCbcEncryptDecrypt(void); +int test_wc_Camellia_MissingKey(void); int test_wc_CamelliaCbc_MonteCarlo(void); #define TEST_CAMELLIA_DECLS \ @@ -37,6 +38,7 @@ int test_wc_CamelliaCbc_MonteCarlo(void); TEST_DECL_GROUP("camellia", test_wc_CamelliaFree), \ TEST_DECL_GROUP("camellia", test_wc_CamelliaEncryptDecryptDirect), \ TEST_DECL_GROUP("camellia", test_wc_CamelliaCbcEncryptDecrypt), \ + TEST_DECL_GROUP("camellia", test_wc_Camellia_MissingKey), \ TEST_DECL_GROUP("camellia", test_wc_CamelliaCbc_MonteCarlo) #endif /* WOLFCRYPT_TEST_CAMELLIA_H */ diff --git a/tests/api/test_evp.c b/tests/api/test_evp.c index 172bf3d2c1..4935669791 100644 --- a/tests/api/test_evp.c +++ b/tests/api/test_evp.c @@ -203,6 +203,25 @@ int test_wolfSSL_EVP_EncodeUpdate(void) sizeof(encBlock0)-1); ExpectStrEQ(encOutBuff, encBlock0); + /* oversized length must be rejected, not read past the input buffer */ + XMEMSET( encOutBuff,0, sizeof(encOutBuff)); + ExpectIntEQ(EVP_EncodeBlock(encOutBuff, plain0, 0x7FFFFFFF), -1); + + /* oversized length must be rejected by EVP_EncodeUpdate as well, rather + * than reading far past the caller's input buffer */ + EVP_EncodeInit(ctx); + outl = 1; + XMEMSET( encOutBuff,0, sizeof(encOutBuff)); + ExpectIntEQ( + EVP_EncodeUpdate( + ctx, + encOutBuff, + &outl, + plain0, + 0x7FFFFFFF), + 0); + ExpectIntEQ(outl, 0); + /* pass small size( < 48bytes ) input, then make sure they are not * encoded and just stored in ctx */ diff --git a/tests/api/test_ossl_asn1.c b/tests/api/test_ossl_asn1.c index f1b56c3f04..fc4a9d28e6 100644 --- a/tests/api/test_ossl_asn1.c +++ b/tests/api/test_ossl_asn1.c @@ -916,6 +916,8 @@ int test_wolfSSL_ASN1_get_object(void) const unsigned char objDerBadLen[] = { 0x30, 0x04 }; const unsigned char objDerNotObj[] = { 0x02, 0x01, 0x00 }; const unsigned char objDerNoData[] = { 0x06, 0x00 }; + /* OBJECT_ID header claims 126 content bytes but only one is present. */ + const unsigned char objDerOobLen[] = { 0x06, 0x7e, 0x2a }; const unsigned char* p; unsigned char objDer[10]; unsigned char* der; @@ -1018,6 +1020,10 @@ int test_wolfSSL_ASN1_get_object(void) ExpectNull(d2i_ASN1_OBJECT(&a, &p, sizeof(objDerNotObj))); p = objDerNoData; ExpectNull(d2i_ASN1_OBJECT(&a, &p, sizeof(objDerNoData))); + /* Oversized length must not let the header's claimed content length drive + * a read past the end of the actual buffer. */ + p = objDerOobLen; + ExpectNull(d2i_ASN1_OBJECT(&a, &p, INT_MAX)); /* Create an ASN OBJECT from content */ p = derBuf + 2; @@ -1188,6 +1194,22 @@ int test_wolfSSL_ASN1_STRING(void) ExpectIntEQ(ASN1_STRING_length(NULL), 0); ExpectIntGT(ASN1_STRING_length(str), 0); + /* Setting from the object's own buffer must not read freed/cleared data. + * Fixed-buffer case: data is held in the small array. */ + ExpectIntEQ(ASN1_STRING_set(str, (const void*)data, (int)XSTRLEN(data)), 1); + ExpectIntEQ(ASN1_STRING_set(str, ASN1_STRING_get0_data(str), + ASN1_STRING_length(str)), 1); + ExpectIntEQ(ASN1_STRING_length(str), (int)XSTRLEN(data)); + ExpectIntEQ(XMEMCMP(ASN1_STRING_get0_data(str), data, XSTRLEN(data)), 0); + /* Dynamic-buffer case: data is held in a heap allocation. */ + ExpectIntEQ(ASN1_STRING_set(str, (const void*)longData, + (int)XSTRLEN(longData)), 1); + ExpectIntEQ(ASN1_STRING_set(str, ASN1_STRING_get0_data(str), + ASN1_STRING_length(str)), 1); + ExpectIntEQ(ASN1_STRING_length(str), (int)XSTRLEN(longData)); + ExpectIntEQ(XMEMCMP(ASN1_STRING_get0_data(str), longData, + XSTRLEN(longData)), 0); + ASN1_STRING_free(c); ASN1_STRING_free(str); ASN1_STRING_free(NULL); diff --git a/tests/api/test_ossl_bio.c b/tests/api/test_ossl_bio.c index b111fd4468..6223ee8f93 100644 --- a/tests/api/test_ossl_bio.c +++ b/tests/api/test_ossl_bio.c @@ -1019,6 +1019,39 @@ int test_wolfSSL_BIO_read_negative_len(void) return EXPECT_RESULT(); } +/* A length larger than the source buffer must never reach XMEMCPY in the + * memory-BIO write path. A huge positive length on a fresh buffer would + * otherwise overflow the buffer growth calculation, allocate a short + * destination, and copy far past the small source. Verify such a length is + * rejected with an error, nothing is buffered, and normal writes still work. */ +int test_wolfSSL_BIO_write_large_len(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) + BIO* bio = NULL; + char msg[] = "large length test"; + int msgLen = (int)XSTRLEN(msg); + char out[64]; + + ExpectNotNull(bio = BIO_new(BIO_s_mem())); + + /* Oversized length on a fresh buffer: must be rejected with an error, not + * a wild copy from the small source buffer. */ + ExpectIntLT(BIO_write(bio, msg, (int)0x7FFFFFFF), 0); + /* Nothing should have been buffered. */ + ExpectIntEQ(BIO_pending(bio), 0); + + /* A normal write then read still returns the intact message. */ + ExpectIntEQ(BIO_write(bio, msg, msgLen), msgLen); + XMEMSET(out, 0, sizeof(out)); + ExpectIntEQ(BIO_read(bio, out, (int)sizeof(out)), msgLen); + ExpectIntEQ(XMEMCMP(out, msg, msgLen), 0); + + BIO_free(bio); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_BIO_printf(void) { diff --git a/tests/api/test_ossl_bio.h b/tests/api/test_ossl_bio.h index acf13fb776..7aac4f4add 100644 --- a/tests/api/test_ossl_bio.h +++ b/tests/api/test_ossl_bio.h @@ -36,6 +36,7 @@ int test_wolfSSL_BIO_s_null(void); int test_wolfSSL_BIO_accept(void); int test_wolfSSL_BIO_write(void); int test_wolfSSL_BIO_read_negative_len(void); +int test_wolfSSL_BIO_write_large_len(void); int test_wolfSSL_BIO_printf(void); int test_wolfSSL_BIO_f_md(void); int test_wolfSSL_BIO_up_ref(void); @@ -57,6 +58,7 @@ int test_wolfSSL_BIO_get_init(void); TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_s_null), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_write), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_read_negative_len), \ + TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_write_large_len), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_printf), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_f_md), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_up_ref), \ diff --git a/tests/api/test_rc2.c b/tests/api/test_rc2.c index 10b7194e4c..19f59e786a 100644 --- a/tests/api/test_rc2.c +++ b/tests/api/test_rc2.c @@ -228,6 +228,37 @@ int test_wc_Rc2CbcEncryptDecrypt(void) } /* END test_wc_Rc2CbcEncryptDecrypt */ +/* + * Cipher operations must fail safely when no key has been configured. + */ +int test_wc_Rc2_MissingKey(void) +{ + EXPECT_DECLS; +#ifdef WC_RC2 + Rc2 rc2; + byte out[RC2_BLOCK_SIZE]; + byte in[RC2_BLOCK_SIZE]; + + XMEMSET(out, 0, sizeof(out)); + XMEMSET(in, 0, sizeof(in)); + + /* Zeroed context, never keyed: every op must reject with MISSING_KEY + * rather than ciphering under an all-zero key schedule. */ + XMEMSET(&rc2, 0, sizeof(rc2)); + + ExpectIntEQ(wc_Rc2EcbEncrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Rc2EcbDecrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Rc2CbcEncrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Rc2CbcDecrypt(&rc2, out, in, RC2_BLOCK_SIZE), + WC_NO_ERR_TRACE(MISSING_KEY)); +#endif + return EXPECT_RESULT(); +} /* END test_wc_Rc2_MissingKey */ + + #define MC_CIPHER_TEST_COUNT 100 #define MC_RC2_MAX_DATA_SZ 1024 diff --git a/tests/api/test_rc2.h b/tests/api/test_rc2.h index acdd08e3ae..a9219494af 100644 --- a/tests/api/test_rc2.h +++ b/tests/api/test_rc2.h @@ -28,6 +28,7 @@ int test_wc_Rc2SetKey(void); int test_wc_Rc2SetIV(void); int test_wc_Rc2EcbEncryptDecrypt(void); int test_wc_Rc2CbcEncryptDecrypt(void); +int test_wc_Rc2_MissingKey(void); int test_wc_Rc2Cbc_MonteCarlo(void); int test_wc_Rc2Free(void); @@ -36,6 +37,7 @@ int test_wc_Rc2Free(void); TEST_DECL_GROUP("rc2", test_wc_Rc2SetIV), \ TEST_DECL_GROUP("rc2", test_wc_Rc2EcbEncryptDecrypt), \ TEST_DECL_GROUP("rc2", test_wc_Rc2CbcEncryptDecrypt), \ + TEST_DECL_GROUP("rc2", test_wc_Rc2_MissingKey), \ TEST_DECL_GROUP("rc2", test_wc_Rc2Cbc_MonteCarlo), \ TEST_DECL_GROUP("rc2", test_wc_Rc2Free) diff --git a/tests/quic.c b/tests/quic.c index 3e8ed2a428..e11f7bfb93 100644 --- a/tests/quic.c +++ b/tests/quic.c @@ -1470,6 +1470,56 @@ static int test_quic_server_hello_fail(int verbose) { return EXPECT_RESULT(); } +static int test_quic_key_update_rejected(int verbose) { + EXPECT_DECLS; + WOLFSSL_CTX * ctx_c = NULL; + WOLFSSL_CTX * ctx_s = NULL; + QuicTestContext tclient, tserver; + QuicConversation conv; + uint8_t lbuffer[16]; + size_t len; + int ret; + + ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method())); + ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method())); + ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile, + WOLFSSL_FILETYPE_PEM)); + ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile, + WOLFSSL_FILETYPE_PEM)); + + /* complete a normal QUIC handshake */ + QuicTestContext_init(&tclient, ctx_c, "client", verbose); + QuicTestContext_init(&tserver, ctx_s, "server", verbose); + QuicConversation_init(&conv, &tclient, &tserver); + QuicConversation_do(&conv); + + /* RFC 9001 section 6: a QUIC connection must not send a TLS KeyUpdate; + * key updates are handled at the QUIC packet-protection layer. The + * public wolfSSL_update_keys() must refuse on a QUIC connection. */ + ExpectIntEQ(wolfSSL_update_keys(tserver.ssl), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* RFC 9001 section 6: a TLS KeyUpdate handshake message must be rejected + * as a fatal unexpected_message connection error when running over QUIC. + * Feed a key_update (update_not_requested) as post-handshake CRYPTO data + * and confirm the server refuses to process it. */ + len = fake_record(key_update, OPAQUE8_LEN, lbuffer); + lbuffer[HANDSHAKE_HEADER_SZ] = update_not_requested; + ExpectIntEQ(wolfSSL_provide_quic_data(tserver.ssl, + wolfssl_encryption_application, lbuffer, len), WOLFSSL_SUCCESS); + ret = wolfSSL_process_quic_post_handshake(tserver.ssl); + ExpectIntEQ(ret, WC_NO_ERR_TRACE(SANITY_MSG_E)); + + QuicTestContext_free(&tclient); + QuicTestContext_free(&tserver); + + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + printf(" test_quic_key_update_rejected: %s\n", + EXPECT_RESULT() ? pass : fail); + return EXPECT_RESULT(); +} + /* This has gotten a bit out of hand. */ #if (defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ @@ -2005,6 +2055,7 @@ int QuicTest(void) #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) if ((ret = test_quic_server_hello(verbose)) != TEST_SUCCESS) goto leave; if ((ret = test_quic_server_hello_fail(verbose)) != TEST_SUCCESS) goto leave; + if ((ret = test_quic_key_update_rejected(verbose)) != TEST_SUCCESS) goto leave; #ifdef REALLY_HAVE_ALPN_AND_SNI if ((ret = test_quic_alpn(verbose)) != TEST_SUCCESS) goto leave; #endif /* REALLY_HAVE_ALPN_AND_SNI */ diff --git a/wolfcrypt/src/camellia.c b/wolfcrypt/src/camellia.c index 49541144e0..f89975ffd4 100644 --- a/wolfcrypt/src/camellia.c +++ b/wolfcrypt/src/camellia.c @@ -1562,11 +1562,21 @@ int wc_CamelliaSetIV(wc_Camellia* cam, const byte* iv) } +/* Returns 1 when a valid key has been configured, 0 otherwise. */ +static int CamelliaKeyIsSet(const wc_Camellia* cam) +{ + return (cam->keySz == 128 || cam->keySz == 192 || cam->keySz == 256); +} + + int wc_CamelliaEncryptDirect(wc_Camellia* cam, byte* out, const byte* in) { if (cam == NULL || out == NULL || in == NULL) { return BAD_FUNC_ARG; } + if (!CamelliaKeyIsSet(cam)) { + return MISSING_KEY; + } Camellia_EncryptBlock(cam->keySz, in, cam->key, out); return 0; @@ -1578,6 +1588,9 @@ int wc_CamelliaDecryptDirect(wc_Camellia* cam, byte* out, const byte* in) if (cam == NULL || out == NULL || in == NULL) { return BAD_FUNC_ARG; } + if (!CamelliaKeyIsSet(cam)) { + return MISSING_KEY; + } Camellia_DecryptBlock(cam->keySz, in, cam->key, out); return 0; @@ -1593,6 +1606,9 @@ int wc_CamelliaCbcEncrypt(wc_Camellia* cam, byte* out, const byte* in, word32 sz if (sz % WC_CAMELLIA_BLOCK_SIZE != 0) { return BAD_LENGTH_E; } + if (!CamelliaKeyIsSet(cam)) { + return MISSING_KEY; + } blocks = sz / WC_CAMELLIA_BLOCK_SIZE; while (blocks--) { @@ -1618,6 +1634,9 @@ int wc_CamelliaCbcDecrypt(wc_Camellia* cam, byte* out, const byte* in, word32 sz if (sz % WC_CAMELLIA_BLOCK_SIZE != 0) { return BAD_LENGTH_E; } + if (!CamelliaKeyIsSet(cam)) { + return MISSING_KEY; + } blocks = sz / WC_CAMELLIA_BLOCK_SIZE; while (blocks--) { diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 5001288338..66e66381b7 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -13266,6 +13266,11 @@ int wolfSSL_EVP_EncodeBlock(unsigned char *out, const unsigned char *in, if (inLen < 0) return WOLFSSL_FATAL_ERROR; + /* Reject lengths whose base64 output would overflow a positive int. This + * also guards against reads far past the caller's input allocation. */ + if (inLen > (INT_MAX / 4) * 3) + return WOLFSSL_FATAL_ERROR; + if (Base64_Encode_NoNl(in, (word32)inLen, out, &ret) == 0) return (int)ret; else @@ -13324,6 +13329,15 @@ int wolfSSL_EVP_EncodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx, *outl = 0; + if (inl < 0) + return 0; + + /* Reject lengths whose base64 output would overflow a positive int. This + * also guards against reads far past the caller's input allocation. */ + if (inl > (INT_MAX / (BASE64_ENCODE_RESULT_BLOCK_SIZE + 1)) * + BASE64_ENCODE_BLOCK_SIZE) + return 0; + /* if the remaining data exists in the ctx, add input data to them * to create a block(48bytes) for encoding */ diff --git a/wolfcrypt/src/rc2.c b/wolfcrypt/src/rc2.c index 3fd9ecbbac..f4050b97bf 100644 --- a/wolfcrypt/src/rc2.c +++ b/wolfcrypt/src/rc2.c @@ -171,6 +171,10 @@ int wc_Rc2EcbEncrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BUFFER_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + r10 = (word16)((word16)in[1] << 8) | in[0]; /* R[0] */ r32 = (word16)((word16)in[3] << 8) | in[2]; /* R[1] */ r54 = (word16)((word16)in[5] << 8) | in[4]; /* R[2] */ @@ -236,6 +240,10 @@ int wc_Rc2EcbDecrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BUFFER_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + r0 = (word16)((word16)in[1] << 8) | in[0]; r1 = (word16)((word16)in[3] << 8) | in[2]; r2 = (word16)((word16)in[5] << 8) | in[4]; @@ -285,14 +293,14 @@ int wc_Rc2CbcEncrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BAD_FUNC_ARG; } - if (sz == 0) { - return 0; - } - if (sz % RC2_BLOCK_SIZE != 0) { return BAD_LENGTH_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + blocks = sz / RC2_BLOCK_SIZE; while (blocks--) { @@ -320,14 +328,14 @@ int wc_Rc2CbcDecrypt(Rc2* rc2, byte* out, const byte* in, word32 sz) return BAD_FUNC_ARG; } - if (sz == 0) { - return 0; - } - if (sz % RC2_BLOCK_SIZE != 0) { return BAD_LENGTH_E; } + if (rc2->keylen == 0) { + return MISSING_KEY; + } + blocks = sz / RC2_BLOCK_SIZE; while (blocks--) {