diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index c5f82a610..e3c07e625 100755 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -799,13 +799,13 @@ static word32 SetBitString(word32 len, byte unusedBits, byte* output) * returns ASN_PARSE_E if the BER data is invalid and BAD_FUNC_ARG if ber or * derSz are NULL. */ -int wc_BerToDer(byte* ber, word32 berSz, byte* der, word32* derSz) +int wc_BerToDer(const byte* ber, word32 berSz, byte* der, word32* derSz) { int ret; word32 i, j, k; int len, l; int indef; - int depth = 1; + int depth = 0; byte type; word32 cnt, sz; word32 outSz; @@ -818,7 +818,7 @@ int wc_BerToDer(byte* ber, word32 berSz, byte* der, word32* derSz) for (i = 0, j = 0; i < berSz; ) { /* Check that there is data for an ASN item to parse. */ - if (i + 1 > berSz) + if (i + 2 > berSz) return ASN_PARSE_E; /* End Of Content (EOC) mark end of indefinite length items. @@ -827,6 +827,8 @@ int wc_BerToDer(byte* ber, word32 berSz, byte* der, word32* derSz) * terminated in depth. */ if (ber[i] == 0 && ber[i+1] == 0) { + if (depth == 0) + break; if (--depth == 0) break; @@ -857,7 +859,7 @@ int wc_BerToDer(byte* ber, word32 berSz, byte* der, word32* derSz) i++; /* There must be further ASN1 items to combine. */ - if (i + 1 >= berSz) + if (i + 2 > berSz) return ASN_PARSE_E; /* Calculate length of combined data. */ @@ -876,7 +878,7 @@ int wc_BerToDer(byte* ber, word32 berSz, byte* der, word32* derSz) len += l; /* Must at least have terminating EOC. */ - if (k + 1 >= berSz) + if (k + 2 > berSz) return ASN_PARSE_E; } /* Ensure a valid EOC ASN item. */ @@ -976,6 +978,9 @@ int wc_BerToDer(byte* ber, word32 berSz, byte* der, word32* derSz) } } + if (depth >= 1) + return ASN_PARSE_E; + /* Return length if no buffer to write to. */ if (der == NULL) { *derSz = j; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 6d9b5bbbe..45678923d 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -316,6 +316,9 @@ int memory_test(void); #ifdef HAVE_VALGRIND int mp_test(void); #endif +#ifdef ASN_BER_TO_DER +int berder_test(void); +#endif int logging_test(void); int mutex_test(void); #if defined(USE_WOLFSSL_MEMORY) && !defined(FREERTOS) @@ -883,6 +886,13 @@ int wolfcrypt_test(void* args) printf( "mp test passed!\n"); #endif +#ifdef ASN_BER_TO_DER + if ( (ret = berder_test()) != 0) + return err_sys("ber-der test failed!\n", ret); + else + printf( "ber-der test passed!\n"); +#endif + if ( (ret = logging_test()) != 0) return err_sys("logging test failed!\n", ret); else @@ -17352,6 +17362,114 @@ done: } #endif +#ifdef ASN_BER_TO_DER +typedef struct berDerTestData { + const byte *in; + word32 inSz; + const byte *out; + word32 outSz; +} berDerTestData; + +int berder_test(void) +{ + int ret; + int i; + word32 len, l; + byte out[32]; + static const byte good1_in[] = { 0x30, 0x80, 0x00, 0x00 }; + static const byte good1_out[] = { 0x30, 0x00 }; + static const byte good2_in[] = { 0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00 }; + static const byte good2_out[] = { 0x30, 0x03, 0x02, 0x01, 0x01 }; + static const byte good3_in[] = { + 0x24, 0x80, 0x04, 0x01, 0x01, 0x00, 0x00 + }; + static const byte good3_out[] = { 0x04, 0x1, 0x01 }; + static const byte good4_in[] = { + 0x30, 0x80, + 0x02, 0x01, 0x01, + 0x30, 0x80, + 0x24, 0x80, + 0x04, 0x01, 0x01, + 0x04, 0x02, 0x02, 0x03, + 0x00, 0x00, + 0x06, 0x01, 0x01, + 0x00, 0x00, + 0x31, 0x80, + 0x06, 0x01, 0x01, + 0x00, 0x00, + 0x00, 0x00, + }; + static const byte good4_out[] = { + 0x30, 0x0d, + 0x02, 0x01, 0x01, + 0x30, 0x08, + 0x04, 0x03, 0x01, 0x02, 0x03, + 0x06, 0x01, 0x01, + 0x31, 0x03, + 0x06, 0x01, 0x01 + }; + + berDerTestData testData[] = { + { good1_in, sizeof(good1_in), good1_out, sizeof(good1_out) }, + { good2_in, sizeof(good2_in), good2_out, sizeof(good2_out) }, + { good3_in, sizeof(good3_in), good3_out, sizeof(good3_out) }, + { good4_in, sizeof(good4_in), good4_out, sizeof(good4_out) }, + }; + + for (i = 0; i < (int)(sizeof(testData) / sizeof(*testData)); i++) { + ret = wc_BerToDer(testData[i].in, testData[i].inSz, NULL, &len); + if (ret != LENGTH_ONLY_E) + return -7830 - i; + if (len != testData[i].outSz) + return -7840 - i; + len = testData[i].outSz; + ret = wc_BerToDer(testData[i].in, testData[i].inSz, out, &len); + if (ret != 0) + return -7850 - i; + if (XMEMCMP(out, testData[i].out, len) != 0) + return -7860 - i; + + for (l = 1; l < testData[i].inSz; l++) { + ret = wc_BerToDer(testData[i].in, l, NULL, &len); + if (ret != ASN_PARSE_E) + return -7870; + len = testData[i].outSz; + ret = wc_BerToDer(testData[i].in, l, out, &len); + if (ret != ASN_PARSE_E) + return -7871; + } + } + + ret = wc_BerToDer(NULL, 4, NULL, NULL); + if (ret != BAD_FUNC_ARG) + return -7880; + ret = wc_BerToDer(out, 4, NULL, NULL); + if (ret != BAD_FUNC_ARG) + return -7881; + ret = wc_BerToDer(NULL, 4, NULL, &len); + if (ret != BAD_FUNC_ARG) + return -7882; + ret = wc_BerToDer(NULL, 4, out, NULL); + if (ret != BAD_FUNC_ARG) + return -7883; + ret = wc_BerToDer(out, 4, out, NULL); + if (ret != BAD_FUNC_ARG) + return -7884; + ret = wc_BerToDer(NULL, 4, out, &len); + if (ret != BAD_FUNC_ARG) + return -7885; + + for (l = 1; l < sizeof(good4_out); l++) { + len = l; + ret = wc_BerToDer(good4_in, sizeof(good4_in), out, &len); + if (ret != BUFFER_E) + return -7890; + } + + return 0; +} +#endif + #ifdef DEBUG_WOLFSSL static THREAD_LS_T int log_cnt = 0; static void my_Logging_cb(const int logLevel, const char *const logMessage) diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 3be1029c3..2d43c6a89 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -766,7 +766,7 @@ struct TrustedPeerCert { #define WOLFSSL_ASN_API WOLFSSL_LOCAL #endif -WOLFSSL_ASN_API int wc_BerToDer(byte* ber, word32 berSz, byte* der, +WOLFSSL_ASN_API int wc_BerToDer(const byte* ber, word32 berSz, byte* der, word32* derSz); WOLFSSL_ASN_API void FreeAltNames(DNS_entry*, void*);