Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions doc/dox_comments/header_files/ecc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2151,9 +2151,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
Expand All @@ -2166,8 +2166,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
Expand Down
92 changes: 92 additions & 0 deletions tests/api/test_ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,79 @@ 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");
byte out[KEY20 * 2 + 1 + (sizeof("EccBlock Size 16") - 1) +
WC_SHA256_DIGEST_SIZE];
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);

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:
Expand Down Expand Up @@ -2477,6 +2550,25 @@ 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
{
/* An OID with more sub-identifiers than the internal decode array can
* hold must be rejected, not decoded past the end of that array. The
* first byte decodes to two arcs and every following byte to one, so
* MAX_OID_SZ bytes yield well over the MAX_OID_SZ/2 element capacity.
* Run under ASan to catch a regression. */
byte longOid[MAX_OID_SZ];
word32 i;

longOid[0] = 0x2A;
for (i = 1; i < (word32)sizeof(longOid); i++)
longOid[i] = 0x01;

ExpectIntEQ(wc_ecc_get_curve_id_from_oid(longOid, sizeof(longOid)),
WC_NO_ERR_TRACE(BUFFER_E));
}
#endif
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_get_curve_id_from_oid */
Expand Down
2 changes: 2 additions & 0 deletions tests/api/test_ecc.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,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);
Expand Down Expand Up @@ -104,6 +105,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), \
Expand Down
144 changes: 144 additions & 0 deletions tests/api/test_pkcs7.c
Original file line number Diff line number Diff line change
Expand Up @@ -4498,6 +4498,93 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
}
#endif /* !NO_AES && HAVE_AES_CBC && WOLFSSL_AES_256 && HAVE_AES_KEYWRAP */

