diff --git a/CMakeLists.txt b/CMakeLists.txt index f9c62130eb..1165a108a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4406,6 +4406,7 @@ if(WOLFSSL_EXAMPLES) tests/api/test_random.c tests/api/test_wolfentropy.c tests/api/test_wolfevent.c + tests/api/test_port.c tests/api/test_wolfmath.c tests/api/test_rsa.c tests/api/test_dsa.c diff --git a/tests/api.c b/tests/api.c index d396634ac9..e7b1fd9934 100644 --- a/tests/api.c +++ b/tests/api.c @@ -237,6 +237,7 @@ #include #include #include +#include #include #include #include @@ -38681,6 +38682,7 @@ TEST_CASE testCases[] = { TEST_RANDOM_DECLS, TEST_WOLFENTROPY_DECLS, TEST_WOLFEVENT_DECLS, + TEST_PORT_DECLS, /* Public key */ /* wolfmath MP API tests */ diff --git a/tests/api/include.am b/tests/api/include.am index 97191f343c..b3f922643f 100644 --- a/tests/api/include.am +++ b/tests/api/include.am @@ -44,6 +44,7 @@ tests_unit_test_SOURCES += tests/api/test_error.c tests_unit_test_SOURCES += tests/api/test_random.c tests_unit_test_SOURCES += tests/api/test_wolfentropy.c tests_unit_test_SOURCES += tests/api/test_wolfevent.c +tests_unit_test_SOURCES += tests/api/test_port.c # MP tests_unit_test_SOURCES += tests/api/test_wolfmath.c # Public Key Algorithm @@ -177,6 +178,7 @@ EXTRA_DIST += tests/api/test_error.h EXTRA_DIST += tests/api/test_random.h EXTRA_DIST += tests/api/test_wolfentropy.h EXTRA_DIST += tests/api/test_wolfevent.h +EXTRA_DIST += tests/api/test_port.h EXTRA_DIST += tests/api/test_wolfmath.h EXTRA_DIST += tests/api/test_rsa.h EXTRA_DIST += tests/api/test_dsa.h diff --git a/tests/api/test_port.c b/tests/api/test_port.c new file mode 100644 index 0000000000..407528557c --- /dev/null +++ b/tests/api/test_port.c @@ -0,0 +1,176 @@ +/* test_port.c + * + * Copyright (C) 2006-2026 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 3 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 +#include +#include +#include + +/* + * MC/DC decision coverage for the portability layer (wolfcrypt/src/wc_port.c): + * the file/directory helpers and the wolfCrypt string helpers, whose argument + * guards are multi-operand ORs that no other module's tests reach. + * + * Residuals left uncovered on purpose: wc_open_cloexec / wc_accept_cloexec's + * "fd < 0 && errno == EINVAL" and "errno != ENOSYS && errno != EINVAL" arms are + * the fallback for kernels without O_CLOEXEC / SOCK_CLOEXEC, unreachable on any + * host the campaign runs on. + */ + +#ifndef SINGLE_THREADED +static THREAD_RETURN WOLFSSL_THREAD test_port_thread_cb(void* arg) +{ + (void)arg; + WOLFSSL_RETURN_FROM_THREAD(0); +} +#endif + +int test_wc_PortDecisionCoverage(void) +{ + EXPECT_DECLS; + +#ifndef NO_FILESYSTEM + { + unsigned char* fbuf = NULL; + size_t fbufLen = 0; + + /* wc_FileLoad: "fname == NULL || buf == NULL || bufLen == NULL", + * one operand true per call so each independence pair is shown. */ + ExpectIntEQ(wc_FileLoad(NULL, &fbuf, &fbufLen, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_FileLoad("./certs/server-cert.pem", NULL, &fbufLen, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_FileLoad("./certs/server-cert.pem", &fbuf, NULL, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* all three operands false: the guard is passed and the call is + * decided by the filesystem, not by the argument check. */ + ExpectIntNE(wc_FileLoad("./certs/no-such-file.der", &fbuf, &fbufLen, + NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + if (fbuf != NULL) { + XFREE(fbuf, NULL, DYNAMIC_TYPE_FILE); + fbuf = NULL; + } + } +#endif /* !NO_FILESYSTEM */ + +#if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) + { + ReadDirCtx dirCtx; + char* dirName = NULL; + + XMEMSET(&dirCtx, 0, sizeof(dirCtx)); + + /* wc_ReadDirFirst / wc_ReadDirNext: "ctx == NULL || path == NULL", + * each operand flipped independently. */ + ExpectIntEQ(wc_ReadDirFirst(NULL, "./certs", &dirName), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_ReadDirFirst(&dirCtx, NULL, &dirName), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_ReadDirNext(NULL, "./certs", &dirName), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_ReadDirNext(&dirCtx, NULL, &dirName), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* both operands false on a directory that always exists in-tree. */ + if (wc_ReadDirFirst(&dirCtx, "./certs", &dirName) == 0) { + (void)wc_ReadDirNext(&dirCtx, "./certs", &dirName); + wc_ReadDirClose(&dirCtx); + } + } +#endif /* !NO_FILESYSTEM && !NO_WOLFSSL_DIR */ + +#ifdef USE_WOLF_STRTOK + { + char tokBuf[] = "a,b"; + char* tokNext = NULL; + + /* "str == NULL && nextp": nextp NULL is the operand's false half, and + * the same call then takes "str == NULL || *str == '\0'" true on its + * first operand. */ + ExpectNull(wc_strtok(NULL, ",", NULL)); + + /* str non-NULL: first operand false, and the second guard decided by + * *str instead. */ + ExpectNotNull(wc_strtok(tokBuf, ",", &tokNext)); + } +#endif /* USE_WOLF_STRTOK */ + +#ifdef USE_WOLF_STRSEP + { + char sepBuf[] = "a,b"; + char* sepp = sepBuf; + char* sepNull = NULL; + + /* "stringp == NULL || *stringp == NULL", one operand true per call. */ + ExpectNull(wc_strsep(NULL, ",")); + ExpectNull(wc_strsep(&sepNull, ",")); + /* both false */ + ExpectNotNull(wc_strsep(&sepp, ",")); + } +#endif /* USE_WOLF_STRSEP */ + +#ifndef SINGLE_THREADED + { + THREAD_TYPE portThread; + + XMEMSET(&portThread, 0, sizeof(portThread)); + + /* wolfSSL_NewThread: "thread == NULL || cb == NULL", each operand + * flipped independently, then both false on a thread that is created + * and joined. */ + ExpectIntEQ(wolfSSL_NewThread(NULL, test_port_thread_cb, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_NewThread(&portThread, NULL, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + if (EXPECT_SUCCESS()) { + int thrRet = wolfSSL_NewThread(&portThread, test_port_thread_cb, + NULL); + ExpectIntEQ(thrRet, 0); + if (thrRet == 0) { + ExpectIntEQ(wolfSSL_JoinThread(portThread), 0); + } + } + } +#endif /* !SINGLE_THREADED */ + +#ifdef USE_WOLF_STRLCPY + { + char lcpyDst[4]; + + /* "i < (dstSize - 1) && *src != '\0'": a source longer than the + * destination ends the loop on the size operand rather than on the + * terminator, which is that operand's uncovered half. */ + XMEMSET(lcpyDst, 0, sizeof(lcpyDst)); + ExpectIntEQ((int)wc_strlcpy(lcpyDst, "abcdef", 3), 2); + ExpectIntEQ(XSTRNCMP(lcpyDst, "ab", 3), 0); + + /* short source: the loop ends on the terminator instead. */ + XMEMSET(lcpyDst, 0, sizeof(lcpyDst)); + ExpectIntEQ((int)wc_strlcpy(lcpyDst, "a", sizeof(lcpyDst)), 1); + } +#endif /* USE_WOLF_STRLCPY */ + + return EXPECT_RESULT(); +} diff --git a/tests/api/test_port.h b/tests/api/test_port.h new file mode 100644 index 0000000000..b16a8f7170 --- /dev/null +++ b/tests/api/test_port.h @@ -0,0 +1,32 @@ +/* test_port.h + * + * Copyright (C) 2006-2026 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 3 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_PORT_H +#define WOLFCRYPT_TEST_PORT_H + +#include + +int test_wc_PortDecisionCoverage(void); + +#define TEST_PORT_DECLS \ + TEST_DECL_GROUP("port", test_wc_PortDecisionCoverage) + +#endif /* WOLFCRYPT_TEST_PORT_H */