diff --git a/.github/workflows/_resolve-wolfssl.yml b/.github/workflows/_resolve-wolfssl.yml new file mode 100644 index 0000000..3c5bfed --- /dev/null +++ b/.github/workflows/_resolve-wolfssl.yml @@ -0,0 +1,63 @@ +name: Resolve wolfSSL versions + +on: + workflow_call: + outputs: + matrix: + description: 'JSON matrix include of wolfSSL refs (master + latest -stable), each with a pqc flag' + value: ${{ jobs.resolve.outputs.matrix }} + refs: + description: 'JSON array of wolfSSL refs ([latest -stable, master]) for use as a matrix axis' + value: ${{ jobs.resolve.outputs.refs }} + latest_stable: + description: 'Latest wolfSSL v*-stable tag resolved at run time' + value: ${{ jobs.resolve.outputs.latest_stable }} + latest_pqc: + description: 'true when latest -stable is strictly newer than the v5.9.1 PQC floor' + value: ${{ jobs.resolve.outputs.latest_pqc }} + +permissions: + contents: read + +jobs: + resolve: + name: Resolve wolfSSL version matrix + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + refs: ${{ steps.set-matrix.outputs.refs }} + latest_stable: ${{ steps.set-matrix.outputs.latest_stable }} + latest_pqc: ${{ steps.set-matrix.outputs.latest_pqc }} + steps: + - name: Resolve latest -stable wolfSSL tag and PQC eligibility + id: set-matrix + run: | + set -euo pipefail + LATEST=$(git ls-remote --tags --refs https://github.com/wolfSSL/wolfssl.git 'v*-stable' \ + | awk -F/ '{print $NF}' | sort -V | tail -n 1) + if [ -z "${LATEST:-}" ]; then + echo "::error::Could not resolve latest wolfSSL -stable tag from remote" + exit 1 + fi + echo "Latest stable wolfSSL: $LATEST" + echo "latest_stable=$LATEST" >> "$GITHUB_OUTPUT" + # Enable PQC only when $LATEST is strictly newer than v5.9.1-stable. + # The wc_MlDsaKey_* API lands post-v5.9.1-stable; older stables only + # ship the legacy ML-DSA API. + PQC_FLOOR="v5.9.1-stable" + if [ "$(printf '%s\n%s\n' "$PQC_FLOOR" "$LATEST" | sort -V | tail -n 1)" != "$PQC_FLOOR" ]; then + LATEST_PQC=true + else + LATEST_PQC=false + fi + echo "latest-stable PQC eligible: $LATEST_PQC" + echo "latest_pqc=$LATEST_PQC" >> "$GITHUB_OUTPUT" + MATRIX=$(jq -nc --arg latest "$LATEST" --argjson latest_pqc "$LATEST_PQC" '{ + include: [ + {"wolfssl-version":$latest,"wolfssl-ref":$latest,"pqc":$latest_pqc}, + {"wolfssl-version":"master","wolfssl-ref":"master","pqc":true} + ] + }') + echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" + REFS=$(jq -nc --arg latest "$LATEST" '[$latest, "master"]') + echo "refs=$REFS" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/make-test.yml b/.github/workflows/make-test.yml index bbd254c..c352cd6 100644 --- a/.github/workflows/make-test.yml +++ b/.github/workflows/make-test.yml @@ -10,6 +10,10 @@ on: make-args: required: false type: string + wolfssl-ref: + required: false + default: master + type: string jobs: @@ -30,12 +34,13 @@ jobs: - uses: actions/checkout@master with: repository: wolfssl/wolfssl + ref: ${{ inputs.wolfssl-ref }} path: wolfssl - name: wolfssl build working-directory: ./wolfssl run: | ./autogen.sh - ./configure --enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys CFLAGS="-DWOLFSSL_DH_EXTRA" + ./configure --enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys --enable-opensslextra CFLAGS="-DWOLFSSL_DH_EXTRA" make make check make dist diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml new file mode 100644 index 0000000..1b82cbd --- /dev/null +++ b/.github/workflows/sanitizer.yml @@ -0,0 +1,79 @@ +name: wolfKeyMgr Sanitizer Build Workflow + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + + # Auto-resolve the latest wolfSSL -stable tag; refs = [ latest -stable, master ]. + resolve: + uses: ./.github/workflows/_resolve-wolfssl.yml + + sanitizer: + name: ${{ matrix.sanitizer.name }} (wolfSSL ${{ matrix.wolfssl-ref }}) + needs: resolve + runs-on: ubuntu-latest + timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + sanitizer: + - name: ASan + cflags: "-fsanitize=address -fno-omit-frame-pointer -g -O1" + - name: UBSan + cflags: "-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -g" + + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libevent-dev libpcap-dev autoconf automake libtool + + - name: Checkout wolfKeyMgr + uses: actions/checkout@v4 + + - name: Build wolfSSL (${{ matrix.sanitizer.name }}) + run: | + git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} \ + https://github.com/wolfSSL/wolfssl.git + cd wolfssl + ./autogen.sh + ./configure --enable-sniffer --enable-curve25519 --enable-curve448 \ + --enable-enckeys --enable-opensslextra \ + CFLAGS="-DWOLFSSL_DH_EXTRA ${{ matrix.sanitizer.cflags }}" + make -j"$(nproc)" + sudo make install + sudo ldconfig + + - name: Build wolfKeyMgr (${{ matrix.sanitizer.name }}) + run: | + ./autogen.sh + ./configure CFLAGS="${{ matrix.sanitizer.cflags }}" + make -j"$(nproc)" + + - name: make check (${{ matrix.sanitizer.name }}) + env: + # detect_leaks=0: catch overflows / use-after-free now; leak + # detection can flag library init allocations and is left to a + # follow-up. + ASAN_OPTIONS: detect_leaks=0 + UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1 + run: make check + + - name: Upload failure logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: wolfKeyMgr-${{ matrix.sanitizer.name }}-wolfssl-${{ matrix.wolfssl-ref }}-logs + path: | + test-suite.log + tests/*.log + retention-days: 5 diff --git a/.github/workflows/test-nightly.yml b/.github/workflows/test-nightly.yml index b9795c5..dc77ac1 100644 --- a/.github/workflows/test-nightly.yml +++ b/.github/workflows/test-nightly.yml @@ -15,20 +15,73 @@ on: jobs: + # Auto-resolve the latest wolfSSL -stable tag so nightly tracks releases + # without a manual bump; refs = [ latest -stable, master ]. + resolve: + uses: ./.github/workflows/_resolve-wolfssl.yml + build_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} uses: ./.github/workflows/make-test.yml with: config-args: make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} build_debug_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} uses: ./.github/workflows/make-test.yml with: config-args: --enable-debug make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} build_no_vault_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} uses: ./.github/workflows/make-test.yml with: config-args: --disable-vault make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} + + build_no_sniffer_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + uses: ./.github/workflows/make-test.yml + with: + config-args: --disable-sniffer + make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} + + build_vault_clear_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + uses: ./.github/workflows/make-test.yml + with: + config-args: --enable-vault=clear + make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} + + build_minimal_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + uses: ./.github/workflows/make-test.yml + with: + config-args: --disable-sniffer --disable-vault + make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} diff --git a/.github/workflows/test-pull.yml b/.github/workflows/test-pull.yml index acdd678..eaabe71 100644 --- a/.github/workflows/test-pull.yml +++ b/.github/workflows/test-pull.yml @@ -8,20 +8,73 @@ on: jobs: + # Auto-resolve the latest wolfSSL -stable tag so CI tracks releases without a + # manual bump; refs = [ latest -stable, master ]. + resolve: + uses: ./.github/workflows/_resolve-wolfssl.yml + build_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} uses: ./.github/workflows/make-test.yml with: config-args: make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} build_debug_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} uses: ./.github/workflows/make-test.yml with: config-args: --enable-debug make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} build_no_vault_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} uses: ./.github/workflows/make-test.yml with: config-args: --disable-vault make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} + + build_no_sniffer_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + uses: ./.github/workflows/make-test.yml + with: + config-args: --disable-sniffer + make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} + + build_vault_clear_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + uses: ./.github/workflows/make-test.yml + with: + config-args: --enable-vault=clear + make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} + + build_minimal_test: + needs: resolve + strategy: + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + uses: ./.github/workflows/make-test.yml + with: + config-args: --disable-sniffer --disable-vault + make-args: + wolfssl-ref: ${{ matrix.wolfssl-ref }} diff --git a/README.md b/README.md index 861a7d1..f2019cb 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ $ ./autogen.sh $ git clone https://github.com/wolfssl/wolfssl $ cd wolfssl $ ./autogen.sh -$ ./configure --enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys CFLAGS="-DWOLFSSL_DH_EXTRA" +$ ./configure --enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys --enable-opensslextra CFLAGS="-DWOLFSSL_DH_EXTRA" $ make $ make check # (optional, but highly recommended) $ sudo make install diff --git a/configure.ac b/configure.ac index 03db1d8..fa51c5e 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ AC_PREREQ(2.59) -AC_INIT([wolfKeyManager],[1.1],[http://www.wolfssl.com]) +AC_INIT([wolfKeyManager],[1.2],[http://www.wolfssl.com]) AC_CONFIG_AUX_DIR(config) AC_CONFIG_HEADERS([wolfkeymgr/config.h]) AC_CONFIG_MACRO_DIR(m4) @@ -71,7 +71,7 @@ LT_PREREQ([2.2]) LT_INIT([disable-static win32-dll]) # Shared library versioning -WOLFKM_LIBRARY_VERSION=9:0:0 +WOLFKM_LIBRARY_VERSION=9:1:0 # | | | # +------+ | +---+ # | | | diff --git a/src/mod_ets.c b/src/mod_ets.c index d653c28..99a7dc4 100644 --- a/src/mod_ets.c +++ b/src/mod_ets.c @@ -257,7 +257,7 @@ static int EtsClientGet(EtsClientCtx* client, EtsKey* key, /* TODO: handle HTTP chunked content type */ /* TODO: handle multiple packets */ /* TODO: Integrate HTTP processing with read to handle larger payloads */ - key->responseSz = sizeof(key->response); + key->responseSz = sizeof(key->response) - 1; /* leave room for null */ do { ret = wolfTlsRead(client->ssl, (byte*)key->response, (int*)&key->responseSz, timeoutSec); @@ -272,11 +272,15 @@ static int EtsClientGet(EtsClientCtx* client, EtsKey* key, if (ret > 0) { /* parse HTTP server response */ key->expires = 0; + key->response[key->responseSz] = '\0'; ret = wolfHttpClient_ParseResponse(rsp, (char*)key->response, key->responseSz); if (ret == 0 && rsp->body && rsp->bodySz > 0) { wolfHttpResponsePrint(rsp); + /* parse expires before memmove invalidates the header pointers */ + ParseHttpResponseExpires(rsp, key, wolfGetCurrentTimeT()); + /* move payload (body) to response (same buffer) */ memmove(key->response, rsp->body, rsp->bodySz); key->responseSz = rsp->bodySz; @@ -319,9 +323,6 @@ int wolfEtsClientGet(EtsClientCtx* client, EtsKey* key, ret = EtsClientGet(client, key, keyType, fingerprint, contextStr, timeoutSec, &rsp); - if (ret == 0) { - ParseHttpResponseExpires(&rsp, key, now); - } return ret; } @@ -372,7 +373,7 @@ int wolfEtsClientPush(EtsClientCtx* client, EtsKeyType keyType, /* wait for key response */ do { /* 0 = no timeout - blocking */ - key.responseSz = sizeof(key.response); + key.responseSz = sizeof(key.response) - 1; /* leave room for null */ ret = wolfTlsRead(client->ssl, (byte*)key.response, (int*)&key.responseSz, 0); if (ret < 0 && ret != WOLFKM_BAD_TIMEOUT) { @@ -386,6 +387,7 @@ int wolfEtsClientPush(EtsClientCtx* client, EtsKeyType keyType, /* parse HTTP server response */ key.expires = 0; + key.response[key.responseSz] = '\0'; ret = wolfHttpClient_ParseResponse(&rsp, (char*)key.response, key.responseSz); if (ret == 0 && rsp.body && rsp.bodySz > 0) { @@ -395,7 +397,7 @@ int wolfEtsClientPush(EtsClientCtx* client, EtsKeyType keyType, ParseHttpResponseExpires(&rsp, &key, now); /* move payload (body) to response (same buffer) */ - memcpy(key.response, rsp.body, rsp.bodySz); + memmove(key.response, rsp.body, rsp.bodySz); key.responseSz = rsp.bodySz; ret = cb(client, &key, cbCtx); @@ -415,6 +417,8 @@ int wolfEtsClientPush(EtsClientCtx* client, EtsKeyType keyType, } while (ret == 0 || ret == WOLFKM_BAD_TIMEOUT); wc_UnLockMutex(&client->lock); + wolfKeyMgr_ForceZero(&key, sizeof(key)); + return ret; } @@ -687,7 +691,7 @@ static int wolfKeyCalcFingerprint(EtsKeyType keyType, const byte* pub, word32 pu /* Return 10-bytes truncated (big endian) */ if (tmpSz > WC_SHA256_DIGEST_SIZE) tmpSz = WC_SHA256_DIGEST_SIZE; - memcpy(fp, pub, tmpSz); + memcpy(fp, digest, tmpSz); *fpSz = tmpSz; } @@ -905,6 +909,8 @@ static int GenNewKeyDh(EtsKey* key, EtsKeyType keyType, WC_RNG* rng) } wc_FreeDhKey(&dh); + wolfKeyMgr_ForceZero(privKey, sizeof(privKey)); + if (ret != 0) { XLOG(WOLFKM_LOG_ERROR, "DH Key Generation Failed! %d\n", ret); } @@ -1153,7 +1159,9 @@ int wolfEtsKeyComputeName(EtsKey* key) } #endif - key->fingerprintSz = fpSz; + if (ret == 0) { + key->fingerprintSz = fpSz; + } return ret; } @@ -1193,6 +1201,7 @@ void wolfEtsKeyFree(EtsKey* key) { if (key) { if (key->isDynamic) { + wolfKeyMgr_ForceZero(key, sizeof(*key)); free(key); } } diff --git a/src/mod_http.c b/src/mod_http.c index 8c57afa..55a60b8 100644 --- a/src/mod_http.c +++ b/src/mod_http.c @@ -49,7 +49,7 @@ const char* wolfHttpGetMethodStr(HttpMethodType type, word32* strLen) str = "DELETE"; break; case HTTP_METHOD_TRACE: - str = "DELETE"; + str = "TRACE"; break; case HTTP_METHOD_CONNECT: str = "CONNECT"; @@ -250,10 +250,10 @@ int wolfHttpServer_EncodeResponse(int rspCode, const char* message, /* append version and response code / message */ i = snprintf(out, remain, "%s %d %s\r\n", kHTTPVer, rspCode, message); - if (i > 0) { - out += i; - remain -= i; - } + if (i < 0 || (word32)i >= remain) + return WOLFKM_BAD_ARGS; + out += i; + remain -= i; /* append headers */ for (c=0; c<(int)headerCount && remain > 0; c++) { @@ -261,28 +261,28 @@ int wolfHttpServer_EncodeResponse(int rspCode, const char* message, i = snprintf(out, remain, "%s%s\r\n", wolfHttpGetHeaderStr(hdr->type, NULL), hdr->string); - if (i > 0) { - out += i; - remain -= i; - } + if (i < 0 || (word32)i >= remain) + return WOLFKM_BAD_ARGS; + out += i; + remain -= i; } /* append content length */ if (bodySz > 0) { i = snprintf(out, remain, "%s%d\r\n", wolfHttpGetHeaderStr(HTTP_HDR_CONTENT_LENGTH, NULL), bodySz); - if (i > 0) { - out += i; - remain -= i; - } + if (i < 0 || (word32)i >= remain) + return WOLFKM_BAD_ARGS; + out += i; + remain -= i; } /* add trailing crlf and body */ i = snprintf(out, remain, "\r\n"); - if (i > 0) { - out += i; - remain -= i; - } + if (i < 0 || (word32)i >= remain) + return WOLFKM_BAD_ARGS; + out += i; + remain -= i; /* append body (optional) */ if (body && bodySz > 0) { @@ -357,6 +357,11 @@ int wolfHttpClient_ParseResponse(HttpRsp* rsp, char* buf, word32 sz) endline = strstr(sec, kCrlf); /* Find end of line */ } + /* require the blank-line header terminator before computing the body */ + if (endline == NULL) { + return HTTP_ERROR_EXPECTED_CRLF; + } + /* calculate total length */ itemSz = (word32)((size_t)endline - (size_t)buf); @@ -384,10 +389,10 @@ int wolfHttpClient_EncodeRequest(HttpMethodType type, const char* uri, /* append method */ i = snprintf(out, remain, "%s %s %s\r\n", wolfHttpGetMethodStr(type, NULL), uri, kHTTPVer); - if (i > 0) { - out += i; - remain -= i; - } + if (i < 0 || (word32)i >= remain) + return WOLFKM_BAD_ARGS; + out += i; + remain -= i; /* append headers */ for (c=0; c<(int)headerCount && remain > 0; c++) { @@ -395,10 +400,10 @@ int wolfHttpClient_EncodeRequest(HttpMethodType type, const char* uri, i = snprintf(out, remain, "%s%s\r\n", wolfHttpGetHeaderStr(hdr->type, NULL), hdr->string); - if (i > 0) { - out += i; - remain -= i; - } + if (i < 0 || (word32)i >= remain) + return WOLFKM_BAD_ARGS; + out += i; + remain -= i; } /* calculate total length */ @@ -450,20 +455,27 @@ void wolfHttpResponsePrint(HttpRsp* rsp) int wolfHttpUriEncode(const char *s, size_t sSz, char *enc, size_t encSz) { int idx = 0; - for (; idx < (int)sSz && *s; s++){ + size_t i; + byte c; + char a, b; + for (i = 0; i < sSz && s[i] != '\0'; i++){ + c = (byte)s[i]; if (idx + 3 > (int)encSz) return -1; - if (*s == '*' || *s == '-' || *s == '.' || *s == '_') { - char a = (char)(*s >> 4), b = (char)(*s & 0xff); - enc[idx++] = '%'; - enc[idx++] = (a < 10) ? '0' + a : 'A' + a - 10; - enc[idx++] = (b < 10) ? '0' + b : 'A' + b - 10; + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '-' || c == '.' || c == '_' || c == '~') { + enc[idx++] = c; } - else if (*s == ' ') { + else if (c == ' ') { enc[idx++] = '+'; } else { - enc[idx++] = *s; + a = (char)((c >> 4) & 0x0f); + b = (char)(c & 0x0f); + enc[idx++] = '%'; + enc[idx++] = (a < 10) ? '0' + a : 'A' + a - 10; + enc[idx++] = (b < 10) ? '0' + b : 'A' + b - 10; } } return idx; @@ -476,7 +488,7 @@ static int hex_to_char(char a, byte* out) else if (a >= 'A' && a <= 'F') a -= 'A' - 10; else if (a >= 'a' && a <= 'f') - a -= 'a' - 'A' - 10; + a -= 'a' - 10; else return 0; *out = (byte)a; @@ -486,24 +498,31 @@ static int hex_to_char(char a, byte* out) int wolfHttpUriDecode(const char *s, size_t sSz, char *dec, size_t decSz) { int idx = 0; + int ret = 0; + size_t i; byte a, b; - for (; idx < (int)sSz && *s; s++){ - if (idx + 1 > (int)decSz) - return -1; - if (*s == '%' && - hex_to_char((char)s[1], &a) && - hex_to_char((char)s[2], &b)) { - dec[idx++] = (a << 4 | b); - s+=2; + if (dec == NULL || decSz == 0) + return -1; + for (i = 0; i < sSz && s[i] != '\0'; i++){ + if (idx + 1 >= (int)decSz) { + ret = -1; /* leave room for the null terminator */ + break; } - else if (*s == '+') { + if (s[i] == '%' && i + 2 < sSz && + hex_to_char(s[i+1], &a) && + hex_to_char(s[i+2], &b)) { + dec[idx++] = (char)(a << 4 | b); + i += 2; + } + else if (s[i] == '+') { dec[idx++] = ' '; } else { - dec[idx++] = *s; + dec[idx++] = s[i]; } } - return idx; + dec[idx] = '\0'; + return (ret == 0) ? idx : ret; } int wolfHttpUrlDecode(HttpUrl* url, char* s) diff --git a/src/mod_socket.c b/src/mod_socket.c index 26e86ee..4bc4217 100644 --- a/src/mod_socket.c +++ b/src/mod_socket.c @@ -308,7 +308,7 @@ int wolfSocketWrite(WKM_SOCKET_T sockFd, const byte* buffer, void wolfSocketClose(WKM_SOCKET_T sockFd) { - if (WKM_SOCKET_IS_INVALID(sockFd)) { + if (!WKM_SOCKET_IS_INVALID(sockFd)) { #ifdef USE_WINDOWS_API closesocket(sockFd); #else diff --git a/src/mod_tls.c b/src/mod_tls.c index 590dde8..9c0ec16 100644 --- a/src/mod_tls.c +++ b/src/mod_tls.c @@ -104,17 +104,21 @@ static int wkmTlsWriteCb(WOLFSSL* ssl, char* buf, int sz, void* ctx) #ifdef WOLFSSL_ENCRYPTED_KEYS static int wkmTlsPasswordCallBack(char* passwd, int sz, int rw, void* userdata) { + const char* pass; + int len; (void)rw; - (void)userdata; - if (userdata != NULL) { - strncpy(passwd, (char*)userdata, sz); - return (int)strlen((char*)userdata); - } - else { - /* generic default password */ - strncpy(passwd, "wolfssl", sz); - return 8; - } + + if (sz <= 0) + return 0; + + /* generic default password when none is provided */ + pass = (userdata != NULL) ? (const char*)userdata : "wolfssl"; + len = (int)strlen(pass); + if (len > sz - 1) + len = sz - 1; + memcpy(passwd, pass, len); + passwd[len] = '\0'; + return len; } #endif @@ -234,6 +238,7 @@ static int wolfTlsInitSslDefaults(WOLFSSL_CTX* ctx, WOLFSSL** ssl) return WOLFKM_BAD_MEMORY; } memset(cbCtx, 0, sizeof(wolfTlsCbCtx)); + cbCtx->sockFd = WKM_SOCKET_INVALID; wolfSSL_SetIOReadCtx(tssl, cbCtx); wolfSSL_SetIOWriteCtx(tssl, cbCtx); @@ -254,28 +259,26 @@ static int wolfTlsNegotiate(WOLFSSL* ssl, SOCKET_T sockFd, int timeoutSec) int ret; do { ret = wolfSSL_negotiate(ssl); - if (ret != WOLFSSL_SUCCESS) { - ret = wolfSSL_get_error(ssl, 0); - if (ret == WOLFSSL_ERROR_WANT_READ || - ret == WOLFSSL_ERROR_WANT_WRITE) { - /* do select on socket for timeout */ - ret = wolfSockSelect(sockFd, 1, 1); - if (ret == WKM_SOCKET_SELECT_RECV_READY || - ret == WKM_SOCKET_SELECT_TIMEOUT) { - ret = 0; /* try again */ - timeoutSec--; - } - else - ret = WOLFKM_BAD_TIMEOUT; - } - } - else { + if (ret == WOLFSSL_SUCCESS) { ret = 0; /* success */ break; /* done */ } - } while (ret == 0 && timeoutSec > 0); - if (timeoutSec <= 0) - ret = WOLFKM_BAD_TIMEOUT; + ret = wolfSSL_get_error(ssl, 0); + if (ret == WOLFSSL_ERROR_WANT_READ || + ret == WOLFSSL_ERROR_WANT_WRITE) { + /* do select on socket for timeout */ + ret = wolfSockSelect(sockFd, 1, 1); + if (ret == WKM_SOCKET_SELECT_RECV_READY || + ret == WKM_SOCKET_SELECT_TIMEOUT) { + ret = 0; /* try again */ + timeoutSec--; + if (timeoutSec <= 0) + ret = WOLFKM_BAD_TIMEOUT; + } + else + ret = WOLFKM_BAD_TIMEOUT; + } + } while (ret == 0); return ret; } @@ -357,10 +360,10 @@ int wolfTlsRead(WOLFSSL* ssl, byte* p, int* len, int timeoutSec) if (ret > 0) { *len = ret; } - else if (timeoutSec <= 0) { - ret = WOLFKM_BAD_TIMEOUT; + else if (ret == WOLFKM_BAD_SOCKET) { + XLOG(WOLFKM_LOG_ERROR, "wolfTlsRead socket error\n"); } - else if (ret < 0) { + else if (ret != WOLFKM_BAD_TIMEOUT && err != 0) { XLOG(WOLFKM_LOG_ERROR, "wolfTlsRead error %d: %s\n", err, wolfSSL_ERR_reason_error_string(err)); } diff --git a/src/mod_vault.c b/src/mod_vault.c index 8354198..093ee81 100644 --- a/src/mod_vault.c +++ b/src/mod_vault.c @@ -23,6 +23,9 @@ #include #include #include +#ifndef USE_WINDOWS_API +#include +#endif #ifdef WOLFKM_VAULT @@ -125,6 +128,14 @@ static int wolfVaultCreateNew(wolfVaultCtx* ctx, const char* file) if (ctx->fd == NULL) { return WOLFKM_BAD_FILE; } +#ifndef USE_WINDOWS_API + /* restrict to owner read/write; daemon mode may set a wide umask */ + if (fchmod(fileno(ctx->fd), S_IRUSR | S_IWUSR) != 0) { + fclose(ctx->fd); + ctx->fd = NULL; + return WOLFKM_BAD_FILE; + } +#endif /* write header */ memset(&ctx->header, 0, sizeof(ctx->header)); @@ -178,9 +189,11 @@ int wolfVaultOpen(wolfVaultCtx** ctx, const char* file) ret = WOLFKM_BAD_FILE; } - if (ret == 0 && ctx_new->header.headerSz > sizeof(ctx_new->header)) { - XLOG(WOLFKM_LOG_ERROR, "Header size invalid! %u != %u\n", - (uint32_t)sizeof(ctx_new->header), ctx_new->header.headerSz); + if (ret == 0 && (ctx_new->header.headerSz > sizeof(ctx_new->header) || + ctx_new->header.headerSz < (word32)headSz)) { + XLOG(WOLFKM_LOG_ERROR, "Header size invalid! %u (min %d, max %u)\n", + ctx_new->header.headerSz, headSz, + (uint32_t)sizeof(ctx_new->header)); ret = WOLFKM_BAD_FILE; } @@ -204,10 +217,16 @@ int wolfVaultOpen(wolfVaultCtx** ctx, const char* file) if (ret != 0) { /* resetting vault */ XLOG(WOLFKM_LOG_ERROR, "Vault open failed, creating new\n"); + if (ctx_new->fd != NULL) { + fclose(ctx_new->fd); + ctx_new->fd = NULL; + } ret = wolfVaultCreateNew(ctx_new, file); vaultSz = 0; } if (ret == 0) { + /* start item searches at the first item after the header */ + ctx_new->itemPos = ctx_new->header.headerSz; XLOG(WOLFKM_LOG_INFO, "Vault %s opened (%lu bytes)\n", file, vaultSz); } else { @@ -259,6 +278,8 @@ static int wolfVaultSetupKey(wolfVaultCtx* ctx) else { XLOG(WOLFKM_LOG_ERROR, "Error %d setting up AES key!\n", ret); } + + wolfKeyMgr_ForceZero(key, sizeof(key)); #endif return ret; @@ -470,6 +491,7 @@ static int wolfVaultGetItemData(wolfVaultCtx* ctx, wolfVaultItem* item) #endif /* on error release allocated memory */ if (ret != 0 && item->data) { + wolfKeyMgr_ForceZero(item->data, item->dataSz); free(item->data); item->data = NULL; } @@ -526,8 +548,10 @@ int wolfVaultGet(wolfVaultCtx* ctx, wolfVaultItem* item, word32 type, int wolfVaultFreeItem(wolfVaultItem* item) { if (item && item->data != NULL) { + wolfKeyMgr_ForceZero(item->data, item->dataSz); free(item->data); item->data = NULL; + item->dataSz = 0; } return 0; } diff --git a/src/sock_mgr.c b/src/sock_mgr.c index f47a4a6..d59e074 100644 --- a/src/sock_mgr.c +++ b/src/sock_mgr.c @@ -474,7 +474,7 @@ static int DoRead(struct bufferevent* bev, SvcConn* conn) ret = wolfSSL_read(conn->ssl, conn->request + conn->requestSz, - sizeof(conn->request) - conn->requestSz); + sizeof(conn->request) - conn->requestSz - 1); if (ret < 0) { int err = wolfSSL_get_error(conn->ssl, 0); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) @@ -512,6 +512,9 @@ static void ReadCb(struct bufferevent* bev, void* ctx) else if (ret > 0) { conn->requestSz += ret; + /* terminate so string-based HTTP parsing cannot scan past the buffer */ + conn->request[conn->requestSz] = '\0'; + /* handle request with callback */ if (conn->svc && conn->svc->requestCb) { conn->start = wolfGetCurrentTime(); @@ -996,7 +999,7 @@ int wolfKeyMgr_MakeDaemon(int chDir) } } - umask(0); /* always successful */ + umask(0077); /* restrict created files to owner */ fd = open("/dev/null", O_RDWR, 0); if (fd == -1) { diff --git a/src/svc_ets.c b/src/svc_ets.c index a17f62e..7e7e92a 100644 --- a/src/svc_ets.c +++ b/src/svc_ets.c @@ -52,7 +52,8 @@ typedef struct EtsSvcCtx { wolfVaultCtx* vault; /* key vault */ #endif - byte shutdown:1; /* signal to shutdown workers */ + byte shutdown; /* signal to shutdown workers (guarded by kgMutex) */ + byte kgThreadStarted; /* key gen worker thread is running */ } EtsSvcCtx; static EtsSvcCtx gSvcCtx; @@ -261,12 +262,13 @@ static int SetupKeyFindResponse(SvcConn* conn, wolfVaultItem* item) static void* KeyPushWorker(void* arg) { - int ret, i; + int ret = 0, i; SvcInfo* svc = (SvcInfo*)arg; EtsSvcCtx* svcCtx = (EtsSvcCtx*)svc->svcCtx; EtsKey* key; time_t now, nextExpires; int renewSec, keyGenCount; + int doExit = 0; struct timespec max_wait = {0, 0}; /* generate default key */ @@ -319,14 +321,17 @@ static void* KeyPushWorker(void* arg) clock_gettime(CLOCK_REALTIME, &max_wait); max_wait.tv_sec += renewSec; - /* wait for wake signal or timeout */ + /* re-check shutdown under the mutex so a wake signal cannot be missed */ pthread_mutex_lock(&svcCtx->kgMutex); - ret = pthread_cond_timedwait(&svcCtx->kgCond, &svcCtx->kgMutex, + if (!svcCtx->shutdown) { + ret = pthread_cond_timedwait(&svcCtx->kgCond, &svcCtx->kgMutex, &max_wait); + } + doExit = svcCtx->shutdown; pthread_mutex_unlock(&svcCtx->kgMutex); XLOG(WOLFKM_LOG_DEBUG, "Key Generation Worker Wake %d sec\n", ret); - } while (!svcCtx->shutdown); + } while (!doExit); return NULL; } @@ -553,8 +558,11 @@ int wolfEtsSvc_Start(SvcInfo* svc, struct event_base* mainBase, /* start key generation thread */ if (pthread_create(&svcCtx->kgThread, NULL, KeyPushWorker, svc) != 0) { XLOG(WOLFKM_LOG_ERROR, "Error creating keygen worker\n"); + pthread_cond_destroy(&svcCtx->kgCond); + pthread_mutex_destroy(&svcCtx->kgMutex); return WOLFKM_BAD_MEMORY; } + svcCtx->kgThreadStarted = 1; /* setup listening events - IPv6 may contain a IPv4 */ ret = wolfKeyMgr_AddListeners(svc, AF_INET6, listenPort, mainBase); @@ -573,13 +581,25 @@ void wolfEtsSvc_Cleanup(SvcInfo* svc) if (svc) { EtsSvcCtx* svcCtx = (EtsSvcCtx*)svc->svcCtx; + /* stop and join the worker before tearing down what it uses */ + if (svcCtx->kgThreadStarted) { + pthread_mutex_lock(&svcCtx->kgMutex); + svcCtx->shutdown = 1; + pthread_cond_signal(&svcCtx->kgCond); + pthread_mutex_unlock(&svcCtx->kgMutex); + pthread_join(svcCtx->kgThread, NULL); + } + if (svc->keyBuffer) { + wolfKeyMgr_ForceZero(svc->keyBuffer, svc->keyBufferSz); free(svc->keyBuffer); svc->keyBuffer = NULL; + svc->keyBufferSz = 0; } if (svc->certBuffer) { free(svc->certBuffer); svc->certBuffer = NULL; + svc->certBufferSz = 0; } #ifdef WOLFKM_VAULT if (svcCtx->vault) { @@ -589,12 +609,12 @@ void wolfEtsSvc_Cleanup(SvcInfo* svc) wc_FreeRng(&svcCtx->rng); - /* signal shutdown and wake worker */ - svcCtx->shutdown = 1; - WakeKeyGenWorker(svcCtx); - - pthread_mutex_destroy(&svcCtx->kgMutex); - pthread_cond_destroy(&svcCtx->kgCond); + if (svcCtx->kgThreadStarted) { + pthread_mutex_destroy(&svcCtx->kgMutex); + pthread_cond_destroy(&svcCtx->kgCond); + svcCtx->kgThreadStarted = 0; + } + svcCtx->shutdown = 0; /* allow a re-initialized service to run */ pthread_mutex_destroy(&svcCtx->lock); } diff --git a/src/wkm_utils.c b/src/wkm_utils.c index d039bf1..cb9f5a3 100644 --- a/src/wkm_utils.c +++ b/src/wkm_utils.c @@ -66,7 +66,7 @@ const char* wolfKeyMgr_GetError(int err) } else { #ifdef WOLFCRYPT_ONLY - return wc_GetErrorString(error); + return wc_GetErrorString(err); #else return wolfSSL_ERR_reason_error_string(err); #endif @@ -338,7 +338,7 @@ int wolfHexStringToByte(const char* in, word32 inSz, byte* out, word32 outSz) if (in == NULL || out == NULL) return WOLFKM_BAD_ARGS; - for (i = 0; i < (int)inSz && calcSz < outSz; i+=2) { + for (i = 0; i + 1 < (int)inSz && calcSz < outSz; i+=2) { cl = HexToByte((char)in[i]); ch = HexToByte((char)in[i+1]); *out++ = (((byte)cl) << 4) | (byte)ch; diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 279d490..0072f8c 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -20,6 +20,19 @@ */ #include "wolfkeymgr/mod_vault.h" +#include "wolfkeymgr/mod_http.h" +#include "wolfkeymgr/mod_socket.h" +#include "wolfkeymgr/mod_ets.h" +#include "wolfkeymgr/wkm_utils.h" +#include +#include + +#include +#include +#ifndef USE_WINDOWS_API +#include +#include +#endif #if defined(WOLFKM_VAULT) && defined(WOLFKM_VAULT_ENC) /* key: returned AES key */ @@ -116,9 +129,306 @@ static int vault_test(void) return ret; } +static int http_test(void) +{ + int ret = 0; + int rc; + const char* m; + word32 mlen; + char enc[64]; + char dec[64]; + char tiny[4]; + HttpRsp rsp; + HttpReq req; + char goodRsp[] = + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nDATA"; + char badRsp[] = + "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nDATA"; + char goodReq[] = + "GET /path HTTP/1.1\r\nHost: x\r\nAccept: application/pkcs8\r\n\r\n"; + char noHdrReq[] = "GET / HTTP/1.1\r\n\r\n"; + HttpHeader hdrs[1]; + char small[8]; + word32 smallSz; + + /* TRACE must encode as "TRACE", not "DELETE" */ + m = wolfHttpGetMethodStr(HTTP_METHOD_TRACE, &mlen); + if (m == NULL || strcmp(m, "TRACE") != 0) { + printf(" method TRACE string wrong: %s\n", m ? m : "(null)"); + ret = -1; + } + + /* lowercase percent-encoding must decode correctly */ + rc = wolfHttpUriDecode("%2a%5f", 6, dec, sizeof(dec)); + if (rc != 2 || (byte)dec[0] != '*' || (byte)dec[1] != '_') { + printf(" lowercase hex decode failed rc=%d\n", rc); + ret = -1; + } + + /* reserved characters must percent-encode and round-trip */ + rc = wolfHttpUriEncode("a&b", 3, enc, sizeof(enc)); + if (rc < 0 || rc >= (int)sizeof(enc)) { + printf(" uri encode failed rc=%d\n", rc); + ret = -1; + } + else { + enc[rc] = '\0'; + if (strcmp(enc, "a%26b") != 0) { + printf(" uri encode wrong output: %s\n", enc); + ret = -1; + } + rc = wolfHttpUriDecode(enc, strlen(enc), dec, sizeof(dec)); + if (rc != 3 || strcmp(dec, "a&b") != 0) { + printf(" uri encode/decode round-trip failed: %s\n", dec); + ret = -1; + } + } + + /* decode must always null terminate, even when the output is full */ + rc = wolfHttpUriDecode("AAAAAAAA", 8, tiny, sizeof(tiny)); + if (rc != -1 || tiny[sizeof(tiny)-1] != '\0' || strlen(tiny) != 3) { + printf(" uri decode did not null terminate on overflow rc=%d\n", rc); + ret = -1; + } + + /* a response missing the blank-line terminator must be rejected */ + rc = wolfHttpClient_ParseResponse(&rsp, badRsp, (word32)strlen(badRsp)); + if (rc != HTTP_ERROR_EXPECTED_CRLF) { + printf(" truncated response not rejected rc=%d\n", rc); + ret = -1; + } + + /* a well-formed response must still parse with the correct body */ + rc = wolfHttpClient_ParseResponse(&rsp, goodRsp, (word32)strlen(goodRsp)); + if (rc != 0 || rsp.code != 200 || rsp.bodySz != 4 || + memcmp(rsp.body, "DATA", 4) != 0) { + printf(" valid response parse failed rc=%d code=%d bodySz=%d\n", + rc, rsp.code, rsp.bodySz); + ret = -1; + } + + /* header count must be exact; the blank-line terminator is not a header */ + rc = wolfHttpServer_ParseRequest(&req, (byte*)goodReq, + (word32)strlen(goodReq)); + if (rc != 0 || req.type != HTTP_METHOD_GET || req.headerCount != 2) { + printf(" request parse wrong rc=%d type=%d headers=%d\n", + rc, req.type, req.headerCount); + ret = -1; + } + + /* a request with no headers must report zero headers */ + rc = wolfHttpServer_ParseRequest(&req, (byte*)noHdrReq, + (word32)strlen(noHdrReq)); + if (rc != 0 || req.headerCount != 0) { + printf(" no-header request parse wrong rc=%d headers=%d\n", + rc, req.headerCount); + ret = -1; + } + + /* encoding into an undersized buffer must error, not overflow */ + hdrs[0].type = HTTP_HDR_CONTENT_TYPE; + hdrs[0].string = "application/pkcs8"; + smallSz = sizeof(small); + rc = wolfHttpServer_EncodeResponse(200, "OK", (byte*)small, &smallSz, + hdrs, 1, NULL, 0); + if (rc != WOLFKM_BAD_ARGS) { + printf(" encode into small buffer did not error rc=%d\n", rc); + ret = -1; + } + + return ret; +} + +static int utils_test(void) +{ + int ret = 0; + int rc; + byte hexout[8]; + + /* odd-length hex input must not read past the buffer */ + memset(hexout, 0, sizeof(hexout)); + rc = wolfHexStringToByte("abc", 3, hexout, sizeof(hexout)); + if (rc != 1 || hexout[0] != 0xab) { + printf(" odd-length hex decode failed rc=%d byte=%02x\n", + rc, hexout[0]); + ret = -1; + } + + return ret; +} + +static int socket_test(void) +{ + int ret = 0; +#ifndef USE_WINDOWS_API + WKM_SOCKET_T fd; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (WKM_SOCKET_IS_INVALID(fd)) { + printf(" socket() failed, skipping\n"); + return 0; + } + + wolfSocketClose(fd); + + /* a valid socket must actually be closed; a second close should fail */ + if (close(fd) == 0) { + printf(" wolfSocketClose did not close a valid socket\n"); + ret = -1; + } +#endif + return ret; +} + +static int vault_reopen_test(void) +{ + int ret = 0; +#ifdef WOLFKM_VAULT + wolfVaultCtx* ctx = NULL; + wolfVaultItem item; + const char* testFile = "vault_reopen.bin"; + const byte name[] = "reopenName"; + const byte data[] = "reopenData"; + + unlink(testFile); + + ret = wolfVaultOpen(&ctx, testFile); +#ifdef WOLFKM_VAULT_ENC + if (ret == 0) + ret = wolfVaultAuth(ctx, wolfEtsSvcVaultAuthCb, NULL); +#endif + if (ret == 0) + ret = wolfVaultAdd(ctx, 7, name, sizeof(name), data, sizeof(data)); + if (ctx != NULL) + wolfVaultClose(ctx); + + /* reopen and get the item without adding first */ + ctx = NULL; + if (ret == 0) + ret = wolfVaultOpen(&ctx, testFile); +#ifdef WOLFKM_VAULT_ENC + if (ret == 0) + ret = wolfVaultAuth(ctx, wolfEtsSvcVaultAuthCb, NULL); +#endif + if (ret == 0) { + memset(&item, 0, sizeof(item)); + ret = wolfVaultGet(ctx, &item, 7, name, sizeof(name)); + if (ret == 0) { + if (item.dataSz != sizeof(data) || + memcmp(item.data, data, sizeof(data)) != 0) { + printf(" reopened vault item mismatch\n"); + ret = -1; + } + wolfVaultFreeItem(&item); + } + else { + printf(" vault get after reopen failed: %d\n", ret); + } + } + if (ctx != NULL) + wolfVaultClose(ctx); + unlink(testFile); +#endif + return ret; +} + +static int vault_corrupt_test(void) +{ + int ret = 0; +#ifdef WOLFKM_VAULT + /* on-disk vault format constants (must match mod_vault.c) */ + const uint32_t headerId = 0x666C6F57U; + const uint32_t headerVer = 1; + const uint32_t badHeaderSz = 0; /* too small: would underflow the read */ + const char* testFile = "vault_corrupt.bin"; + wolfVaultCtx* ctx = NULL; + byte payload[64]; + FILE* f; + + unlink(testFile); + + f = fopen(testFile, "wb"); + if (f == NULL) + return -1; + fwrite(&headerId, 1, sizeof(headerId), f); + fwrite(&headerVer, 1, sizeof(headerVer), f); + fwrite(&badHeaderSz, 1, sizeof(badHeaderSz), f); + memset(payload, 0xAA, sizeof(payload)); + fwrite(payload, 1, sizeof(payload), f); + fclose(f); + + /* an undersized header must recreate cleanly, not overflow the buffer */ + ret = wolfVaultOpen(&ctx, testFile); + if (ret == 0 && ctx != NULL) + wolfVaultClose(ctx); + unlink(testFile); +#endif + return ret; +} + +static int fingerprint_test(void) +{ + int ret = 0; +#if defined(HAVE_ECC) && !defined(NO_SHA256) + WC_RNG rng; + EtsKey key; + ecc_key ecKey; + word32 idx = 0; + byte pub[MAX_ECC_BYTES * 2]; + word32 pubXLen = (word32)sizeof(pub) / 2; + word32 pubYLen = (word32)sizeof(pub) / 2; + word32 keySize = 0; + byte digest[WC_SHA256_DIGEST_SIZE]; + int rngInit = 0, eccInit = 0; + + memset(&key, 0, sizeof(key)); + ret = wc_InitRng(&rng); + if (ret == 0) { + rngInit = 1; + ret = wolfEtsKeyGen(&key, ETS_KEY_TYPE_SECP256R1, &rng); + } + if (ret == 0) { + ret = wc_ecc_init(&ecKey); + } + if (ret == 0) { + eccInit = 1; + ret = wc_EccPrivateKeyDecode((byte*)key.response, &idx, &ecKey, + key.responseSz); + } + if (ret == 0) { + keySize = (word32)wc_ecc_size(&ecKey); + ret = wc_ecc_export_ex(&ecKey, pub, &pubXLen, pub + keySize, &pubYLen, + NULL, NULL, WC_TYPE_UNSIGNED_BIN); + } + if (ret == 0) { + ret = wc_Sha256Hash(pub, keySize * 2, digest); + } + if (ret == 0) { + /* fingerprint is the truncated SHA-256 of the public key */ + if (memcmp(key.fingerprint, digest, sizeof(key.fingerprint)) != 0) { + printf(" fingerprint is not the SHA-256 of the public key\n"); + ret = -1; + } + /* and must not be the raw public key bytes (the original bug) */ + if (ret == 0 && + memcmp(key.fingerprint, pub, sizeof(key.fingerprint)) == 0) { + printf(" fingerprint matches raw public key (regression)\n"); + ret = -1; + } + } + + if (eccInit) + wc_ecc_free(&ecKey); + if (rngInit) + wc_FreeRng(&rng); +#endif + return ret; +} + int main(int argc, char** argv) { - int ret; + int ret = 0; + int rc; enum log_level_t logLevel = WOLFKM_DEFAULT_LOG_LEVEL; (void)argc; @@ -128,8 +438,33 @@ int main(int argc, char** argv) wolfKeyMgr_SetLogFile(NULL, 0, logLevel); printf("Key Manager Unit Test\n"); - ret = vault_test(); - printf("Vault Open Test: %s\n", ret == 0 ? "pass" : "fail"); + rc = vault_test(); + printf("Vault Open Test: %s\n", rc == 0 ? "pass" : "fail"); + if (rc != 0) ret = rc; + + rc = http_test(); + printf("HTTP Test: %s\n", rc == 0 ? "pass" : "fail"); + if (rc != 0) ret = rc; + + rc = utils_test(); + printf("Utils Test: %s\n", rc == 0 ? "pass" : "fail"); + if (rc != 0) ret = rc; + + rc = socket_test(); + printf("Socket Test: %s\n", rc == 0 ? "pass" : "fail"); + if (rc != 0) ret = rc; + + rc = vault_reopen_test(); + printf("Vault Reopen Test: %s\n", rc == 0 ? "pass" : "fail"); + if (rc != 0) ret = rc; + + rc = vault_corrupt_test(); + printf("Vault Corrupt Header Test: %s\n", rc == 0 ? "pass" : "fail"); + if (rc != 0) ret = rc; + + rc = fingerprint_test(); + printf("Fingerprint Test: %s\n", rc == 0 ? "pass" : "fail"); + if (rc != 0) ret = rc; return ret; } diff --git a/wolfkeymgr/mod_socket.h b/wolfkeymgr/mod_socket.h index 2972966..aafb4f9 100644 --- a/wolfkeymgr/mod_socket.h +++ b/wolfkeymgr/mod_socket.h @@ -55,8 +55,8 @@ extern "C" { #endif #include #define WKM_SOCKET_T int - #define WKM_SOCKET_INVALID (WKM_SOCKET_T)(0) - #define WKM_SOCKET_IS_INVALID(s) ((WKM_SOCKET_T)(s) < WKM_SOCKET_INVALID) + #define WKM_SOCKET_INVALID (WKM_SOCKET_T)(-1) + #define WKM_SOCKET_IS_INVALID(s) ((WKM_SOCKET_T)(s) < 0) #endif #ifdef USE_IPV6 diff --git a/wolfkeymgr/version.h b/wolfkeymgr/version.h index 1d6bd50..40fcd8b 100644 --- a/wolfkeymgr/version.h +++ b/wolfkeymgr/version.h @@ -27,7 +27,7 @@ extern "C" { #endif -#define LIBWOLFSSL_VERSION_STRING "1.1" +#define LIBWOLFSSL_VERSION_STRING "1.2" #define LIBWOLFSSL_VERSION_HEX @HEX_VERSION@ #ifdef __cplusplus diff --git a/wolfkeymgr/wkm_utils.h b/wolfkeymgr/wkm_utils.h index 179f409..cdbb9e3 100644 --- a/wolfkeymgr/wkm_utils.h +++ b/wolfkeymgr/wkm_utils.h @@ -52,6 +52,15 @@ WOLFKM_API int wolfHexStringToByte(const char* in, word32 inSz, byte* out, word3 WOLFKM_API int wolfSigIgnore(int sig); +/* zeroize sensitive data; volatile prevents the compiler from eliding it */ +static inline void wolfKeyMgr_ForceZero(void* mem, word32 len) +{ + volatile byte* p = (volatile byte*)mem; + while (len-- > 0) { + *p++ = 0; + } +} + /* misc functions */ #if !defined(min) && !defined(WOLFSSL_HAVE_MIN) static inline int min(int a, int b)