#if !defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
defined(WOLFSSL_AES_256) && defined(ASN_BER_TO_DER) && \
!defined(NO_PKCS7_STREAM)
/* A BER EnvelopedData whose encryptedContent is a multi-segment
* indefinite-length OCTET STRING must never report more plaintext than it
* placed in the caller's buffer. Encode >1 segment (content > the 4096-byte
* streaming chunk), then decode with a full and an undersized output buffer.
* Run under ASan. */
{
/* 6000 spans two 4096-byte streaming segments (4096 + 1904) without
* being an exact multiple of the chunk size. */
const word32 bigSz = 6000;
const word32 halfSz = 4096; /* one segment: smaller than the total */
byte* bigContent = NULL;
byte* berOut = NULL;
byte* plainFull = NULL;
byte* plainSmall = NULL;
int berSz = 0;
int dSz;
word32 j;

bigContent = (byte*)XMALLOC(bigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
berOut = (byte*)XMALLOC(bigSz + FOURK_BUF, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER);
plainFull = (byte*)XMALLOC(bigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
/* exact-size small buffer so any over-write faults under ASan */
plainSmall = (byte*)XMALLOC(halfSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(bigContent);
ExpectNotNull(berOut);
ExpectNotNull(plainFull);
ExpectNotNull(plainSmall);
if (bigContent != NULL) {
for (j = 0; j < bigSz; j++)
bigContent[j] = (byte)j;
}

/* encode as BER (streaming) so encryptedContent is fragmented */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
if (pkcs7 != NULL) {
pkcs7->content = bigContent;
pkcs7->contentSz = bigSz;
pkcs7->contentOID = DATA;
pkcs7->encryptOID = AES256CBCb;
pkcs7->privateKey = rsaPrivKey;
pkcs7->privateKeySz = rsaPrivKeySz;
}
ExpectIntEQ(wc_PKCS7_SetStreamMode(pkcs7, 1, NULL, NULL, NULL), 0);
ExpectIntGT((berSz = wc_PKCS7_EncodeEnvelopedData(pkcs7, berOut,
bigSz + FOURK_BUF)), 0);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;

/* full-size output buffer: all segments returned and content matches */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
if (pkcs7 != NULL) {
pkcs7->privateKey = rsaPrivKey;
pkcs7->privateKeySz = rsaPrivKeySz;
}
dSz = wc_PKCS7_DecodeEnvelopedData(pkcs7, berOut, (word32)berSz,
plainFull, bigSz);
ExpectIntEQ(dSz, (int)bigSz);
ExpectIntEQ(XMEMCMP(plainFull, bigContent, bigSz), 0);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;

/* undersized output buffer: must fail, not report a length past it */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
if (pkcs7 != NULL) {
pkcs7->privateKey = rsaPrivKey;
pkcs7->privateKeySz = rsaPrivKeySz;
}
dSz = wc_PKCS7_DecodeEnvelopedData(pkcs7, berOut, (word32)berSz,
plainSmall, halfSz);
ExpectIntLT(dSz, 0);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;

XFREE(bigContent, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(berOut, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(plainFull, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(plainSmall, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif /* multi-segment BER bounds regression */

#ifndef NO_RSA
XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
Expand Down Expand Up @@ -4550,6 +4637,63 @@ 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. Encode such sizes and
* confirm they succeed; run under ASan.
*/
int test_wc_PKCS7_stream_encode_chunk_boundary(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
defined(WOLFSSL_AES_256) && defined(HAVE_AES_KEYWRAP) && \
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 };
static const byte keyId[] = { 0x00 };
word32 i;

for (i = 0; i < (word32)XELEM_CNT(contentSizes); i++) {
PKCS7* pkcs7 = NULL;
byte* content = NULL;
byte* ber = NULL;
word32 contentSz = contentSizes[i];
word32 berSz = contentSz + FOURK_BUF;
word32 j;

ExpectNotNull(content = (byte*)XMALLOC(contentSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectNotNull(ber = (byte*)XMALLOC(berSz, 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));
if (pkcs7 != NULL) {
pkcs7->content = content;
pkcs7->contentSz = contentSz;
pkcs7->contentOID = DATA;
pkcs7->encryptOID = AES256CBCb;
}
ExpectIntGT(wc_PKCS7_AddRecipient_KEKRI(pkcs7, AES256_WRAP,
(byte*)defKey, sizeof(defKey), (byte*)keyId, sizeof(keyId),
NULL, NULL, 0, NULL, 0, 0), 0);
ExpectIntEQ(wc_PKCS7_SetSignerIdentifierType(pkcs7, CMS_SKID), 0);
ExpectIntEQ(wc_PKCS7_SetStreamMode(pkcs7, 1, NULL, NULL, NULL), 0);
ExpectIntGT(wc_PKCS7_EncodeEnvelopedData(pkcs7, ber, berSz), 0);

wc_PKCS7_Free(pkcs7);
XFREE(content, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(ber, 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)
Expand Down
3 changes: 3 additions & 0 deletions tests/api/test_pkcs7.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ int test_wc_PKCS7_VerifySignedData_ECC(void);
int test_wc_PKCS7_VerifySignedData_ECC_TamperedAttribs(void);
int test_wc_PKCS7_DecodeEnvelopedData_stream(void);
int test_wc_PKCS7_EncodeDecodeEnvelopedData(void);
int test_wc_PKCS7_stream_encode_chunk_boundary(void);
int test_wc_PKCS7_SetAESKeyWrapUnwrapCb(void);
int test_wc_PKCS7_GetEnvelopedDataKariRid(void);
int test_wc_PKCS7_EncodeEncryptedData(void);
Expand Down Expand Up @@ -155,6 +156,8 @@ int test_wc_PKCS7_VerifySignedData_NoDigestParams(void);
#define TEST_PKCS7_ENCRYPTED_DATA_DECLS \
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_stream_encode_chunk_boundary), \
TEST_PKCS7_RSA_PSS_ED_DECL \
TEST_PKCS7_KTRI_BADRSAPAD_DECL \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \
Expand Down
8 changes: 5 additions & 3 deletions wolfcrypt/src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -17069,7 +17069,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
*/
Expand Down Expand Up @@ -17100,8 +17101,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
*/
Expand Down
18 changes: 7 additions & 11 deletions wolfcrypt/src/ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -4642,7 +4642,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;
Expand Down Expand Up @@ -16092,17 +16093,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) {
Expand Down
Loading
Loading