From e0f2e3e0311e76523ba2724c387287d7e2cfa71b Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 1 Oct 2026 16:35:46 -0700 Subject: [PATCH 1/4] Add a wolfCrypt-only CMake option and fix stray defines in options.h --- .github/workflows/cmake.yml | 61 ++++++++++++++++++++++++++++++ CMakeLists.txt | 74 +++++++++++++++++++++++++++++++++++++ cmake/functions.cmake | 4 ++ cmake/options.h.in | 2 + 4 files changed, 141 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 7a42c7e70cf..80b414e8679 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -111,6 +111,67 @@ jobs: cd .. rm -rf build +# Option plumbing: a declared option must reach both the library and +# options.h, and a -D that is not an option must reach neither. + - name: Check option to options.h plumbing + run: | + mkdir build + cd build + cmake -DWOLFSSL_CRYPT_ONLY=yes .. 2>&1 | tee cfg.log + grep -q '^#define WOLFCRYPT_ONLY$' wolfssl/options.h + grep -q '^#define NO_TLS$' wolfssl/options.h + # TLS-layer options default off, as with --enable-cryptonly, but the + # TLS 1.3 KDFs stay. + ! grep -q '^#define HAVE_SNI$' wolfssl/options.h + ! grep -q '^#define WOLFSSL_DTLS$' wolfssl/options.h + grep -q '^#define WOLFSSL_TLS13$' wolfssl/options.h + ! grep -q 'is not a wolfSSL build option' cfg.log + cmake --build . + + cd .. + rm -rf build + mkdir build + cd build + # Adding cryptonly to a directory configured without it must take the + # TLS layer out too, not leave the previous defaults cached. + cmake .. > /dev/null + grep -q '^#define HAVE_SNI$' wolfssl/options.h + cmake -DWOLFSSL_CRYPT_ONLY=yes .. > /dev/null + ! grep -q '^#define HAVE_SNI$' wolfssl/options.h + grep -q '^#define NO_TLS$' wolfssl/options.h + + cd .. + rm -rf build + mkdir build + cd build + # Cryptonly wins over a TLS-layer option asked for alongside it. + cmake -DWOLFSSL_CRYPT_ONLY=yes -DWOLFSSL_DTLS=yes .. > /dev/null + ! grep -q '^#define WOLFSSL_DTLS$' wolfssl/options.h + + cd .. + rm -rf build + mkdir build + cd build + # An option declared with a raw CACHE entry rather than add_option must + # survive the stray-define guard, including across a reconfigure. + cmake -DWOLFSSL_HARDEN_TLS=128 .. 2>&1 | tee cfg.log + grep -q '^#define WOLFSSL_HARDEN_TLS 128$' wolfssl/options.h + ! grep -q 'is not a wolfSSL build option' cfg.log + cmake . > /dev/null + grep -q '^#define WOLFSSL_HARDEN_TLS 128$' wolfssl/options.h + + cd .. + rm -rf build + mkdir build + cd build + # WOLFSSL_STATICMEMORY is the option; this spelling is not one. + cmake -DWOLFSSL_STATIC_MEMORY=yes .. 2>&1 | tee cfg.log + grep -q 'WOLFSSL_STATIC_MEMORY is not a wolfSSL build option' cfg.log + ! grep -q '^#define WOLFSSL_STATIC_MEMORY$' wolfssl/options.h + + cd .. + rm -rf build + # CMake build with user_settings.h - name: Build wolfssl with user_settings.h run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aef3bbc3ca..f2133ce5553 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -632,6 +632,35 @@ if(WOLFSSL_DEBUG) endif() +# wolfCrypt only (no TLS). Declared ahead of the TLS-layer options so the +# forces below land before their add_option() calls. +add_option("WOLFSSL_CRYPT_ONLY" + "Enable wolfCrypt Only build (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_CRYPT_ONLY) + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFCRYPT_ONLY") + # Mirror --enable-cryptonly: turn the TLS-layer options off so options.h + # describes the library that was built. These are forced rather than + # defaulted, because a cache entry cannot be told apart from an explicit + # setting on a reconfigure, and a header claiming a TLS feature that has + # no TLS layer behind it is the failure this is here to prevent. + # WOLFSSL_TLS carries -DNO_TLS itself, and the TLS-version checks read it + # to know a cryptonly build has no handshake. TLS 1.2 and 1.3 stay + # enabled -- their KDFs are wolfCrypt-layer code a cryptonly build wants. + foreach(_o WOLFSSL_TLS + WOLFSSL_ALPN WOLFSSL_CRL_MONITOR WOLFSSL_DTLS WOLFSSL_DTLS13 + WOLFSSL_DTLS_CH_FRAG WOLFSSL_DTLS_CID WOLFSSL_DTLS_MTU + WOLFSSL_EARLYDATA WOLFSSL_ECH WOLFSSL_MCAST WOLFSSL_OCSP + WOLFSSL_OCSPSTAPLING WOLFSSL_OCSPSTAPLING_V2 + WOLFSSL_PKCALLBACKS WOLFSSL_QUIC + WOLFSSL_RENEGOTIATION_INDICATION WOLFSSL_SECURE_RENEGOTIATION + WOLFSSL_SNI WOLFSSL_SRTP WOLFSSL_TLSX) + force_option(${_o} "no") + endforeach() + message(STATUS "WOLFSSL_CRYPT_ONLY: TLS layer off, including its options") +endif() + # Single threaded add_option("WOLFSSL_SINGLE_THREADED" "Enable wolfSSL single threaded (default: disabled)" @@ -4547,6 +4576,51 @@ endforeach() # both emitting the same feature define). list(REMOVE_DUPLICATES WOLFSSL_DEFINITIONS) +# A -D the user passed that is not a build option still satisfies the +# matching #cmakedefine below, yielding an options.h that claims features the +# library was not compiled with -- the classic case being WOLFSSL_STATIC_MEMORY +# for the WOLFSSL_STATICMEMORY option. Drop those before the header is +# generated. +get_property(WOLFSSL_DECLARED_OPTIONS GLOBAL PROPERTY WOLFSSL_DECLARED_OPTIONS) +get_cmake_property(WOLFSSL_CACHE_VARS CACHE_VARIABLES) +file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/options.h.in" OPTIONS_H_LINES + REGEX "^#cmakedefine[ \t]+[A-Za-z_]") +foreach(LINE IN LISTS OPTIONS_H_LINES) + string(REGEX REPLACE "^#cmakedefine[ \t]+([A-Za-z_][A-Za-z0-9_]*).*$" "\\1" + MACRO_NAME "${LINE}") + # Only wolfSSL's own namespace: everything else in options.h.in is a + # system probe (HAVE_LIMITS_H and friends) that the project sets itself. + if(NOT MACRO_NAME MATCHES "^WOLF") + continue() + endif() + if(MACRO_NAME IN_LIST WOLFSSL_DECLARED_OPTIONS) + continue() + endif() + if(NOT MACRO_NAME IN_LIST WOLFSSL_CACHE_VARS) + continue() + endif() + # Already compiled into the library, so it is a real option however its + # cache entry was made (WOLFSSL_HARDEN_TLS uses a raw CACHE STRING to keep + # an out-of-range value for validation). + set(MACRO_IN_DEFS FALSE) + foreach(DEF IN LISTS WOLFSSL_DEFINITIONS) + if(DEF MATCHES "^-D${MACRO_NAME}(=.*)?$") + set(MACRO_IN_DEFS TRUE) + break() + endif() + endforeach() + if(MACRO_IN_DEFS) + continue() + endif() + if(${MACRO_NAME}) + message(WARNING "${MACRO_NAME} is not a wolfSSL build option; ignoring " + "it so that wolfssl/options.h matches the library. Run " + "`cmake -LH` for the option list.") + unset(${MACRO_NAME}) + unset(${MACRO_NAME} CACHE) + endif() +endforeach() + foreach(DEF IN LISTS WOLFSSL_DEFINITIONS) string(REGEX MATCH "^(-D)?([^=]+)(=(.*))?$" DEF_MATCH ${DEF}) if (NOT "${CMAKE_MATCH_4}" STREQUAL "") diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 6c5fa97658f..74a7a4af4a5 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -39,6 +39,10 @@ function(wolfssl_warn_unconsumed_forces) endfunction() function(add_option NAME HELP_STRING DEFAULT VALUES) + # Record the name so a -D that is not a build option can be told apart + # from one that is. See the options.h.in guard in CMakeLists.txt. + set_property(GLOBAL APPEND PROPERTY WOLFSSL_DECLARED_OPTIONS "${NAME}") + if(VALUES STREQUAL "yes;no") # Set the default value for the option. set(${NAME} ${DEFAULT} CACHE BOOL ${HELP_STRING}) diff --git a/cmake/options.h.in b/cmake/options.h.in index bcf1aaef3e2..b5d7627c771 100644 --- a/cmake/options.h.in +++ b/cmake/options.h.in @@ -696,6 +696,8 @@ extern "C" { #cmakedefine WOLFSSL_STATIC_MEMORY_LEAN #undef WOLFSSL_STATIC_MEMORY_DEBUG_CALLBACK #cmakedefine WOLFSSL_STATIC_MEMORY_DEBUG_CALLBACK +#undef WOLFCRYPT_ONLY +#cmakedefine WOLFCRYPT_ONLY #undef NO_TLS #cmakedefine NO_TLS #undef NO_SHA256 From 8ea8033cfec8cc7485da86b14fcc919600061a4d Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 1 Oct 2026 16:35:46 -0700 Subject: [PATCH 2/4] Encode certificate names and extensions without an allocator --- .github/workflows/no-malloc.yml | 3 +- wolfcrypt/src/asn.c | 129 ++++++++++++++++++++++++++++++-- wolfcrypt/test/test.c | 100 +++++++++++++++++++++++++ 3 files changed, 223 insertions(+), 9 deletions(-) diff --git a/.github/workflows/no-malloc.yml b/.github/workflows/no-malloc.yml index 0fc8fa38ab2..68e31060a81 100644 --- a/.github/workflows/no-malloc.yml +++ b/.github/workflows/no-malloc.yml @@ -99,7 +99,8 @@ jobs: "run": [["./wolfcrypt/test/testwolfcrypt"]]}, {"name": "no-heap-cert", "minutes": 0.8, "configure": ["--enable-rsa", "--enable-keygen", "--enable-ecc", - "--enable-acert", "--disable-dh", "--disable-filesystem", + "--enable-acert", "--enable-certgen", "--enable-certreq", + "--enable-certext", "--disable-dh", "--disable-filesystem", "CFLAGS=-DWOLFSSL_NO_MALLOC -DNO_WOLFSSL_MEMORY -DRSA_MIN_SIZE=1024 -DWOLFSSL_TEST_CERT -DUSE_CERT_BUFFERS_2048 -DUSE_CERT_BUFFERS_256 -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"], "check": false, "run": [["./wolfcrypt/test/testwolfcrypt"]]} diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 8df5aa91193..aad221fe555 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -277,6 +277,21 @@ ASN Options: #include #include + +/* No allocator behind XMALLOC, so the certificate generation paths work from + * the stack. WOLFSSL_STATIC_MEMORY and a user-supplied XMALLOC still have a + * heap. */ +#if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) && \ + !defined(XMALLOC_USER) && !defined(XMALLOC_OVERRIDE) + #define WC_ASN_CERTGEN_NO_ALLOC + + /* The buffers below live on the stack, so they must never reach XFREE -- + * wolfSSL_SetAllocators() can install a free_function even here. */ + #define WC_ASN_FREE_TMP(p, heap) WC_DO_NOTHING +#else + #define WC_ASN_FREE_TMP(p, heap) \ + XFREE((p), (heap), DYNAMIC_TYPE_TMP_BUFFER) +#endif #ifdef NO_INLINE #include #else @@ -28941,6 +28956,21 @@ struct { #define EKU_OID_LO 1 #define EKU_OID_HI 6 + +/* Bound for wc_SetExtKeyUsage()'s value. Every usage name ParseExtKeyUsageStr() + * knows, comma separated, is 78 bytes today; the headroom is there so adding a + * name does not start rejecting valid strings on the no-allocator path. */ +#define WC_ASN_EKU_STR_MAX 128 + +#ifdef WC_ASN_CERTGEN_NO_ALLOC +/* Extended Key Usage template items: the SEQUENCE, one per known usage, and + * the WOLFSSL_EKU_OID slots where that is enabled. */ +#ifdef WOLFSSL_EKU_OID + #define WC_ASN_EKU_MAX_ITEMS (1 + EKU_OID_HI + CTC_MAX_EKU_NB) +#else + #define WC_ASN_EKU_MAX_ITEMS (1 + EKU_OID_HI) +#endif +#endif #endif /* WOLFSSL_ASN_TEMPLATE */ /* encode Extended Key Usage (RFC 5280 4.2.1.12), return total bytes written */ @@ -28949,6 +28979,11 @@ static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input) { /* TODO: consider calculating size of OBJECT_IDs, setting length into * SEQUENCE, encode SEQUENCE, encode OBJECT_IDs into buffer. */ +#ifdef WC_ASN_CERTGEN_NO_ALLOC + /* cnt below is a compile-time bound, so these fit on the stack. */ + ASNSetData dataASNbuf[WC_ASN_EKU_MAX_ITEMS]; + ASNItem extKuASNbuf[WC_ASN_EKU_MAX_ITEMS]; +#endif ASNSetData* dataASN; ASNItem* extKuASN = NULL; int asnIdx = 1; @@ -28961,6 +28996,10 @@ static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input) cnt += CTC_MAX_EKU_NB; #endif +#ifdef WC_ASN_CERTGEN_NO_ALLOC + dataASN = dataASNbuf; + extKuASN = extKuASNbuf; +#else /* Allocate memory for dynamic data items. */ dataASN = (ASNSetData*)XMALLOC(cnt * sizeof(ASNSetData), cert->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -28975,6 +29014,7 @@ static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input) ret = MEMORY_E; } } +#endif if (ret == 0) { /* Copy Sequence into dynamic ASN.1 template. */ @@ -29043,9 +29083,11 @@ static int SetExtKeyUsage(Cert* cert, byte* output, word32 outSz, byte input) ret = (int)sz; } +#ifndef WC_ASN_CERTGEN_NO_ALLOC /* Dispose of allocated data. */ XFREE(extKuASN, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(dataASN, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif return ret; } @@ -29414,24 +29456,38 @@ int ParseExtKeyUsageStr(const char* value, byte* extKeyUsage, void* heap) char *token, *str, *ptr; word32 len = 0; byte usage = 0; +#ifdef WC_ASN_CERTGEN_NO_ALLOC + char strBuf[WC_ASN_EKU_STR_MAX + 1]; +#endif if (value == NULL || extKeyUsage == NULL) { return BAD_FUNC_ARG; } - /* duplicate string (including terminator) */ + /* duplicate string (including terminator) -- XSTRTOK writes into it */ len = (word32)XSTRLEN(value); +#ifdef WC_ASN_CERTGEN_NO_ALLOC + (void)heap; + if (len > WC_ASN_EKU_STR_MAX) { + return BUFFER_E; + } + str = strBuf; +#else str = (char*)XMALLOC(len + 1, heap, DYNAMIC_TYPE_TMP_BUFFER); if (str == NULL) { return MEMORY_E; } +#endif XMEMCPY(str, value, len + 1); /* parse value, and set corresponding Key Usage value */ if ((token = XSTRTOK(str, ",", &ptr)) == NULL) { + #ifndef WC_ASN_CERTGEN_NO_ALLOC XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif return EXTKEYUSAGE_E; } + /* Adding a usage name here may need WC_ASN_EKU_STR_MAX raised. */ while (token != NULL) { if (!XSTRCASECMP(token, "any")) usage |= EXTKEYUSE_ANY; @@ -29455,7 +29511,9 @@ int ParseExtKeyUsageStr(const char* value, byte* extKeyUsage, void* heap) token = XSTRTOK(NULL, ",", &ptr); } +#ifndef WC_ASN_CERTGEN_NO_ALLOC XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif if (ret == 0) { *extKeyUsage = usage; @@ -29523,6 +29581,21 @@ enum { /* Number of items in ASN.1 template for the SEQUENCE around the RDNs. */ #define nameASN_Length (sizeof(nameASN) / sizeof(ASNItem)) +#ifdef WC_ASN_CERTGEN_NO_ALLOC + /* Name components encodable in one certificate name. Lower it to trade + * encodable components for stack; SetNameEx() returns BUFFER_E when a + * name needs more. */ + #ifndef WC_ASN_MAX_NAME_ENTRIES + #ifdef WOLFSSL_MULTI_ATTRIB + #define WC_ASN_MAX_NAME_ENTRIES (NAME_ENTRIES + CTC_MAX_ATTRIB) + #else + #define WC_ASN_MAX_NAME_ENTRIES NAME_ENTRIES + #endif + #endif + #define WC_ASN_NAME_MAX_ITEMS \ + (nameASN_Length + rdnASN_Length * (word32)WC_ASN_MAX_NAME_ENTRIES) +#endif + static int SetNameRdnItems(ASNSetData* dataASN, ASNItem* namesASN, int maxIdx, CertName* name) { @@ -29654,11 +29727,16 @@ int SetNameEx(byte* output, word32 outputSz, CertName* name, void* heap) { /* TODO: consider calculating size of entries, putting length into * SEQUENCE, encode SEQUENCE, encode entries into buffer. */ - ASNSetData* dataASN = NULL; /* Can't use DECL_ASNSETDATA. Always dynamic. */ + /* Can't use DECL_ASNSETDATA: item count is only known at run time. */ + ASNSetData* dataASN = NULL; ASNItem* namesASN = NULL; word32 items = 0; int ret = 0; word32 sz = 0; +#ifdef WC_ASN_CERTGEN_NO_ALLOC + ASNSetData dataASNbuf[WC_ASN_NAME_MAX_ITEMS]; + ASNItem namesASNbuf[WC_ASN_NAME_MAX_ITEMS]; +#endif /* Calculate length of name entries and size for allocating. */ ret = SetNameRdnItems(NULL, NULL, 0, name); @@ -29674,6 +29752,14 @@ int SetNameEx(byte* output, word32 outputSz, CertName* name, void* heap) return 0; } +#ifdef WC_ASN_CERTGEN_NO_ALLOC + if (items > WC_ASN_NAME_MAX_ITEMS) { + WOLFSSL_MSG("Name needs more entries than WC_ASN_MAX_NAME_ENTRIES"); + return BUFFER_E; + } + dataASN = dataASNbuf; + namesASN = namesASNbuf; +#else /* Allocate dynamic data items. */ dataASN = (ASNSetData*)XMALLOC(items * sizeof(ASNSetData), heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -29688,6 +29774,7 @@ int SetNameEx(byte* output, word32 outputSz, CertName* name, void* heap) ret = MEMORY_E; } } +#endif if (ret == 0) { /* Clear the dynamic data. */ @@ -29722,8 +29809,10 @@ int SetNameEx(byte* output, word32 outputSz, CertName* name, void* heap) } } +#ifndef WC_ASN_CERTGEN_NO_ALLOC XFREE(namesASN, heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(dataASN, heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif (void)heap; return ret; } @@ -32904,6 +32993,9 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, void* mlKemKey, int kid_type) { +#ifdef WC_ASN_CERTGEN_NO_ALLOC + byte bufOnStack[MAX_PUBLIC_KEY_SZ]; +#endif byte *buf; int bufferSz, ret; word32 bufSz = MAX_PUBLIC_KEY_SZ; @@ -32927,9 +33019,17 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, bufSz = MLKEM_MAX_PUB_KEY_DER_SIZE; } #endif +#ifdef WC_ASN_CERTGEN_NO_ALLOC + if (bufSz > (word32)sizeof(bufOnStack)) { + /* The PQC keys above ask for more than the stack buffer holds. */ + return NOT_COMPILED_IN; + } + buf = bufOnStack; +#else buf = (byte *)XMALLOC(bufSz, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); if (buf == NULL) return MEMORY_E; +#endif /* Public Key */ bufferSz = -1; @@ -32987,7 +33087,9 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, #endif if (bufferSz <= 0) { + #ifndef WC_ASN_CERTGEN_NO_ALLOC XFREE(buf, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif return PUBLIC_KEY_E; } @@ -33011,7 +33113,9 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, #endif } +#ifndef WC_ASN_CERTGEN_NO_ALLOC XFREE(buf, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif return ret; } @@ -34014,17 +34118,26 @@ int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) word32 idx = 0, nb_val; char *token, *str, *ptr; word32 len; +#ifdef WC_ASN_CERTGEN_NO_ALLOC + char strBuf[CTC_MAX_CERTPOL_SZ]; +#endif (void)heap; if (out == NULL || outSz == NULL || *outSz < 2 || in == NULL) return BAD_FUNC_ARG; - /* duplicate string (including terminator) */ + /* duplicate string (including terminator) -- XSTRTOK writes into it */ len = (word32)XSTRLEN(in); +#ifdef WC_ASN_CERTGEN_NO_ALLOC + if (len >= sizeof(strBuf)) + return BUFFER_E; + str = strBuf; +#else str = (char *)XMALLOC(len+1, heap, DYNAMIC_TYPE_TMP_BUFFER); if (str == NULL) return MEMORY_E; +#endif XMEMCPY(str, in, len+1); nb_val = 0; @@ -34037,7 +34150,7 @@ int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) if (nb_val == 0) { if (val > 2) { - XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_ASN_FREE_TMP(str, heap); return ASN_OBJECT_ID_E; } @@ -34045,12 +34158,12 @@ int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) } else if (nb_val == 1) { if (val > 127) { - XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_ASN_FREE_TMP(str, heap); return ASN_OBJECT_ID_E; } if (idx > *outSz) { - XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_ASN_FREE_TMP(str, heap); return BUFFER_E; } @@ -34069,7 +34182,7 @@ int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) } if ((idx+(word32)i) >= *outSz) { - XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_ASN_FREE_TMP(str, heap); return BUFFER_E; } @@ -34086,7 +34199,7 @@ int EncodePolicyOID(byte *out, word32 *outSz, const char *in, void* heap) *outSz = idx; - XFREE(str, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_ASN_FREE_TMP(str, heap); return 0; } #endif /* WOLFSSL_CERT_EXT || OPENSSL_EXTRA */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index b8112c1ca56..58e465fb7b8 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -1232,6 +1232,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_cts_test(void); #endif /* !WC_TEST_EXPORT_SUBTESTS */ +/* These two are static and called from wolfcrypt_test(), so they need a + * declaration even where WC_TEST_EXPORT_SUBTESTS drops the block above. */ +#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \ + defined(WOLFSSL_CERT_EXT) && defined(HAVE_ECC) && \ + defined(USE_CERT_BUFFERS_256) && !defined(NO_SHA256) +static wc_test_ret_t certreq_no_malloc_test(void); +#endif + /* General big buffer size for many tests. */ #define FOURK_BUF 4096 @@ -3412,6 +3420,15 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("CERT NOMALLOC test passed!\n"); #endif +#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \ + defined(WOLFSSL_CERT_EXT) && defined(HAVE_ECC) && \ + defined(USE_CERT_BUFFERS_256) && !defined(NO_SHA256) + if ( (ret = certreq_no_malloc_test()) != 0) + TEST_FAIL("CERTREQ NOMALLOC test failed!\n", ret); + else + TEST_PASS("CERTREQ NOMALLOC test passed!\n"); +#endif + #if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) && \ !defined(NO_FILESYSTEM) && !defined(NO_RSA) && defined(WOLFSSL_GEN_CERT) if ( (ret = certext_test()) != 0) @@ -38978,6 +38995,89 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_test(void) #endif /* !NO_RSA */ +#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \ + defined(WOLFSSL_CERT_EXT) && defined(HAVE_ECC) && \ + defined(USE_CERT_BUFFERS_256) && !defined(NO_SHA256) +/* Certificate request generation with the Cert on the stack, so it also runs + * where there is no allocator behind XMALLOC. */ +static wc_test_ret_t certreq_no_malloc_test(void) +{ + /* Cert is far too large for one stack frame -- the kernel module caps + * them at 4kB -- and there is only ever one of these in flight. */ + static Cert req; + static ecc_key key; + static byte der[1024]; + word32 idx = 0; + int derSz; + wc_test_ret_t ret; + + WOLFSSL_ENTER("certreq_no_malloc_test"); + + ret = wc_ecc_init_ex(&key, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_EccPrivateKeyDecode(ecc_key_der_256, &idx, &key, + (word32)sizeof_ecc_key_der_256); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + if (ret == 0) { + ret = wc_InitCert_ex(&req, HEAP_HINT, devId); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + XSTRNCPY(req.subject.country, "US", CTC_NAME_SIZE); + XSTRNCPY(req.subject.org, "wolfSSL", CTC_NAME_SIZE); + XSTRNCPY(req.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE); + req.version = 0; + req.sigType = CTC_SHA256wECDSA; + /* An extended key usage takes SetExtKeyUsage() through the same + * path, from the string parser as well as the encoder. */ + ret = wc_SetExtKeyUsage(&req, "clientAuth,codeSigning"); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + derSz = wc_MakeCertReq_ex(&req, der, (word32)sizeof(der), ECC_TYPE, + &key); + if (derSz <= 0) + ret = WC_TEST_RET_ENC_EC(derSz); + } + +#if !defined(NO_ASN_TIME) && !defined(WC_NO_RNG) + /* Certificate policies only encode for a certificate, not a request, so + * EncodePolicyOID() needs wc_MakeCert(). */ + if (ret == 0) { + static WC_RNG rng; + + ret = wc_InitRng_ex(&rng, HEAP_HINT, devId); + if (ret != 0) { + ret = WC_TEST_RET_ENC_EC(ret); + } + else { + XMEMCPY(&req.issuer, &req.subject, sizeof(CertName)); + req.selfSigned = 1; + XSTRNCPY(req.certPolicies[0], "2.16.840.1.101.3.4.1.42", + CTC_MAX_CERTPOL_SZ); + req.certPoliciesNb = 1; + + derSz = wc_MakeCert(&req, der, (word32)sizeof(der), NULL, &key, + &rng); + if (derSz <= 0) + ret = WC_TEST_RET_ENC_EC(derSz); + wc_FreeRng(&rng); + } + } +#endif + + wc_ecc_free(&key); + return ret; +} +#endif /* WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ && WOLFSSL_CERT_EXT && + * HAVE_ECC && USE_CERT_BUFFERS_256 && !NO_SHA256 */ + + #if defined(WOLFSSL_TEST_CERT) && defined(HAVE_ECC) && \ !defined(NO_ECC256) && !defined(NO_ECC_SECP) /* Self-signed P-256 cert with a critical extension of unrecognized OID From 6286a4b1374bf61b7519580325c275f21fe19418 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 1 Oct 2026 16:35:46 -0700 Subject: [PATCH 3/4] Size key identifier buffers from the hash the build actually uses --- .github/configs/os-check-linux.json | 9 +++- wolfcrypt/src/asn.c | 45 ++++++++++++++--- wolfcrypt/test/test.c | 76 +++++++++++++++++++++++++++++ wolfssl/wolfcrypt/asn.h | 4 +- wolfssl/wolfcrypt/asn_public.h | 38 ++++++++++++++- 5 files changed, 160 insertions(+), 12 deletions(-) diff --git a/.github/configs/os-check-linux.json b/.github/configs/os-check-linux.json index 5fdf80daa5c..bed10581804 100644 --- a/.github/configs/os-check-linux.json +++ b/.github/configs/os-check-linux.json @@ -533,5 +533,12 @@ "--disable-oldtls", "--disable-examples", "CPPFLAGS=-DWOLFSSL_NO_TLS12"]}, {"name": "tls13-sha512-runtime", "minutes": 1.6, "comment": "--enable-tls13-sha512 with TLS 1.2 left in, so the examples and unit tests build and run with WOLFSSL_HS_HASH_SHA512 set. No cipher suite sets mac_algorithm to sha512_mac, so the sha512_mac arms in src/tls13.c stay unreached; what this entry proves is that the option does not break an otherwise ordinary build, which the two compile-only entries above cannot show.", - "configure": ["--enable-tls13", "--enable-tls13-sha512", "--enable-sha512"]} + "configure": ["--enable-tls13", "--enable-tls13-sha512", "--enable-sha512"]}, +{"name": "cryptonly-sha3-keyid", "minutes": 0.8, + "comment": "SHA3 as the only hash family that can derive key identifiers: no SHA-1 and no SHA-256, so HashIdAlg()/CalcHashId_ex() must pick SHA3-256 and KEYID_SIZE must follow it. SHA-512 is kept only because the Hash DRBG needs it. The CERT KEYID subtest checks the SKID/AKID sizes the generator writes against CTC_MAX_SKID_SIZE.", + "configure": ["--enable-cryptonly", "--enable-ecc", "--enable-certgen", + "--enable-certreq", "--enable-certext", "--enable-sha3", "--enable-sha512", + "--disable-sha", "--disable-sha256", "--disable-sha224", "--disable-rsa", + "--disable-dh", + "CPPFLAGS=-DWOLFSSL_DRBG_SHA512 -DUSE_CERT_BUFFERS_256"]} ] diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index aad221fe555..28b4ac6d619 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -14379,6 +14379,13 @@ static int GetCertKey(DecodedCert* cert, const byte* source, word32* inOutIdx, } #endif +#ifdef WOLFSSL_CERT_EXT +/* The key identifier buffers in Cert must hold whatever CalcHashId_ex() + * writes. */ +wc_static_assert((int)KEYID_SIZE <= (int)CTC_MAX_SKID_SIZE); +wc_static_assert((int)KEYID_SIZE <= (int)CTC_MAX_AKID_SIZE); +#endif + /* Return the hash algorithm to use with the signature algorithm. * * @param [in] oidSum Signature id. @@ -14396,10 +14403,14 @@ int HashIdAlg(word32 oidSum) return WC_SM3; } #endif -#if defined(NO_SHA) || (!defined(NO_SHA256) && defined(WC_ASN_HASH_SHA256)) +#ifdef WC_ASN_KEYID_HASH_SHA256 return WC_SHA256; -#else +#elif defined(WC_ASN_KEYID_HASH_SHA) return WC_SHA; +#elif defined(WC_ASN_KEYID_HASH_SHA3_256) + return WC_SHA3_256; +#else + return WC_HASH_TYPE_NONE; #endif } @@ -14415,10 +14426,14 @@ int CalcHashId(const byte* data, word32 len, byte* hash) { /* Use default hash algorithm. */ return CalcHashId_ex(data, len, hash, -#if defined(NO_SHA) || (!defined(NO_SHA256) && defined(WC_ASN_HASH_SHA256)) +#ifdef WC_ASN_KEYID_HASH_SHA256 WC_SHA256 -#else +#elif defined(WC_ASN_KEYID_HASH_SHA) WC_SHA +#elif defined(WC_ASN_KEYID_HASH_SHA3_256) + WC_SHA3_256 +#else + WC_HASH_TYPE_NONE #endif ); } @@ -14441,12 +14456,12 @@ int CalcHashId_ex(const byte* data, word32 len, byte* hash, int hashAlg) } else #endif -#if defined(NO_SHA) || (!defined(NO_SHA256) && defined(WC_ASN_HASH_SHA256)) +#ifdef WC_ASN_KEYID_HASH_SHA256 if (hashAlg == WC_SHA256) { ret = wc_Sha256Hash(data, len, hash); } else -#elif !defined(NO_SHA) +#elif defined(WC_ASN_KEYID_HASH_SHA) if (hashAlg == WC_SHA) { #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) XMEMSET(hash + WC_SHA_DIGEST_SIZE, 0, KEYID_SIZE - WC_SHA_DIGEST_SIZE); @@ -14454,10 +14469,28 @@ int CalcHashId_ex(const byte* data, word32 len, byte* hash, int hashAlg) ret = wc_ShaHash(data, len, hash); } else +#elif defined(WC_ASN_KEYID_HASH_SHA3_256) + if (hashAlg == WC_SHA3_256) { + wc_Sha3 sha3[1]; + + ret = wc_InitSha3_256(sha3, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_Sha3_256_Update(sha3, data, len); + if (ret == 0) { + ret = wc_Sha3_256_Final(sha3, hash); + } + wc_Sha3_256_Free(sha3); + } + } + else #else + /* With SM3 above this arm must stay empty, so its "else" binds to the + * NOT_COMPILED_IN block and the SM3 result survives. */ + #if !defined(WOLFSSL_SM2) || !defined(WOLFSSL_SM3) (void)data; (void)len; (void)hash; + #endif #endif { ret = NOT_COMPILED_IN; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 58e465fb7b8..7616ed61d80 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -1239,6 +1239,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_cts_test(void); defined(USE_CERT_BUFFERS_256) && !defined(NO_SHA256) static wc_test_ret_t certreq_no_malloc_test(void); #endif +#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \ + defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) && \ + defined(WC_ASN_KEYID_HASH) +static wc_test_ret_t keyid_test(void); +#endif /* General big buffer size for many tests. */ #define FOURK_BUF 4096 @@ -3429,6 +3434,15 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("CERTREQ NOMALLOC test passed!\n"); #endif +#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \ + defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) && \ + defined(WC_ASN_KEYID_HASH) + if ( (ret = keyid_test()) != 0) + TEST_FAIL("CERT KEYID test failed!\n", ret); + else + TEST_PASS("CERT KEYID test passed!\n"); +#endif + #if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) && \ !defined(NO_FILESYSTEM) && !defined(NO_RSA) && defined(WOLFSSL_GEN_CERT) if ( (ret = certext_test()) != 0) @@ -39077,6 +39091,68 @@ static wc_test_ret_t certreq_no_malloc_test(void) #endif /* WOLFSSL_CERT_GEN && WOLFSSL_CERT_REQ && WOLFSSL_CERT_EXT && * HAVE_ECC && USE_CERT_BUFFERS_256 && !NO_SHA256 */ +#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \ + defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) && \ + defined(WC_ASN_KEYID_HASH) +/* The SKID and AKID buffers in Cert are sized for whichever hash the ASN + * layer derives key identifiers with; a build whose selected hash was not + * compiled in did not reach this far. */ +static wc_test_ret_t keyid_test(void) +{ + static Cert cert; + static ecc_key key; + word32 idx = 0; + wc_test_ret_t ret; + + WOLFSSL_ENTER("keyid_test"); + + ret = wc_ecc_init_ex(&key, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_EccPrivateKeyDecode(ecc_key_der_256, &idx, &key, + (word32)sizeof_ecc_key_der_256); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + if (ret == 0) { + ret = wc_InitCert_ex(&cert, HEAP_HINT, devId); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + + if (ret == 0) { + ret = wc_SetSubjectKeyIdFromPublicKey(&cert, NULL, &key); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if ((ret == 0) && ((cert.skidSz <= 0) || + (cert.skidSz > (int)CTC_MAX_SKID_SIZE))) { + ret = WC_TEST_RET_ENC_NC; + } +#if !defined(WOLFSSL_SM2) || !defined(WOLFSSL_SM3) + /* ShangMi builds size KEYID_SIZE for SM3 but may identify keys with + * another hash, so only the plain case can check for equality. */ + if ((ret == 0) && (cert.skidSz != (int)KEYID_SIZE)) + ret = WC_TEST_RET_ENC_NC; +#endif + + if (ret == 0) { + ret = wc_SetAuthKeyIdFromPublicKey(&cert, NULL, &key); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if ((ret == 0) && ((cert.akidSz <= 0) || + (cert.akidSz > (int)CTC_MAX_AKID_SIZE))) { + ret = WC_TEST_RET_ENC_NC; + } + if ((ret == 0) && (cert.akidSz != cert.skidSz)) + ret = WC_TEST_RET_ENC_NC; + + wc_ecc_free(&key); + return ret; +} +#endif /* WOLFSSL_CERT_GEN && WOLFSSL_CERT_EXT && HAVE_ECC && + * USE_CERT_BUFFERS_256 && WC_ASN_KEYID_HASH */ #if defined(WOLFSSL_TEST_CERT) && defined(HAVE_ECC) && \ !defined(NO_ECC256) && !defined(NO_ECC_SECP) diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 91cb91afd47..7fd587d92a6 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1340,10 +1340,8 @@ enum Misc_ASN { ASN_ECC_CONTEXT_SZ = 2, /* Content specific type + 1 byte len */ #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) KEYID_SIZE = WC_SM3_DIGEST_SIZE, -#elif defined(NO_SHA) || (!defined(NO_SHA256) && defined(WC_ASN_HASH_SHA256)) - KEYID_SIZE = WC_SHA256_DIGEST_SIZE, #else - KEYID_SIZE = WC_SHA_DIGEST_SIZE, + KEYID_SIZE = WC_ASN_KEYID_SZ, #endif RSA_INTS = 2 /* RSA ints in private key */ #ifndef WOLFSSL_RSA_PUBLIC_ONLY diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 93933aac4d1..db65b723f82 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -128,6 +128,40 @@ enum EncPkcs8Types { ENC_PKCS8_ALG_DES3 = 652 }; +/* Hash the ASN.1 layer derives key identifiers with -- SKID, AKID and the + * internal name and key hashes. SHA-1 while it is in the build, for + * interoperability; SHA-256 once SHA-1 is gone or when WC_ASN_HASH_SHA256 asks + * for it; SHA3-256 when neither is built. */ +#if !defined(NO_SHA256) && (defined(NO_SHA) || defined(WC_ASN_HASH_SHA256)) + #define WC_ASN_KEYID_HASH_SHA256 + #define WC_ASN_KEYID_SZ 32 /* WC_SHA256_DIGEST_SIZE */ +#elif !defined(NO_SHA) + #define WC_ASN_KEYID_HASH_SHA + #define WC_ASN_KEYID_SZ 20 /* WC_SHA_DIGEST_SIZE */ +#elif defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_256) + #define WC_ASN_KEYID_HASH_SHA3_256 + #define WC_ASN_KEYID_SZ 32 /* WC_SHA3_256_DIGEST_SIZE */ +#else + /* No key identifier hash in this build: CalcHashId_ex() reports + * NOT_COMPILED_IN and the size below is only the buffer floor. */ + #define WC_ASN_KEYID_SZ 32 +#endif + +/* Set when one of the three above is, so callers can tell a build that can + * derive key identifiers from one that cannot. */ +#if defined(WC_ASN_KEYID_HASH_SHA256) || defined(WC_ASN_KEYID_HASH_SHA) || \ + defined(WC_ASN_KEYID_HASH_SHA3_256) + #define WC_ASN_KEYID_HASH +#endif + +/* Key identifier buffers in Cert keep a 32-byte floor so the public struct + * layout does not depend on which hash the build selected. */ +#if WC_ASN_KEYID_SZ > 32 + #define WC_CTC_MAX_KEYID_SIZE WC_ASN_KEYID_SZ +#else + #define WC_CTC_MAX_KEYID_SIZE 32 +#endif + /* Certificate file Type */ enum CertType { CERT_TYPE = 0, @@ -227,8 +261,8 @@ enum Ctc_Misc { #ifdef WOLFSSL_CERT_EXT /* AKID could contains: hash + (Option) AuthCertIssuer,AuthCertSerialNum * We support only hash */ - CTC_MAX_SKID_SIZE = 32, /* SHA256_DIGEST_SIZE */ - CTC_MAX_AKID_SIZE = 32, /* SHA256_DIGEST_SIZE */ + CTC_MAX_SKID_SIZE = WC_CTC_MAX_KEYID_SIZE, + CTC_MAX_AKID_SIZE = WC_CTC_MAX_KEYID_SIZE, CTC_MAX_CERTPOL_SZ = 200, /* RFC 5280 Section 4.2.1.4 */ CTC_MAX_CERTPOL_NB = 2, /* Max number of Certificate Policy */ CTC_MAX_CRLINFO_SZ = WC_CTC_MAX_CRLINFO_SZ, /* Arbitrary size that should be From bd1f752c927730427bb0bd39c52e48b3a80e03c4 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 1 Oct 2026 16:35:46 -0700 Subject: [PATCH 4/4] Provide XATOI under STRING_USER and in the platform templates --- IDE/GCC-ARM/Header/user_settings.h | 3 +++ IDE/SimplicityStudio/user_settings.h | 3 +++ IDE/WICED-STUDIO/user_settings.h | 3 +++ IDE/WINCE/user_settings.h | 3 +++ IDE/XCODE-FIPSv2/macOS-C++/Intel/user_settings.h | 3 +++ IDE/XCODE-FIPSv2/macOS-C++/M1/user_settings.h | 3 +++ IDE/XCODE-FIPSv2/user_settings.h | 3 +++ IDE/XCODE-FIPSv5/user_settings.h | 3 +++ IDE/XCODE-FIPSv6/user_settings.h | 3 +++ examples/configs/user_settings_template.h | 3 +++ wolfssl/wolfcrypt/types.h | 14 +++++++++++++- 11 files changed, 43 insertions(+), 1 deletion(-) diff --git a/IDE/GCC-ARM/Header/user_settings.h b/IDE/GCC-ARM/Header/user_settings.h index 971180c9bda..2ef79b4546f 100644 --- a/IDE/GCC-ARM/Header/user_settings.h +++ b/IDE/GCC-ARM/Header/user_settings.h @@ -537,6 +537,9 @@ extern unsigned int my_rng_seed_gen(void); #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/SimplicityStudio/user_settings.h b/IDE/SimplicityStudio/user_settings.h index 70f560357c4..e2ea3c91d3e 100644 --- a/IDE/SimplicityStudio/user_settings.h +++ b/IDE/SimplicityStudio/user_settings.h @@ -454,6 +454,9 @@ extern "C" { #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/WICED-STUDIO/user_settings.h b/IDE/WICED-STUDIO/user_settings.h index 686dacefee9..ac2f94b4446 100644 --- a/IDE/WICED-STUDIO/user_settings.h +++ b/IDE/WICED-STUDIO/user_settings.h @@ -531,6 +531,9 @@ extern unsigned int my_rng_seed_gen(void); #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/WINCE/user_settings.h b/IDE/WINCE/user_settings.h index f8a69633c22..8bb10ec2a1d 100644 --- a/IDE/WINCE/user_settings.h +++ b/IDE/WINCE/user_settings.h @@ -662,6 +662,9 @@ C149F3285397DFBD0C6720E14818475C3A50B10880EF9619463173A6D5ED15E7 #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/XCODE-FIPSv2/macOS-C++/Intel/user_settings.h b/IDE/XCODE-FIPSv2/macOS-C++/Intel/user_settings.h index 03b8bb81b64..8422deef538 100644 --- a/IDE/XCODE-FIPSv2/macOS-C++/Intel/user_settings.h +++ b/IDE/XCODE-FIPSv2/macOS-C++/Intel/user_settings.h @@ -528,6 +528,9 @@ extern "C" { #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/XCODE-FIPSv2/macOS-C++/M1/user_settings.h b/IDE/XCODE-FIPSv2/macOS-C++/M1/user_settings.h index d4880d52ac6..273e2fd8aa0 100644 --- a/IDE/XCODE-FIPSv2/macOS-C++/M1/user_settings.h +++ b/IDE/XCODE-FIPSv2/macOS-C++/M1/user_settings.h @@ -539,6 +539,9 @@ extern "C" { #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/XCODE-FIPSv2/user_settings.h b/IDE/XCODE-FIPSv2/user_settings.h index 14dc7ed4ac6..733900aed27 100644 --- a/IDE/XCODE-FIPSv2/user_settings.h +++ b/IDE/XCODE-FIPSv2/user_settings.h @@ -540,6 +540,9 @@ extern "C" { #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/XCODE-FIPSv5/user_settings.h b/IDE/XCODE-FIPSv5/user_settings.h index 18e21608ec7..65fba97b735 100644 --- a/IDE/XCODE-FIPSv5/user_settings.h +++ b/IDE/XCODE-FIPSv5/user_settings.h @@ -621,6 +621,9 @@ extern "C" { #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/IDE/XCODE-FIPSv6/user_settings.h b/IDE/XCODE-FIPSv6/user_settings.h index fb4aaddd0f4..e60f2941d6f 100644 --- a/IDE/XCODE-FIPSv6/user_settings.h +++ b/IDE/XCODE-FIPSv6/user_settings.h @@ -681,6 +681,9 @@ extern "C" { #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/examples/configs/user_settings_template.h b/examples/configs/user_settings_template.h index 49a48e9b60e..43d8c457467 100644 --- a/examples/configs/user_settings_template.h +++ b/examples/configs/user_settings_template.h @@ -487,6 +487,9 @@ extern "C" { #define XSTRNCASECMP(s1,s2,n) strncasecmp((s1),(s2),(n)) #define XSNPRINTF snprintf + + #include + #define XATOI(s) atoi((s)) #endif diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 3e3d5997be0..f5ed2a8cacd 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1305,7 +1305,6 @@ binding for XSNPRINTF #define XSTRTOK(s1,d,ptr) strtok_r((s1),(d),(ptr)) #endif #endif - #if defined(WOLFSSL_CERT_EXT) || defined(HAVE_OCSP) || \ defined(HAVE_CRL_IO) || defined(HAVE_HTTP_CLIENT) || \ !defined(NO_CRYPT_BENCHMARK) || defined(OPENSSL_EXTRA) @@ -1317,6 +1316,19 @@ binding for XSNPRINTF #endif #endif /* STRING_USER */ +/* The STRING_USER platform templates override the string and memory macros + * but not XATOI, which the certificate policy OID parser needs. Narrower than + * the case above: a platform that set STRING_USER to keep the standard + * library out only reaches through a feature that cannot work + * without XATOI, and one that supplies its own still wins. */ +#if defined(STRING_USER) && !defined(XATOI) && \ + (defined(WOLFSSL_CERT_EXT) || defined(HAVE_OCSP) || \ + defined(HAVE_CRL_IO) || defined(HAVE_HTTP_CLIENT) || \ + defined(OPENSSL_EXTRA)) + #include + #define XATOI(s) atoi((s)) +#endif + #ifdef WOLFSSL_WIDE_BYTE /* Packed octet stream -> one octet per byte cell. All sizes are in byte cells; * out needs octetSz, in needs WC_PACKED_CELLS(octetSz), and they must not