mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1792ef29c | |||
| 0f3d063f0a | |||
| 0d7d637466 | |||
| 1ff0c8588d | |||
| b1cc8095a8 |
@@ -120,6 +120,155 @@ jobs:
|
||||
- name: build and run ThreadPool test
|
||||
run: cd test && make test_thread_pool && ./test_thread_pool
|
||||
|
||||
# BoringSSL is Google's fork of OpenSSL. It has no API stability guarantee
|
||||
# and is not packaged by distros, so we build it from source. cpp-httplib
|
||||
# treats it as an OpenSSL backend variant via the OPENSSL_IS_BORINGSSL
|
||||
# macro (see httplib.h). This job is best-effort: continue-on-error keeps
|
||||
# upstream API drift from blocking PRs while still surfacing breakage.
|
||||
ubuntu-boringssl:
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
(github.event_name == 'push') ||
|
||||
(github.event_name == 'pull_request' &&
|
||||
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
|
||||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_linux == 'true')
|
||||
continue-on-error: true
|
||||
name: ubuntu (boringssl, best-effort)
|
||||
env:
|
||||
# Tracking HEAD keeps us honest about upstream churn. If breakage
|
||||
# becomes routine, replace HEAD with a 40-char commit SHA; the
|
||||
# resolve step uses the SHA directly when it matches that shape.
|
||||
BORINGSSL_REF: HEAD
|
||||
BORINGSSL_PREFIX: ${{ github.workspace }}/boringssl-install
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: install common libraries
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libcurl4-openssl-dev zlib1g-dev libbrotli-dev libzstd-dev
|
||||
- name: resolve BoringSSL commit
|
||||
id: boringssl-rev
|
||||
# Accept either a ref name (resolved via git ls-remote) or a full
|
||||
# 40-char SHA used directly. ls-remote does not list arbitrary
|
||||
# commit SHAs, so pinning requires the second path.
|
||||
run: |
|
||||
if [[ "${BORINGSSL_REF}" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
sha="${BORINGSSL_REF}"
|
||||
echo "Using pinned BoringSSL SHA: ${sha}"
|
||||
else
|
||||
sha=$(git ls-remote https://boringssl.googlesource.com/boringssl "${BORINGSSL_REF}" | awk '{print $1}')
|
||||
if [ -z "$sha" ]; then
|
||||
echo "Failed to resolve BoringSSL ref ${BORINGSSL_REF}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Resolved ${BORINGSSL_REF} -> ${sha}"
|
||||
fi
|
||||
echo "sha=${sha}" >> "$GITHUB_OUTPUT"
|
||||
- name: cache BoringSSL build
|
||||
id: boringssl-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.BORINGSSL_PREFIX }}
|
||||
key: boringssl-${{ runner.os }}-${{ steps.boringssl-rev.outputs.sha }}
|
||||
- name: build BoringSSL
|
||||
if: steps.boringssl-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
set -e
|
||||
git clone https://boringssl.googlesource.com/boringssl boringssl
|
||||
cd boringssl
|
||||
git checkout "${{ steps.boringssl-rev.outputs.sha }}"
|
||||
cmake -S . -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX="${BORINGSSL_PREFIX}"
|
||||
cmake --build build -j"$(nproc)" --target install
|
||||
- name: build and run tests (BoringSSL)
|
||||
# Override OPENSSL_SUPPORT to point the existing OpenSSL Makefile path
|
||||
# at BoringSSL's prefix. BoringSSL defines OPENSSL_IS_BORINGSSL in
|
||||
# <openssl/base.h>, which httplib.h and test.cc use to switch on API
|
||||
# differences (e.g. SAN-only hostname verification, no CN fallback).
|
||||
#
|
||||
# BoringSSL's public headers (<openssl/stack.h>) use std::enable_if_t,
|
||||
# so consumers must compile with C++14 or later. cpp-httplib itself
|
||||
# supports C++11, but anyone pairing it with BoringSSL inherits this
|
||||
# constraint. EXTRA_CXXFLAGS appends after the Makefile's -std=c++11
|
||||
# and the later flag wins.
|
||||
run: |
|
||||
cd test
|
||||
BORINGSSL_FLAGS="-DCPPHTTPLIB_OPENSSL_SUPPORT -I${BORINGSSL_PREFIX}/include -L${BORINGSSL_PREFIX}/lib -lssl -lcrypto -lpthread"
|
||||
make test_split OPENSSL_SUPPORT="${BORINGSSL_FLAGS}" EXTRA_CXXFLAGS="-std=c++17"
|
||||
make test_openssl_parallel OPENSSL_SUPPORT="${BORINGSSL_FLAGS}" EXTRA_CXXFLAGS="-std=c++17"
|
||||
env:
|
||||
LSAN_OPTIONS: suppressions=lsan_suppressions.txt
|
||||
|
||||
# macOS counterpart of the BoringSSL job. Same best-effort posture; the
|
||||
# extra framework links cover the macOS Keychain integration that
|
||||
# httplib.h auto-enables for any TLS backend on macOS.
|
||||
macos-boringssl:
|
||||
runs-on: macos-latest
|
||||
if: >
|
||||
(github.event_name == 'push') ||
|
||||
(github.event_name == 'pull_request' &&
|
||||
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
|
||||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_macos == 'true')
|
||||
continue-on-error: true
|
||||
name: macos (boringssl, best-effort)
|
||||
env:
|
||||
BORINGSSL_REF: HEAD
|
||||
BORINGSSL_PREFIX: ${{ github.workspace }}/boringssl-install
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: resolve BoringSSL commit
|
||||
id: boringssl-rev
|
||||
# Accept either a ref name (resolved via git ls-remote) or a full
|
||||
# 40-char SHA used directly. ls-remote does not list arbitrary
|
||||
# commit SHAs, so pinning requires the second path.
|
||||
run: |
|
||||
if [[ "${BORINGSSL_REF}" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
sha="${BORINGSSL_REF}"
|
||||
echo "Using pinned BoringSSL SHA: ${sha}"
|
||||
else
|
||||
sha=$(git ls-remote https://boringssl.googlesource.com/boringssl "${BORINGSSL_REF}" | awk '{print $1}')
|
||||
if [ -z "$sha" ]; then
|
||||
echo "Failed to resolve BoringSSL ref ${BORINGSSL_REF}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Resolved ${BORINGSSL_REF} -> ${sha}"
|
||||
fi
|
||||
echo "sha=${sha}" >> "$GITHUB_OUTPUT"
|
||||
- name: cache BoringSSL build
|
||||
id: boringssl-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.BORINGSSL_PREFIX }}
|
||||
key: boringssl-${{ runner.os }}-${{ steps.boringssl-rev.outputs.sha }}
|
||||
- name: build BoringSSL
|
||||
if: steps.boringssl-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
set -e
|
||||
git clone https://boringssl.googlesource.com/boringssl boringssl
|
||||
cd boringssl
|
||||
git checkout "${{ steps.boringssl-rev.outputs.sha }}"
|
||||
cmake -S . -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX="${BORINGSSL_PREFIX}"
|
||||
cmake --build build -j"$(sysctl -n hw.ncpu)" --target install
|
||||
- name: build and run tests (BoringSSL)
|
||||
run: |
|
||||
cd test
|
||||
# CoreFoundation/Security frameworks satisfy the Keychain integration
|
||||
# auto-enabled in httplib.h for macOS TLS builds.
|
||||
BORINGSSL_FLAGS="-DCPPHTTPLIB_OPENSSL_SUPPORT -I${BORINGSSL_PREFIX}/include -L${BORINGSSL_PREFIX}/lib -lssl -lcrypto -framework CoreFoundation -framework Security"
|
||||
make test_split OPENSSL_SUPPORT="${BORINGSSL_FLAGS}" EXTRA_CXXFLAGS="-std=c++17"
|
||||
make test_openssl_parallel OPENSSL_SUPPORT="${BORINGSSL_FLAGS}" EXTRA_CXXFLAGS="-std=c++17"
|
||||
env:
|
||||
LSAN_OPTIONS: suppressions=lsan_suppressions.txt
|
||||
|
||||
# Reproducer for https://github.com/yhirose/cpp-httplib/issues/2431.
|
||||
# On Linux/glibc, getaddrinfo_with_timeout() schedules an asynchronous
|
||||
# DNS lookup with getaddrinfo_a(GAI_NOWAIT) using a stack-local gaicb.
|
||||
@@ -250,6 +399,54 @@ jobs:
|
||||
- name: build and run ThreadPool test
|
||||
run: cd test && make test_thread_pool && ./test_thread_pool
|
||||
|
||||
ios-parse-check:
|
||||
runs-on: macos-latest
|
||||
if: >
|
||||
(github.event_name == 'push') ||
|
||||
(github.event_name == 'pull_request' &&
|
||||
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
|
||||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_macos == 'true')
|
||||
name: ios header parse check (not officially supported)
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: install OpenSSL headers
|
||||
run: brew install openssl@3
|
||||
- name: verify header parses on iOS target
|
||||
run: |
|
||||
IOS_SDK=$(xcrun --sdk iphoneos --show-sdk-path)
|
||||
OPENSSL_INC=$(brew --prefix openssl@3)/include
|
||||
echo "Using iOS SDK: $IOS_SDK"
|
||||
echo '#include "httplib.h"' | clang++ \
|
||||
-isysroot "$IOS_SDK" \
|
||||
-target arm64-apple-ios16.0 \
|
||||
-std=c++11 \
|
||||
-DCPPHTTPLIB_OPENSSL_SUPPORT \
|
||||
-I"$OPENSSL_INC" \
|
||||
-I. -Wall -Wextra \
|
||||
-fsyntax-only -x c++ -
|
||||
- name: verify CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN is rejected on iOS
|
||||
run: |
|
||||
IOS_SDK=$(xcrun --sdk iphoneos --show-sdk-path)
|
||||
OPENSSL_INC=$(brew --prefix openssl@3)/include
|
||||
out=$(echo '#include "httplib.h"' | clang++ \
|
||||
-isysroot "$IOS_SDK" \
|
||||
-target arm64-apple-ios16.0 \
|
||||
-std=c++11 \
|
||||
-DCPPHTTPLIB_OPENSSL_SUPPORT \
|
||||
-DCPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN \
|
||||
-I"$OPENSSL_INC" \
|
||||
-I. \
|
||||
-fsyntax-only -x c++ - 2>&1 || true)
|
||||
if echo "$out" | grep -q "only supported on macOS"; then
|
||||
echo "OK: #error fired as expected"
|
||||
else
|
||||
echo "FAIL: expected #error did not fire"
|
||||
echo "--- compiler output ---"
|
||||
echo "$out"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
if: >
|
||||
|
||||
@@ -73,6 +73,9 @@ cpp-httplib supports multiple TLS backends through an abstraction layer:
|
||||
> [!NOTE]
|
||||
> **Mbed TLS / wolfSSL limitation:** `get_ca_certs()` and `get_ca_names()` only reflect CA certificates loaded via `load_ca_cert_store()`. Certificates loaded through `set_ca_cert_path()` or system certificates (`load_system_certs`) are not enumerable.
|
||||
|
||||
> [!NOTE]
|
||||
> **BoringSSL (best-effort):** BoringSSL builds under `CPPHTTPLIB_OPENSSL_SUPPORT` and is exercised by CI against current upstream. Because BoringSSL does not guarantee API stability, support is best-effort — breakage may occasionally land. Two known behavioral differences vs OpenSSL: (1) BoringSSL's public headers require C++14 or later, so consumers must compile accordingly; (2) hostname verification is SAN-only per RFC 6125 §6.4.4 (no CN fallback).
|
||||
|
||||
```c++
|
||||
// Use either OpenSSL, Mbed TLS, or wolfSSL
|
||||
#define CPPHTTPLIB_OPENSSL_SUPPORT // or CPPHTTPLIB_MBEDTLS_SUPPORT or CPPHTTPLIB_WOLFSSL_SUPPORT
|
||||
|
||||
@@ -61,7 +61,7 @@ if(@HTTPLIB_IS_USING_ZSTD@)
|
||||
if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
|
||||
set(httplib_fd_zstd_required_arg REQUIRED)
|
||||
endif()
|
||||
find_package(zstd QUIET)
|
||||
find_package(zstd 1.5.6 CONFIG QUIET)
|
||||
if(NOT zstd_FOUND)
|
||||
find_package(PkgConfig ${httplib_fd_zstd_quiet_arg} ${httplib_fd_zstd_required_arg})
|
||||
if(PKG_CONFIG_FOUND)
|
||||
|
||||
@@ -4,7 +4,7 @@ langs = ["en", "ja"]
|
||||
|
||||
[site]
|
||||
title = "cpp-httplib"
|
||||
version = "0.45.0"
|
||||
version = "0.45.1"
|
||||
hostname = "https://yhirose.github.io"
|
||||
base_path = "/cpp-httplib"
|
||||
footer_message = "© 2026 Yuji Hirose. All rights reserved."
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||
#define CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
#define CPPHTTPLIB_VERSION "0.45.0"
|
||||
#define CPPHTTPLIB_VERSION_NUM "0x002d00"
|
||||
#define CPPHTTPLIB_VERSION "0.45.1"
|
||||
#define CPPHTTPLIB_VERSION_NUM "0x002d01"
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00
|
||||
@@ -339,16 +339,26 @@ using socket_t = int;
|
||||
#include <utility>
|
||||
|
||||
// On macOS with a TLS backend, enable Keychain root certificates by default
|
||||
// unless the user explicitly opts out.
|
||||
// unless the user explicitly opts out. Not enabled on iOS/tvOS/watchOS since
|
||||
// the SecTrustSettings APIs used to enumerate anchor certificates are macOS
|
||||
// only; on those platforms the user must provide a CA bundle explicitly.
|
||||
#if defined(__APPLE__) && defined(__clang__) && \
|
||||
!defined(CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES) && \
|
||||
(defined(CPPHTTPLIB_OPENSSL_SUPPORT) || \
|
||||
defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || \
|
||||
defined(CPPHTTPLIB_WOLFSSL_SUPPORT))
|
||||
#if TARGET_OS_OSX
|
||||
#ifndef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
||||
#define CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \
|
||||
defined(__APPLE__) && !TARGET_OS_OSX
|
||||
#error \
|
||||
"CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN is only supported on macOS. On iOS/tvOS/watchOS, supply a CA bundle via set_ca_cert_path()."
|
||||
#endif
|
||||
|
||||
// On Windows, enable Schannel certificate verification by default
|
||||
// unless the user explicitly opts out.
|
||||
@@ -382,7 +392,7 @@ using socket_t = int;
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
||||
#if TARGET_OS_MAC
|
||||
#if TARGET_OS_OSX
|
||||
#include <Security/Security.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -430,7 +440,7 @@ using socket_t = int;
|
||||
#endif
|
||||
#endif // _WIN32
|
||||
#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
||||
#if TARGET_OS_MAC
|
||||
#if TARGET_OS_OSX
|
||||
#include <Security/Security.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -473,7 +483,7 @@ using socket_t = int;
|
||||
#endif
|
||||
#endif // _WIN32
|
||||
#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
|
||||
#if TARGET_OS_MAC
|
||||
#if TARGET_OS_OSX
|
||||
#include <Security/Security.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -1597,7 +1607,7 @@ private:
|
||||
std::regex regex_;
|
||||
};
|
||||
|
||||
int close_socket(socket_t sock);
|
||||
int close_socket(socket_t sock) noexcept;
|
||||
|
||||
ssize_t write_headers(Stream &strm, const Headers &headers);
|
||||
|
||||
@@ -1734,7 +1744,7 @@ public:
|
||||
|
||||
bool is_running() const;
|
||||
void wait_until_ready() const;
|
||||
void stop();
|
||||
void stop() noexcept;
|
||||
void decommission();
|
||||
|
||||
std::function<TaskQueue *(void)> new_task_queue;
|
||||
@@ -3028,8 +3038,6 @@ bool parse_range_header(const std::string &s, Ranges &ranges);
|
||||
bool parse_accept_header(const std::string &s,
|
||||
std::vector<std::string> &content_types);
|
||||
|
||||
int close_socket(socket_t sock);
|
||||
|
||||
ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags);
|
||||
|
||||
ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags);
|
||||
@@ -5422,7 +5430,7 @@ inline void mmap::close() {
|
||||
#endif
|
||||
size_ = 0;
|
||||
}
|
||||
inline int close_socket(socket_t sock) {
|
||||
inline int close_socket(socket_t sock) noexcept {
|
||||
#ifdef _WIN32
|
||||
return closesocket(sock);
|
||||
#else
|
||||
@@ -5649,7 +5657,7 @@ inline bool process_client_socket(
|
||||
return callback(strm);
|
||||
}
|
||||
|
||||
inline int shutdown_socket(socket_t sock) {
|
||||
inline int shutdown_socket(socket_t sock) noexcept {
|
||||
#ifdef _WIN32
|
||||
return shutdown(sock, SD_BOTH);
|
||||
#else
|
||||
@@ -11004,7 +11012,7 @@ inline void Server::wait_until_ready() const {
|
||||
}
|
||||
}
|
||||
|
||||
inline void Server::stop() {
|
||||
inline void Server::stop() noexcept {
|
||||
if (is_running_) {
|
||||
assert(svr_sock_ != INVALID_SOCKET);
|
||||
std::atomic<socket_t> sock(svr_sock_.exchange(INVALID_SOCKET));
|
||||
@@ -16145,9 +16153,18 @@ inline bool enumerate_windows_system_certs(Callback cb) {
|
||||
template <typename Callback>
|
||||
inline bool enumerate_macos_keychain_certs(Callback cb) {
|
||||
bool loaded = false;
|
||||
CFArrayRef certs = nullptr;
|
||||
OSStatus status = SecTrustCopyAnchorCertificates(&certs);
|
||||
if (status == errSecSuccess && certs) {
|
||||
const SecTrustSettingsDomain domains[] = {
|
||||
kSecTrustSettingsDomainSystem,
|
||||
kSecTrustSettingsDomainAdmin,
|
||||
kSecTrustSettingsDomainUser,
|
||||
};
|
||||
for (auto domain : domains) {
|
||||
CFArrayRef certs = nullptr;
|
||||
OSStatus status = SecTrustSettingsCopyCertificates(domain, &certs);
|
||||
if (status != errSecSuccess || !certs) {
|
||||
if (certs) CFRelease(certs);
|
||||
continue;
|
||||
}
|
||||
CFIndex count = CFArrayGetCount(certs);
|
||||
for (CFIndex i = 0; i < count; i++) {
|
||||
SecCertificateRef cert =
|
||||
@@ -16510,28 +16527,36 @@ inline bool load_system_certs(ctx_t ctx) {
|
||||
auto store = SSL_CTX_get_cert_store(ssl_ctx);
|
||||
if (!store) return false;
|
||||
|
||||
CFArrayRef certs = nullptr;
|
||||
if (SecTrustCopyAnchorCertificates(&certs) != errSecSuccess || !certs) {
|
||||
return SSL_CTX_set_default_verify_paths(ssl_ctx) == 1;
|
||||
}
|
||||
|
||||
bool loaded_any = false;
|
||||
auto count = CFArrayGetCount(certs);
|
||||
for (CFIndex i = 0; i < count; i++) {
|
||||
auto cert = reinterpret_cast<SecCertificateRef>(
|
||||
const_cast<void *>(CFArrayGetValueAtIndex(certs, i)));
|
||||
CFDataRef der = SecCertificateCopyData(cert);
|
||||
if (der) {
|
||||
const unsigned char *data = CFDataGetBytePtr(der);
|
||||
auto x509 = d2i_X509(nullptr, &data, CFDataGetLength(der));
|
||||
if (x509) {
|
||||
if (X509_STORE_add_cert(store, x509) == 1) { loaded_any = true; }
|
||||
X509_free(x509);
|
||||
}
|
||||
CFRelease(der);
|
||||
const SecTrustSettingsDomain domains[] = {
|
||||
kSecTrustSettingsDomainSystem,
|
||||
kSecTrustSettingsDomainAdmin,
|
||||
kSecTrustSettingsDomainUser,
|
||||
};
|
||||
for (auto domain : domains) {
|
||||
CFArrayRef certs = nullptr;
|
||||
if (SecTrustSettingsCopyCertificates(domain, &certs) != errSecSuccess ||
|
||||
!certs) {
|
||||
if (certs) CFRelease(certs);
|
||||
continue;
|
||||
}
|
||||
auto count = CFArrayGetCount(certs);
|
||||
for (CFIndex i = 0; i < count; i++) {
|
||||
auto cert = reinterpret_cast<SecCertificateRef>(
|
||||
const_cast<void *>(CFArrayGetValueAtIndex(certs, i)));
|
||||
CFDataRef der = SecCertificateCopyData(cert);
|
||||
if (der) {
|
||||
const unsigned char *data = CFDataGetBytePtr(der);
|
||||
auto x509 = d2i_X509(nullptr, &data, CFDataGetLength(der));
|
||||
if (x509) {
|
||||
if (X509_STORE_add_cert(store, x509) == 1) { loaded_any = true; }
|
||||
X509_free(x509);
|
||||
}
|
||||
CFRelease(der);
|
||||
}
|
||||
}
|
||||
CFRelease(certs);
|
||||
}
|
||||
CFRelease(certs);
|
||||
return loaded_any || SSL_CTX_set_default_verify_paths(ssl_ctx) == 1;
|
||||
#else
|
||||
return SSL_CTX_set_default_verify_paths(ssl_ctx) == 1;
|
||||
|
||||
@@ -10673,8 +10673,20 @@ TEST(SSLClientServerTest, TlsVerifyHostname) {
|
||||
<< "Verify callback should have been called";
|
||||
|
||||
// CN="Common Name" should match our test certificate
|
||||
//
|
||||
// BoringSSL intentionally drops CN-based hostname matching per RFC 6125
|
||||
// §6.4.4 — only SubjectAltName is consulted. Other backends (OpenSSL,
|
||||
// MbedTLS, wolfSSL) still honor the CN fallback, so flip the expectation
|
||||
// for BoringSSL builds. OPENSSL_IS_BORINGSSL is defined by BoringSSL's
|
||||
// <openssl/base.h>, which is included transitively when
|
||||
// CPPHTTPLIB_OPENSSL_SUPPORT is set against a BoringSSL install.
|
||||
#if defined(OPENSSL_IS_BORINGSSL)
|
||||
EXPECT_FALSE(verify_result_cn)
|
||||
<< "BoringSSL should reject CN-based hostname matching (SAN-only)";
|
||||
#else
|
||||
EXPECT_TRUE(verify_result_cn)
|
||||
<< "verify_hostname should match 'Common Name' (certificate CN)";
|
||||
#endif
|
||||
|
||||
// Wrong hostname should not match
|
||||
EXPECT_FALSE(verify_result_wrong)
|
||||
|
||||
Reference in New Issue
Block a user