diff --git a/CMakeLists.txt b/CMakeLists.txt index a33712f03..0e061fc77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2636,6 +2636,7 @@ if(WOLFSSL_EXAMPLES) tests/api/test_tls_ext.c tests/api/test_tls.c tests/api/test_x509.c + tests/api/test_asn.c tests/srp.c tests/suites.c tests/w64wrapper.c diff --git a/tests/api.c b/tests/api.c index 6b67b6ed6..6e5fbd64c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -332,6 +332,7 @@ #include #include #include +#include #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \ !defined(NO_RSA) && !defined(SINGLE_THREADED) && \ @@ -67446,6 +67447,9 @@ TEST_CASE testCases[] = { /* x509 */ TEST_X509_DECLS, + /* ASN */ + TEST_ASN_DECLS, + /* PEM and DER APIs. */ TEST_DECL(test_wc_PemToDer), TEST_DECL(test_wc_AllocDer), diff --git a/tests/api/include.am b/tests/api/include.am index 14a7a5468..7a5b5048c 100644 --- a/tests/api/include.am +++ b/tests/api/include.am @@ -56,6 +56,8 @@ tests_unit_test_SOURCES += tests/api/test_tls_ext.c tests_unit_test_SOURCES += tests/api/test_tls.c # Certs tests_unit_test_SOURCES += tests/api/test_x509.c +# ASN +tests_unit_test_SOURCES += tests/api/test_asn.c endif EXTRA_DIST += tests/api/api.h @@ -108,4 +110,5 @@ EXTRA_DIST += tests/api/test_evp.h EXTRA_DIST += tests/api/test_tls_ext.h EXTRA_DIST += tests/api/test_tls.h EXTRA_DIST += tests/api/test_x509.h +EXTRA_DIST += tests/api/test_asn.h diff --git a/tests/api/test_asn.c b/tests/api/test_asn.c new file mode 100644 index 000000000..ad14069af --- /dev/null +++ b/tests/api/test_asn.c @@ -0,0 +1,175 @@ +/* test_asn.c + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include + +#include + +static int test_SetShortInt_once(word32 val, byte* valDer, word32 valDerSz) +{ + EXPECT_DECLS; + +#ifndef NO_PWDBASED +#if !defined(WOLFSSL_ASN_TEMPLATE) || defined(HAVE_PKCS8) || \ + defined(HAVE_PKCS12) + + byte outDer[MAX_SHORT_SZ]; + word32 outDerSz = 0; + word32 inOutIdx = 0; + word32 maxIdx = MAX_SHORT_SZ; + + ExpectIntLE(2 + valDerSz, MAX_SHORT_SZ); + ExpectIntEQ(outDerSz = SetShortInt(outDer, &inOutIdx, val, maxIdx), + 2 + valDerSz); + ExpectIntEQ(outDer[0], ASN_INTEGER); + ExpectIntEQ(outDer[1], valDerSz); + ExpectIntEQ(XMEMCMP(outDer + 2, valDer, valDerSz), 0); + +#endif /* !WOLFSSL_ASN_TEMPLATE || HAVE_PKCS8 || HAVE_PKCS12 */ +#endif /* !NO_PWDBASED */ + + (void)val; + (void)valDer; + (void)valDerSz; + + return EXPECT_RESULT(); +} + +int test_SetShortInt(void) +{ + EXPECT_DECLS; + + byte valDer[MAX_SHORT_SZ] = {0}; + + /* Corner tests for input size */ + { + /* Input 1 byte min */ + valDer[0] = 0x00; + EXPECT_TEST(test_SetShortInt_once(0x00, valDer, 1)); + + /* Input 1 byte max */ + valDer[0] = 0x00; + valDer[1] = 0xff; + EXPECT_TEST(test_SetShortInt_once(0xff, valDer, 2)); + + /* Input 2 bytes min */ + valDer[0] = 0x01; + valDer[1] = 0x00; + EXPECT_TEST(test_SetShortInt_once(0x0100, valDer, 2)); + + /* Input 2 bytes max */ + valDer[0] = 0x00; + valDer[1] = 0xff; + valDer[2] = 0xff; + EXPECT_TEST(test_SetShortInt_once(0xffff, valDer, 3)); + + /* Input 3 bytes min */ + valDer[0] = 0x01; + valDer[1] = 0x00; + valDer[2] = 0x00; + EXPECT_TEST(test_SetShortInt_once(0x010000, valDer, 3)); + + /* Input 3 bytes max */ + valDer[0] = 0x00; + valDer[1] = 0xff; + valDer[2] = 0xff; + valDer[3] = 0xff; + EXPECT_TEST(test_SetShortInt_once(0xffffff, valDer, 4)); + + /* Input 4 bytes min */ + valDer[0] = 0x01; + valDer[1] = 0x00; + valDer[2] = 0x00; + valDer[3] = 0x00; + EXPECT_TEST(test_SetShortInt_once(0x01000000, valDer, 4)); + + /* Input 4 bytes max */ + valDer[0] = 0x00; + valDer[1] = 0xff; + valDer[2] = 0xff; + valDer[3] = 0xff; + valDer[4] = 0xff; + EXPECT_TEST(test_SetShortInt_once(0xffffffff, valDer, 5)); + } + + /* Corner tests for output size */ + { + /* Skip "Output 1 byte min" because of same as "Input 1 byte min" */ + + /* Output 1 byte max */ + valDer[0] = 0x7f; + EXPECT_TEST(test_SetShortInt_once(0x7f, valDer, 1)); + + /* Output 2 bytes min */ + valDer[0] = 0x00; + valDer[1] = 0x80; + EXPECT_TEST(test_SetShortInt_once(0x80, valDer, 2)); + + /* Output 2 bytes max */ + valDer[0] = 0x7f; + valDer[1] = 0xff; + EXPECT_TEST(test_SetShortInt_once(0x7fff, valDer, 2)); + + /* Output 3 bytes min */ + valDer[0] = 0x00; + valDer[1] = 0x80; + valDer[2] = 0x00; + EXPECT_TEST(test_SetShortInt_once(0x8000, valDer, 3)); + + /* Output 3 bytes max */ + valDer[0] = 0x7f; + valDer[1] = 0xff; + valDer[2] = 0xff; + EXPECT_TEST(test_SetShortInt_once(0x7fffff, valDer, 3)); + + /* Output 4 bytes min */ + valDer[0] = 0x00; + valDer[1] = 0x80; + valDer[2] = 0x00; + valDer[3] = 0x00; + EXPECT_TEST(test_SetShortInt_once(0x800000, valDer, 4)); + + /* Output 4 bytes max */ + valDer[0] = 0x7f; + valDer[1] = 0xff; + valDer[2] = 0xff; + valDer[3] = 0xff; + EXPECT_TEST(test_SetShortInt_once(0x7fffffff, valDer, 4)); + + /* Output 5 bytes min */ + valDer[0] = 0x00; + valDer[1] = 0x80; + valDer[2] = 0x00; + valDer[3] = 0x00; + valDer[4] = 0x00; + EXPECT_TEST(test_SetShortInt_once(0x80000000, valDer, 5)); + + /* Skip "Output 5 bytes max" because of same as "Input 4 bytes max" */ + } + + /* Extra tests */ + { + valDer[0] = 0x01; + EXPECT_TEST(test_SetShortInt_once(0x01, valDer, 1)); + } + + return EXPECT_RESULT(); +} diff --git a/tests/api/test_asn.h b/tests/api/test_asn.h new file mode 100644 index 000000000..9cd5f60d9 --- /dev/null +++ b/tests/api/test_asn.h @@ -0,0 +1,32 @@ +/* test_asn.h + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifndef WOLFCRYPT_TEST_ASN_H +#define WOLFCRYPT_TEST_ASN_H + +#include + +int test_SetShortInt(void); + +#define TEST_ASN_DECLS \ + TEST_DECL_GROUP("asn", test_SetShortInt) \ + +#endif /* WOLFCRYPT_TEST_ASN_H */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 1ef5a422b..cb20eb5ea 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -3252,22 +3252,31 @@ int SetShortInt(byte* output, word32* inOutIdx, word32 number, word32 maxIdx) word32 idx = *inOutIdx; word32 len; int i; + word32 extraByte = 0; if (number == 0) len = 1; else len = BytePrecision(number); + if (number >> (WOLFSSL_BIT_SIZE * len - 1)) { + /* Need one byte of zero value not to be negative number */ + extraByte = 1; + } + /* check for room for type and length bytes. */ - if ((idx + 2 + len) > maxIdx) + if ((idx + 2 + extraByte + len) > maxIdx) return BUFFER_E; /* check that MAX_SHORT_SZ allows this size of ShortInt. */ - if (2 + len > MAX_SHORT_SZ) + if (2 + extraByte + len > MAX_SHORT_SZ) return ASN_PARSE_E; output[idx++] = ASN_INTEGER; - output[idx++] = (byte)len; + output[idx++] = (byte)(len + extraByte); + if (extraByte) { + output[idx++] = 0x00; + } for (i = (int)len - 1; i >= 0; --i) output[idx++] = (byte)(number >> (i * WOLFSSL_BIT_SIZE)); @@ -9565,6 +9574,8 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz, word32 encIdx = 0; const byte* hmacOidBuf = NULL; word32 hmacOidBufSz = 0; + byte tmpShort[MAX_SHORT_SZ]; + word32 tmpIdx = 0; (void)heap; @@ -9587,9 +9598,14 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz, if (ret == 0) { padSz = (word32)((blockSz - ((int)keySz & (blockSz - 1))) & (blockSz - 1)); - /* inner = OCT salt INT itt */ - innerLen = 2 + saltSz + 2 + ((itt < 256) ? 1 : ((itt < 65536) ? 2 : 3)); - + ret = SetShortInt(tmpShort, &tmpIdx, (word32)itt, MAX_SHORT_SZ); + if (ret > 0) { + /* inner = OCT salt INT itt */ + innerLen = 2 + saltSz + (word32)ret; + ret = 0; + } + } + if (ret == 0) { if (version != PKCS5v2) { pbeOidBuf = OidFromId((word32)pbeId, oidPBEType, &pbeOidBufSz); /* pbe = OBJ pbse1 SEQ [ inner ] */ diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 61c515987..fc484dff8 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2202,7 +2202,7 @@ WOLFSSL_LOCAL byte GetCertNameId(int idx); #endif WOLFSSL_LOCAL int GetShortInt(const byte* input, word32* inOutIdx, int* number, word32 maxIdx); -WOLFSSL_LOCAL int SetShortInt(byte* input, word32* inOutIdx, word32 number, +WOLFSSL_TEST_VIS int SetShortInt(byte* input, word32* inOutIdx, word32 number, word32 maxIdx); WOLFSSL_LOCAL const char* GetSigName(int oid); diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 2cff19c4c..2f1dcbfe7 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -2021,7 +2021,7 @@ enum Max_ASN { MAX_SIG_SZ = 256, MAX_ALGO_SZ = 20, MAX_LENGTH_SZ = WOLFSSL_ASN_MAX_LENGTH_SZ, /* Max length size for DER encoding */ - MAX_SHORT_SZ = (1 + MAX_LENGTH_SZ), /* asn int + byte len + 4 byte length */ + MAX_SHORT_SZ = (1 + 1 + 5), /* asn int + byte len + 5 byte length */ MAX_SEQ_SZ = (1 + MAX_LENGTH_SZ), /* enum(seq | con) + length(5) */ MAX_SET_SZ = (1 + MAX_LENGTH_SZ), /* enum(set | con) + length(5) */ MAX_OCTET_STR_SZ = (1 + MAX_LENGTH_SZ), /* enum(set | con) + length(5) */