diff --git a/doc/dox_comments/header_files/ecc.h b/doc/dox_comments/header_files/ecc.h index 74b39375288..8920d61c0f1 100644 --- a/doc/dox_comments/header_files/ecc.h +++ b/doc/dox_comments/header_files/ecc.h @@ -2267,9 +2267,9 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg, the encryption type specified by ctx. \return 0 Returned upon successfully decrypting the input message - \return BAD_FUNC_ARG Returned if privKey, pubKey, msg, msgSz, out, - or outSz are NULL, or the ctx object specifies an unsupported - encryption type + \return BAD_FUNC_ARG Returned if privKey, msg, msgSz, out, or outSz + are NULL (or pubKey is NULL when built with WOLFSSL_ECIES_OLD), or + the ctx object specifies an unsupported encryption type \return BAD_ENC_STATE_E Returned if the ctx object given is in a state that is not appropriate for decryption \return BUFFER_E Returned if the supplied output buffer is too @@ -2282,8 +2282,11 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg, \param privKey pointer to the ecc_key object containing the private key to use for decryption - \param pubKey pointer to the ecc_key object containing the public - key of the peer with whom one wishes to communicate + \param pubKey only used when built with WOLFSSL_ECIES_OLD: pointer to + the ecc_key object containing the public key of the peer with whom one + wishes to communicate. In the default message format the sender's + ephemeral public key is read from the start of msg instead and pubKey + is ignored (it may be NULL and is left unmodified) \param msg pointer to the buffer holding the ciphertext to decrypt \param msgSz size of the buffer to decrypt \param out pointer to the buffer in which to store the decrypted plaintext diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index f841b71421d..0e3ce3d58e6 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -2008,6 +2008,93 @@ int test_wc_ecc_encryptDecrypt(void) return EXPECT_RESULT(); } /* END test_wc_ecc_encryptDecrypt */ +/* + * In the default ECIES message format the sender's ephemeral public key is + * carried in the message, so wc_ecc_decrypt() must not free or overwrite a + * caller-supplied pubKey object. Confirm the object is byte-for-byte preserved + * across a decrypt. + */ +int test_wc_ecc_decrypt_pubkey_preserved(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \ + !defined(WOLFSSL_ECIES_OLD) && defined(HAVE_ECC_KEY_EXPORT) && \ + defined(HAVE_ECC_KEY_IMPORT) && \ + (defined(HAVE_AES_CBC) || \ + (defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \ + defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128) + ecc_key cliKey; + ecc_key srvKey; + ecc_key pubKey; + WC_RNG rng; + const char* msg = "EccBlock Size 16"; + word32 msgSz = (word32)XSTRLEN("EccBlock Size 16"); +#ifdef WOLFSSL_ECIES_GEN_IV + /* GEN_IV mode carries the nonce in the message as well */ + byte out[KEY20 * 2 + 1 + AES_BLOCK_SIZE + + (sizeof("EccBlock Size 16") - 1) + WC_SHA256_DIGEST_SIZE]; +#else + byte out[KEY20 * 2 + 1 + (sizeof("EccBlock Size 16") - 1) + + WC_SHA256_DIGEST_SIZE]; +#endif + word32 outSz = (word32)sizeof(out); + byte plain[sizeof("EccBlock Size 16")]; + word32 plainSz = (word32)sizeof(plain); + byte before[ECC_BUFSIZE]; + byte after[ECC_BUFSIZE]; + word32 beforeSz = (word32)sizeof(before); + word32 afterSz = (word32)sizeof(after); + + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(&cliKey, 0, sizeof(cliKey)); + XMEMSET(&srvKey, 0, sizeof(srvKey)); + XMEMSET(&pubKey, 0, sizeof(pubKey)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_ecc_init(&cliKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, KEY20, &cliKey), 0); + ExpectIntEQ(wc_ecc_init(&srvKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, KEY20, &srvKey), 0); + ExpectIntEQ(wc_ecc_init(&pubKey), 0); + /* Load a public key distinct from the sender's ephemeral (embedded in the + * message) so that overwriting pubKey would be detectable. */ + ExpectIntEQ(wc_ecc_export_x963(&srvKey, before, &beforeSz), 0); + ExpectIntEQ(wc_ecc_import_x963(before, beforeSz, &pubKey), 0); + +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \ + !defined(HAVE_SELFTEST) + ExpectIntEQ(wc_ecc_set_rng(&srvKey, &rng), 0); + ExpectIntEQ(wc_ecc_set_rng(&cliKey, &rng), 0); +#endif + + ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, (byte*)msg, msgSz, out, + &outSz, NULL), 0); + ExpectIntEQ(wc_ecc_decrypt(&srvKey, &pubKey, out, outSz, plain, &plainSz, + NULL), 0); + ExpectIntEQ(XMEMCMP(msg, plain, msgSz), 0); + + /* the caller's pubKey object must be unchanged after the decrypt */ + ExpectIntEQ(wc_ecc_export_x963(&pubKey, after, &afterSz), 0); + ExpectIntEQ(afterSz, beforeSz); + ExpectIntEQ(XMEMCMP(before, after, beforeSz), 0); + + /* pubKey is optional in this format: NULL must decrypt too */ + XMEMSET(plain, 0, sizeof(plain)); + plainSz = (word32)sizeof(plain); + ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain, &plainSz, + NULL), 0); + ExpectIntEQ(plainSz, msgSz); + ExpectIntEQ(XMEMCMP(msg, plain, msgSz), 0); + + wc_ecc_free(&pubKey); + wc_ecc_free(&srvKey); + wc_ecc_free(&cliKey); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} /* END test_wc_ecc_decrypt_pubkey_preserved */ + /* * Testing ECIES with the AES-256-GCM DEM. Exercises, each with its own * single-use client/server ctx pair: @@ -3318,6 +3405,24 @@ int test_wc_ecc_get_curve_id_from_oid(void) ExpectIntEQ(wc_ecc_get_curve_id_from_oid(oid, 0), ECC_CURVE_INVALID); /* Good Case */ ExpectIntEQ(wc_ecc_get_curve_id_from_oid(oid, len), ECC_SECP256R1); + +#ifdef HAVE_OID_DECODING + { + /* Length must stay just over the array's element capacity but under + * MAX_OID_SZ, or a byte-sized limit would also accept it. */ + #define ECC_OID_ELEMS (MAX_OID_SZ / (int)sizeof(word16)) + byte longOid[ECC_OID_ELEMS + 3]; + word32 i; + + longOid[0] = 0x2A; /* two arcs */ + for (i = 1; i < (word32)sizeof(longOid); i++) + longOid[i] = 0x01; /* one arc each */ + + ExpectIntEQ(wc_ecc_get_curve_id_from_oid(longOid, sizeof(longOid)), + WC_NO_ERR_TRACE(BUFFER_E)); + #undef ECC_OID_ELEMS + } +#endif #endif return EXPECT_RESULT(); } /* END test_wc_ecc_get_curve_id_from_oid */ diff --git a/tests/api/test_ecc.h b/tests/api/test_ecc.h index acaa4bb349b..d3928b009a4 100644 --- a/tests/api/test_ecc.h +++ b/tests/api/test_ecc.h @@ -56,6 +56,7 @@ int test_wc_ecc_ctx_set_peer_salt(void); int test_wc_ecc_ctx_set_info(void); int test_wc_ecc_ctx_getters(void); int test_wc_ecc_encryptDecrypt(void); +int test_wc_ecc_decrypt_pubkey_preserved(void); int test_wc_ecc_ecies_gcm(void); int test_wc_ecc_ecies_gcm_no_rng(void); int test_wc_ecc_ecies_cryptocb(void); @@ -109,6 +110,7 @@ int test_wc_EccDecisionCoverage4(void); TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_set_info), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_getters), \ TEST_DECL_GROUP("ecc", test_wc_ecc_encryptDecrypt), \ + TEST_DECL_GROUP("ecc", test_wc_ecc_decrypt_pubkey_preserved), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm_no_rng), \ TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_cryptocb), \ diff --git a/tests/api/test_ossl_p7p12.c b/tests/api/test_ossl_p7p12.c index 58cfa90d9d0..4cc99c3bb31 100644 --- a/tests/api/test_ossl_p7p12.c +++ b/tests/api/test_ossl_p7p12.c @@ -1045,7 +1045,8 @@ int test_wolfSSL_PEM_write_bio_PKCS7(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; @@ -1053,8 +1054,7 @@ int test_wolfSSL_PEM_write_bio_PKCS7(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -1062,8 +1062,7 @@ int test_wolfSSL_PEM_write_bio_PKCS7(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 33edd70075f..6d1015219b4 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -127,14 +127,14 @@ int test_wc_PKCS7_InitWithCert(void) XMEMSET(cert, 0, certSz); XMEMCPY(cert, client_cert_der_1024, sizeof_client_cert_der_1024); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; XFILE fp = XBADFILE; int certSz; ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -288,15 +288,15 @@ int test_wc_PKCS7_InitWithCert_guardrails(void) XMEMSET(cert, 0, sizeof(cert)); XMEMCPY(cert, client_cert_der_1024, sizeof_client_cert_der_1024); #else - byte cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + byte cert[TWOK_BUF]; XFILE fp = XBADFILE; int tmpCertSz; word32 certSz = 0; ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(tmpCertSz = (int)XFREAD(cert, 1, - sizeof_client_cert_der_1024, fp), 0); + ExpectIntGT(tmpCertSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); certSz = (word32)tmpCertSz; if (fp != XBADFILE) XFCLOSE(fp); @@ -368,7 +368,8 @@ int test_wc_PKCS7_EncodeData(void) XMEMCPY(cert, client_cert_der_1024, certSz); XMEMCPY(key, client_key_der_1024, keySz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; @@ -376,8 +377,7 @@ int test_wc_PKCS7_EncodeData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -385,8 +385,7 @@ int test_wc_PKCS7_EncodeData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -511,7 +510,8 @@ static int rsaSignRawDigestCb(PKCS7* pkcs7, byte* digest, word32 digestSz, #else { XFILE fp; - byte keyBuf[ONEK_BUF]; + /* key file is larger than ONEK_BUF */ + byte keyBuf[TWOK_BUF]; int keySz; fp = XFOPEN("./certs/client-key.der", "rb"); @@ -713,7 +713,7 @@ int test_wc_PKCS7_EncodeSignedData(void) XMEMCPY(cert, client_cert_der_2048, certSz); #elif defined(USE_CERT_BUFFERS_1024) byte key[sizeof_client_key_der_1024]; - byte cert[sizeof(sizeof_client_cert_der_1024)]; + byte cert[sizeof_client_cert_der_1024]; word32 keySz = (word32)sizeof(key); word32 certSz = (word32)sizeof(cert); XMEMSET(key, 0, keySz); @@ -721,7 +721,8 @@ int test_wc_PKCS7_EncodeSignedData(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; @@ -729,8 +730,7 @@ int test_wc_PKCS7_EncodeSignedData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -738,8 +738,7 @@ int test_wc_PKCS7_EncodeSignedData(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -1078,7 +1077,8 @@ int test_wc_PKCS7_EncodeSignedData_SKID(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - byte cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + byte cert[TWOK_BUF]; byte key[ONEK_BUF]; word32 certSz = 0; word32 keySz = 0; @@ -1813,7 +1813,7 @@ int test_wc_PKCS7_EncodeSignedData_ex(void) XMEMCPY(cert, client_cert_der_2048, certSz); #elif defined(USE_CERT_BUFFERS_1024) byte key[sizeof_client_key_der_1024]; - byte cert[sizeof(sizeof_client_cert_der_1024)]; + byte cert[sizeof_client_cert_der_1024]; word32 keySz = (word32)sizeof(key); word32 certSz = (word32)sizeof(cert); XMEMSET(key, 0, keySz); @@ -1821,16 +1821,16 @@ int test_wc_PKCS7_EncodeSignedData_ex(void) XMEMCPY(key, client_key_der_1024, keySz); XMEMCPY(cert, client_cert_der_1024, certSz); #else - unsigned char cert[ONEK_BUF]; + /* cert file is larger than ONEK_BUF */ + unsigned char cert[TWOK_BUF]; unsigned char key[ONEK_BUF]; XFILE fp = XBADFILE; int certSz; int keySz; - ExpectTure((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != + ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); - ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, - fp), 0); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof(cert), fp), 0); if (fp != XBADFILE) { XFCLOSE(fp); fp = XBADFILE; @@ -1838,8 +1838,7 @@ int test_wc_PKCS7_EncodeSignedData_ex(void) ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != XBADFILE); - ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), - 0); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof(key), fp), 0); if (fp != XBADFILE) XFCLOSE(fp); #endif @@ -5475,6 +5474,120 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) return EXPECT_RESULT(); } /* END test_wc_PKCS7_EncodeDecodeEnvelopedData() */ +/* + * The BER streaming encoder encrypts the content one 4096-byte octet chunk at a + * time into a working buffer, and the final chunk additionally carries the + * block cipher pad. Content that is an exact multiple of the chunk length makes + * that last chunk the largest one the buffer has to hold. Round-trip such sizes. + */ +int test_wc_PKCS7_stream_encode_chunk_boundary(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_AES) && \ + defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256) && \ + defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM) + /* multiples of the encoder's private BER_OCTET_LENGTH (4096) */ + static const word32 contentSizes[] = { 4096, 8192 }; + word32 i; + #if defined(USE_CERT_BUFFERS_2048) + byte cert[sizeof(client_cert_der_2048)]; + byte key[sizeof(client_key_der_2048)]; + word32 certSz = (word32)sizeof(cert); + word32 keySz = (word32)sizeof(key); + + XMEMCPY(cert, client_cert_der_2048, certSz); + XMEMCPY(key, client_key_der_2048, keySz); + #elif defined(USE_CERT_BUFFERS_1024) + byte cert[sizeof(client_cert_der_1024)]; + byte key[sizeof(client_key_der_1024)]; + word32 certSz = (word32)sizeof(cert); + word32 keySz = (word32)sizeof(key); + + XMEMCPY(cert, client_cert_der_1024, certSz); + XMEMCPY(key, client_key_der_1024, keySz); + #else + /* cert file is larger than ONEK_BUF */ + byte cert[TWOK_BUF]; + byte key[ONEK_BUF]; + word32 certSz = 0; + word32 keySz = 0; + XFILE fp = XBADFILE; + + ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != + XBADFILE); + ExpectIntGT(certSz = (word32)XFREAD(cert, 1, sizeof(cert), fp), 0); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } + ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != + XBADFILE); + ExpectIntGT(keySz = (word32)XFREAD(key, 1, sizeof(key), fp), 0); + if (fp != XBADFILE) + XFCLOSE(fp); + #endif + + for (i = 0; i < (word32)XELEM_CNT(contentSizes); i++) { + PKCS7* pkcs7 = NULL; + byte* content = NULL; + byte* ber = NULL; + byte* plain = NULL; + word32 contentSz = contentSizes[i]; + word32 berBufSz = contentSz + FOURK_BUF; + int encSz = 0; + word32 j; + + ExpectNotNull(content = (byte*)XMALLOC(contentSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(ber = (byte*)XMALLOC(berBufSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(plain = (byte*)XMALLOC(contentSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (content != NULL) { + for (j = 0; j < contentSz; j++) + content[j] = (byte)j; + } + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); + if (pkcs7 != NULL) { + pkcs7->content = content; + pkcs7->contentSz = contentSz; + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES256CBCb; + pkcs7->privateKey = key; + pkcs7->privateKeySz = keySz; + } + ExpectIntEQ(wc_PKCS7_SetStreamMode(pkcs7, 1, NULL, NULL, NULL), 0); + ExpectIntGT((encSz = wc_PKCS7_EncodeEnvelopedData(pkcs7, ber, + berBufSz)), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + /* decode back: a mis-sized or mis-split chunk shows up as corrupt + * plaintext or a parse failure */ + if (encSz > 0) { + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); + if (pkcs7 != NULL) { + pkcs7->privateKey = key; + pkcs7->privateKeySz = keySz; + } + ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, ber, (word32)encSz, + plain, contentSz), (int)contentSz); + ExpectIntEQ(XMEMCMP(plain, content, contentSz), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + } + + XFREE(content, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(ber, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_stream_encode_chunk_boundary() */ + #if defined(HAVE_PKCS7) && defined(HAVE_ECC) && defined(HAVE_X963_KDF) && \ !defined(NO_SHA256) && defined(WOLFSSL_AES_256) && defined(HAVE_AES_CBC) diff --git a/tests/api/test_pkcs7.h b/tests/api/test_pkcs7.h index b1958d84d0c..e4794d616aa 100644 --- a/tests/api/test_pkcs7.h +++ b/tests/api/test_pkcs7.h @@ -61,6 +61,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void); int test_wc_PKCS7_IndefiniteRecipientSet(void); int test_wc_PKCS7_SetAESKeyWrapUnwrapCb(void); int test_wc_PKCS7_MultipleRecipients(void); +int test_wc_PKCS7_stream_encode_chunk_boundary(void); int test_wc_PKCS7_GetEnvelopedDataKariRid(void); int test_wc_PKCS7_EncodeEncryptedData(void); int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void); @@ -168,6 +169,8 @@ int test_wc_PKCS7_VerifySignedData_NoDigestParams(void); TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeDecodeEnvelopedData), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_IndefiniteRecipientSet), \ + TEST_DECL_GROUP("pkcs7_ed", \ + test_wc_PKCS7_stream_encode_chunk_boundary), \ TEST_PKCS7_RSA_PSS_ED_DECL \ TEST_PKCS7_KTRI_BADRSAPAD_DECL \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \ diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index f7aa53f9eb1..fcad0d7bf53 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -17410,7 +17410,8 @@ static WARN_UNUSED_RESULT int wc_AesFeedbackCFB1( * out buffer to hold result of encryption (must be at least as large as input * buffer) * in buffer to encrypt (packed to left, i.e. 101 is 0x90) - * sz size of input buffer in bits (0x1 would be size of 1 and 0xFF size of 8) + * sz number of bits to process, e.g. 1 processes one bit and 8 one byte; + * in and out must hold at least (sz + 7) / 8 bytes * * returns 0 on success and negative values on failure */ @@ -17441,8 +17442,9 @@ int wc_AesCfb8Encrypt(Aes* aes, byte* out, const byte* in, word32 sz) * aes structure holding key to use for encryption * out buffer to hold result of encryption (must be at least as large as input * buffer) - * in buffer to encrypt - * sz size of input buffer in bits (0x1 would be size of 1 and 0xFF size of 8) + * in buffer to decrypt (packed to left, i.e. 101 is 0x90) + * sz number of bits to process, e.g. 1 processes one bit and 8 one byte; + * in and out must hold at least (sz + 7) / 8 bytes * * returns 0 on success and negative values on failure */ diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 0cc84908060..29babb06e95 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4672,7 +4672,8 @@ int wc_ecc_get_curve_id_from_oid(const byte* oid, word32 len) return BAD_FUNC_ARG; #ifdef HAVE_OID_DECODING - decOidSz = (word32)sizeof(decOid); + /* in elements, not bytes */ + decOidSz = (word32)(sizeof(decOid) / sizeof(decOid[0])); ret = DecodeObjectId(oid, len, decOid, &decOidSz); if (ret != 0) { return ret; @@ -16484,17 +16485,12 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, #endif #ifndef WOLFSSL_ECIES_OLD - if (pubKey == NULL) { - WC_ALLOC_VAR_EX(peerKey, ecc_key, 1, ctx->heap, - DYNAMIC_TYPE_ECC_BUFFER, ret=MEMORY_E); - pubKey = peerKey; - } - else { - /* if a public key was passed in we should free it here before init - * and import */ - wc_ecc_free(pubKey); - } + /* The ephemeral public key comes from the message; parse it into the + * local key object so a caller-supplied pubKey is left untouched. */ + WC_ALLOC_VAR_EX(peerKey, ecc_key, 1, ctx->heap, + DYNAMIC_TYPE_ECC_BUFFER, ret=MEMORY_E); if (ret == 0) { + pubKey = peerKey; ret = wc_ecc_init_ex(pubKey, privKey->heap, INVALID_DEVID); } if (ret == 0) { diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index ca0ccdd7432..d63d7925e66 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -594,7 +594,7 @@ static int fillBuff(WOLFSSL_EVP_CIPHER_CTX *ctx, const unsigned char *in, int sz if (sz > 0) { int fill; - if ((sz+ctx->bufUsed) > ctx->block_size) { + if (sz > ctx->block_size - ctx->bufUsed) { fill = ctx->block_size - ctx->bufUsed; } else { fill = sz; @@ -5002,22 +5002,6 @@ static int wolfSSL_evp_digest_pk_init(WOLFSSL_EVP_MD_CTX *ctx, return WOLFSSL_SUCCESS; } -/* Update an EVP_DigestSign/Verify operation. - * Update a digest for RSA and ECC keys, or HMAC for HMAC key. - */ -static int wolfssl_evp_digest_pk_update(WOLFSSL_EVP_MD_CTX *ctx, - const void *d, unsigned int cnt) -{ - if (ctx->isHMAC) { - if (wc_HmacUpdate(&ctx->hash.hmac, (const byte *)d, cnt) != 0) - return WOLFSSL_FAILURE; - - return WOLFSSL_SUCCESS; - } - else - return wolfSSL_EVP_DigestUpdate(ctx, d, cnt); -} - /* Finalize an EVP_DigestSign/Verify operation - common part only. * Finalize a digest for RSA and ECC keys, or HMAC for HMAC key. * Copies the digest so that you can keep updating. @@ -5160,14 +5144,14 @@ int wolfSSL_EVP_DigestSignInit(WOLFSSL_EVP_MD_CTX *ctx, int wolfSSL_EVP_DigestSignUpdate(WOLFSSL_EVP_MD_CTX *ctx, const void *d, - unsigned int cnt) + size_t cnt) { WOLFSSL_ENTER("EVP_DigestSignUpdate"); if (ctx == NULL || d == NULL) return WOLFSSL_FAILURE; - return wolfssl_evp_digest_pk_update(ctx, d, cnt); + return wolfSSL_EVP_DigestUpdate(ctx, d, cnt); } int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig, @@ -5286,7 +5270,7 @@ int wolfSSL_EVP_DigestSign(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sigret, if (sigret != NULL) { if (tbs == NULL) return WOLFSSL_FAILURE; - if (wolfSSL_EVP_DigestSignUpdate(ctx, tbs, (unsigned int)tbslen) + if (wolfSSL_EVP_DigestSignUpdate(ctx, tbs, tbslen) != WOLFSSL_SUCCESS) return WOLFSSL_FAILURE; } @@ -5316,7 +5300,7 @@ int wolfSSL_EVP_DigestVerifyUpdate(WOLFSSL_EVP_MD_CTX *ctx, const void *d, if (ctx == NULL || d == NULL) return WOLFSSL_FAILURE; - return wolfssl_evp_digest_pk_update(ctx, d, (unsigned int)cnt); + return wolfSSL_EVP_DigestUpdate(ctx, d, cnt); } @@ -6278,14 +6262,15 @@ void wolfSSL_EVP_init(void) WOLFSSL_ENTER("EVP_CIPHER_MD_CTX_copy_ex"); wolfSSL_EVP_MD_CTX_cleanup(out); XMEMCPY(out, in, sizeof(WOLFSSL_EVP_MD_CTX)); + /* Zero hash context after shallow copy to prevent shared sub-pointers + * with src, even if the pctx allocation below fails. The hash Copy + * function will perform the proper deep copy. */ + XMEMSET(&out->hash, 0, sizeof(out->hash)); if (in->pctx != NULL) { out->pctx = wolfSSL_EVP_PKEY_CTX_new(in->pctx->pkey, NULL); if (out->pctx == NULL) return WOLFSSL_FAILURE; } - /* Zero hash context after shallow copy to prevent shared sub-pointers - * with src. The hash Copy function will perform the proper deep copy. */ - XMEMSET(&out->hash, 0, sizeof(out->hash)); return wolfSSL_EVP_MD_Copy_Hasher(out, (WOLFSSL_EVP_MD_CTX*)in); } #ifndef NO_AES @@ -11817,15 +11802,14 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) return ret; } - /* WOLFSSL_SUCCESS on ok, WOLFSSL_FAILURE on failure */ - int wolfSSL_EVP_DigestUpdate(WOLFSSL_EVP_MD_CTX* ctx, const void* data, - size_t sz) + /* Update the digest with at most a word32 of data. + * WOLFSSL_SUCCESS on ok, WOLFSSL_FAILURE on failure */ + static int wolfssl_evp_digest_update_chunk(WOLFSSL_EVP_MD_CTX* ctx, + const void* data, word32 sz) { int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); enum wc_HashType macType; - WOLFSSL_ENTER("EVP_DigestUpdate"); - macType = EvpMd2MacType(wolfSSL_EVP_MD_CTX_md(ctx)); switch (macType) { case WC_HASH_TYPE_MD4: @@ -11984,6 +11968,55 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) return ret; } + /* WOLFSSL_SUCCESS on ok, WOLFSSL_FAILURE on failure */ + int wolfSSL_EVP_DigestUpdate(WOLFSSL_EVP_MD_CTX* ctx, const void* data, + size_t sz) + { + int ret; + + WOLFSSL_ENTER("EVP_DigestUpdate"); + + if (ctx == NULL) + return WOLFSSL_FAILURE; + /* A NULL buffer with nothing to hash is a valid no-op, as in + * wc_ShaUpdate(); a NULL buffer with data to hash is not. */ + if (sz == 0) + return WOLFSSL_SUCCESS; + if (data == NULL) + return WOLFSSL_FAILURE; + + /* The underlying update functions take a word32 length. Feed the data + * in chunks so the whole of sz is hashed instead of sz mod 2^32. + * Detect the narrowing by round-tripping rather than comparing against + * a constant, so this holds for any width of size_t. */ + do { + word32 chunk = (word32)sz; + if ((size_t)chunk != sz) + chunk = WC_MAX_UINT_OF(word32); + + #ifndef NO_HMAC + if (ctx->isHMAC) { + if (wc_HmacUpdate(&ctx->hash.hmac, (const byte*)data, + chunk) != 0) { + return WOLFSSL_FAILURE; + } + } + else + #endif + { + /* pass the sub-call's code through, e.g. NOT_COMPILED_IN */ + ret = wolfssl_evp_digest_update_chunk(ctx, data, chunk); + if (ret != WOLFSSL_SUCCESS) + return ret; + } + + data = (const byte*)data + chunk; + sz -= chunk; + } while (sz > 0); + + return WOLFSSL_SUCCESS; + } + /* WOLFSSL_SUCCESS on ok */ static int wolfSSL_EVP_DigestFinal_Common(WOLFSSL_EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s, enum wc_HashType macType) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 9040d3422fd..b87b2433236 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1894,16 +1894,18 @@ static int EncodeAttributes(EncodedAttrib* ea, int eaSz, PKCS7Attrib* attribs, int attribsSz) { int i; - int maxSz; word32 allAttribsSz = 0; if (eaSz < 0 || attribsSz < 0) { return BAD_FUNC_ARG; } - maxSz = (int)min((word32)eaSz, (word32)attribsSz); + /* every attribute must fit in the output array; do not silently drop */ + if (attribsSz > eaSz) { + return BUFFER_E; + } - for (i = 0; i < maxSz; i++) + for (i = 0; i < attribsSz; i++) { word32 attribSz = 0; word32 boundSz = 0; @@ -3526,8 +3528,22 @@ static int wc_PKCS7_EncodeContentStream(wc_PKCS7* pkcs7, ESD* esd, void* aes, idx += (word32)padSz; } + /* The pad can push the tail past a full chunk. StreamOctetString(), + * which sized the output, never emits more than BER_OCTET_LENGTH per + * octet string, so split here to match it. */ + if (ret == 0 && idx > BER_OCTET_LENGTH) { + ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType, aes, + encContentOut, contentData, BER_OCTET_LENGTH, out, + &outIdx, esd); + if (ret == 0) { + idx -= BER_OCTET_LENGTH; + XMEMMOVE(contentData, contentData + BER_OCTET_LENGTH, idx); + } + } + /* encrypt and flush out remainder of content data */ - ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType, aes, + if (ret == 0) + ret = wc_PKCS7_EncodeContentStreamHelper(pkcs7, cipherType, aes, encContentOut, contentData, (int)idx, out, &outIdx, esd); if (ret == 0) { if (cipherType == WC_CIPHER_NONE && esd && diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 55d23d2e6e5..971c700070a 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1485,6 +1485,10 @@ static WARN_UNUSED_RESULT int Hash_gen(DRBG_internal* drbg, byte* out, XMEMCPY(data, V, DRBG_SEED_LEN); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("Hash_gen data", data, DRBG_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE + /* cached digest is the caller's drbg->digest_scratch, already registered */ + wc_MemZero_Add("Hash_gen digest", digest, WC_SHA256_DIGEST_SIZE); +#endif #endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -1525,9 +1529,13 @@ static WARN_UNUSED_RESULT int Hash_gen(DRBG_internal* drbg, byte* out, } } ForceZero(data, DRBG_SEED_LEN); + ForceZero(digest, WC_SHA256_DIGEST_SIZE); #if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(data, DRBG_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_MemZero_Check(digest, WC_SHA256_DIGEST_SIZE); +#endif #endif #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -2152,6 +2160,9 @@ static WARN_UNUSED_RESULT int Hash512_gen(DRBG_SHA512_internal* drbg, XMEMCPY(data, V, DRBG_SHA512_SEED_LEN); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("Hash512_gen data", data, DRBG_SHA512_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_MemZero_Add("Hash512_gen digest", digest, WC_SHA512_DIGEST_SIZE); +#endif #endif for (i = 0; i < len; i++) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -2191,9 +2202,13 @@ static WARN_UNUSED_RESULT int Hash512_gen(DRBG_SHA512_internal* drbg, } } ForceZero(data, DRBG_SHA512_SEED_LEN); + ForceZero(digest, WC_SHA512_DIGEST_SIZE); #if (!defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_SMALL_STACK_CACHE)) && \ defined(WOLFSSL_CHECK_MEM_ZERO) wc_MemZero_Check(data, DRBG_SHA512_SEED_LEN); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_MemZero_Check(digest, WC_SHA512_DIGEST_SIZE); +#endif #endif #ifndef WOLFSSL_SMALL_STACK_CACHE diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index 32fa40464a8..532cb15e3a1 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -2330,6 +2330,7 @@ WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, { int n; int ret; + int first_ret = 0; time_t ts1 = 0; #ifdef WC_RNG_BANK_DEFAULT_SUPPORT int bank_is_default = 0; @@ -2545,7 +2546,14 @@ WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, { goto out; } + /* reseed the rest of the bank, keeping the first error seen for + * the return value */ + if ((ret != 0) && (first_ret == 0)) + first_ret = ret; + ret = WC_CHECK_FOR_INTR_SIGNALS(); + if ((ret != 0) && (first_ret == 0)) + first_ret = ret; if (ret == WC_NO_ERR_TRACE(INTERRUPTED_E)) goto out; WC_RELAX_LONG_LOOP(); @@ -2563,6 +2571,9 @@ WOLFSSL_API int wc_rng_bank_reseed_range(struct wc_rng_bank *bank, out: + if (first_ret != 0) + ret = first_ret; + #ifdef WC_RNG_BANK_DEFAULT_SUPPORT if (bank_is_default) (void)wc_rng_bank_default_checkin(&bank); diff --git a/wolfcrypt/src/srp.c b/wolfcrypt/src/srp.c index 44c48d45ef0..13d70e545ea 100644 --- a/wolfcrypt/src/srp.c +++ b/wolfcrypt/src/srp.c @@ -326,6 +326,13 @@ int wc_SrpSetUsername(Srp* srp, const byte* username, word32 size) if (!srp || !username) return BAD_FUNC_ARG; + if (srp->user) { + ForceZero(srp->user, srp->userSz); + XFREE(srp->user, srp->heap, DYNAMIC_TYPE_SRP); + srp->user = NULL; + srp->userSz = 0; + } + /* +1 for NULL char */ srp->user = (byte*)XMALLOC(size + 1, srp->heap, DYNAMIC_TYPE_SRP); if (srp->user == NULL) @@ -676,6 +683,13 @@ static int wc_SrpSetKey(Srp* srp, byte* secret, word32 size) XMEMSET(digest, 0, SRP_MAX_DIGEST_SIZE); + if (srp->key) { + ForceZero(srp->key, srp->keySz); + XFREE(srp->key, srp->heap, DYNAMIC_TYPE_SRP); + srp->key = NULL; + srp->keySz = 0; + } + srp->key = (byte*)XMALLOC(2 * (word32)digestSz, srp->heap, DYNAMIC_TYPE_SRP); if (srp->key == NULL) return MEMORY_E; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 0c1e4e44544..01e257ad6ba 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -40789,6 +40789,14 @@ static wc_test_ret_t srp_test_digest(SrpType dgstType) if (!r) r = wc_SrpVerifyPeersProof(cli, serverProof, serverProofSz); + /* Regression: a second wc_SrpSetUsername()/wc_SrpComputeKey() must release + * (and, for the key, zeroise) the buffer from the first call rather than + * leaking it. The exchange above is already verified; these repeat calls + * exercise the overwrite path so ASan flags a leak if it regresses. */ + if (!r) r = wc_SrpSetUsername(cli, username, usernameSz); + if (!r) r = wc_SrpComputeKey(cli, clientPubKey, clientPubKeySz, + serverPubKey, serverPubKeySz); + /* Negative test: corrupted proof must be rejected with SRP_VERIFY_E. */ if (!r) { int rNeg; @@ -79557,6 +79565,144 @@ static wc_test_ret_t pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCer return ret; } +#if !defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_128) +/* Boundary test for the fixed-size auth/unauth attribute arrays in + * wc_PKCS7_EncodeAuthEnvelopedData(): filling them to capacity must encode, + * while requesting one attribute more than fits must fail cleanly instead of + * writing past the arrays. Run under ASan to catch a regression. */ +static wc_test_ret_t pkcs7_authenv_attribs_boundary_test(byte* rsaCert, + word32 rsaCertSz, byte* rsaPrivKey, word32 rsaPrivKeySz) +{ + wc_test_ret_t ret = 0; + wc_PKCS7* pkcs7 = NULL; + byte* enveloped = NULL; + int envSz; + byte content[] = "authenv attribs boundary test"; + + /* one past either capacity, so the over-capacity cases stay in bounds */ +#if MAX_AUTH_ATTRIBS_SZ > MAX_UNAUTH_ATTRIBS_SZ + #define PKCS7_AE_ATTRIB_CNT (MAX_AUTH_ATTRIBS_SZ + 1) +#else + #define PKCS7_AE_ATTRIB_CNT (MAX_UNAUTH_ATTRIBS_SZ + 1) +#endif + static const byte val[] = { 0x13,0x01, 0x30 }; + byte oids[PKCS7_AE_ATTRIB_CNT][5]; + PKCS7Attrib attribs[PKCS7_AE_ATTRIB_CNT]; + word32 i; + + for (i = 0; i < (word32)PKCS7_AE_ATTRIB_CNT; i++) { + oids[i][0] = 0x06; oids[i][1] = 0x03; + oids[i][2] = 0x55; oids[i][3] = 0x04; + oids[i][4] = (byte)(0x03 + i); + attribs[i].oid = oids[i]; + attribs[i].oidSz = (word32)sizeof(oids[i]); + attribs[i].value = val; + attribs[i].valueSz = (word32)sizeof(val); + } + + enveloped = (byte*)XMALLOC(PKCS7_BUF_SIZE, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (enveloped == NULL) + return WC_TEST_RET_ENC_ERRNO; + + /* contentOID == DATA so no contentType attribute is auto-added; all + * MAX_AUTH_ATTRIBS_SZ slots are available to the user attributes. */ + + /* exactly MAX_AUTH_ATTRIBS_SZ authenticated attributes: must encode */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->authAttribs = attribs; + pkcs7->authAttribsSz = MAX_AUTH_ATTRIBS_SZ; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz <= 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); + + /* one more authenticated attribute than fits: must fail, not overrun */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->authAttribs = attribs; + pkcs7->authAttribsSz = MAX_AUTH_ATTRIBS_SZ + 1; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz != WC_NO_ERR_TRACE(BUFFER_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); + + /* one more unauthenticated attribute than fits: must fail, not overrun */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->unauthAttribs = attribs; + pkcs7->unauthAttribsSz = MAX_UNAUTH_ATTRIBS_SZ + 1; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz != WC_NO_ERR_TRACE(BUFFER_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); + + /* non-DATA contentOID adds a contentType attrib, leaving one slot fewer */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + ret = wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + pkcs7->content = content; + pkcs7->contentSz = (word32)XSTRLEN((char*)content); + pkcs7->contentOID = FIRMWARE_PKG_DATA; + pkcs7->encryptOID = AES128GCMb; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->authAttribs = attribs; + pkcs7->authAttribsSz = MAX_AUTH_ATTRIBS_SZ; + envSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, PKCS7_BUF_SIZE); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + if (envSz != WC_NO_ERR_TRACE(BUFFER_E)) + ERROR_OUT(WC_TEST_RET_ENC_EC(envSz), out); + + ret = 0; + +out: + if (pkcs7 != NULL) + wc_PKCS7_Free(pkcs7); + XFREE(enveloped, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} +#endif /* RSA + AESGCM + keywrap + AES128 */ + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs7authenveloped_test(void) { wc_test_ret_t ret = 0; @@ -79634,6 +79780,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs7authenveloped_test(void) eccCert, (word32)eccCertSz, eccPrivKey, (word32)eccPrivKeySz); +#if !defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(HAVE_AES_KEYWRAP) && defined(WOLFSSL_AES_128) + if (ret == 0) + ret = pkcs7_authenv_attribs_boundary_test(rsaCert, (word32)rsaCertSz, + rsaPrivKey, (word32)rsaPrivKeySz); +#endif + #ifndef NO_RSA XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 26cc0261b5d..c525e3a9c17 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -869,7 +869,7 @@ WOLFSSL_API int wolfSSL_EVP_DigestFinal_ex(WOLFSSL_EVP_MD_CTX* ctx, WOLFSSL_API int wolfSSL_EVP_DigestFinalXOF(WOLFSSL_EVP_MD_CTX* ctx, unsigned char* md, size_t sz); WOLFSSL_API int wolfSSL_EVP_DigestSignUpdate(WOLFSSL_EVP_MD_CTX *ctx, - const void *d, unsigned int cnt); + const void *d, size_t cnt); WOLFSSL_API int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig, size_t *siglen); WOLFSSL_API int wolfSSL_EVP_DigestSign(WOLFSSL_EVP_MD_CTX *ctx,