diff --git a/.github/workflows/aws-lc-rs.yml b/.github/workflows/aws-lc-rs.yml index 37f6c015759..37b1fa6809d 100644 --- a/.github/workflows/aws-lc-rs.yml +++ b/.github/workflows/aws-lc-rs.yml @@ -88,3 +88,181 @@ jobs: if: runner.os != 'Windows' working-directory: ./aws-lc-rs run: ./scripts/build/collect_build_src.sh + + # CMake Rust bindings generation tests + cmake-rust-bindings: + if: github.repository_owner == 'aws' + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + name: linux + - os: ubuntu-latest + name: linux-prefix + prefix: AWSLC_PREFIX + - os: macos-latest + name: macos + - os: macos-latest + name: macos-prefix + prefix: AWSLC_PREFIX + - os: windows-latest + name: windows + - os: ubuntu-latest + name: linux-no-ssl + build_libssl: OFF + runs-on: ${{ matrix.os }} + name: cmake-rust-bindings (${{ matrix.name }}) + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: 'rustfmt' + - uses: ilammy/setup-nasm@v1 + if: runner.os == 'Windows' + - uses: actions/setup-go@v4 + with: + go-version: '>=1.20' + - name: Install bindgen-cli + run: cargo install --force --locked bindgen-cli + + # Prefix builds need a non-prefixed build first to collect symbols + - name: Generate prefix symbols file + if: matrix.prefix + shell: bash + run: | + cmake -B build-noprefix -DBUILD_TESTING=OFF + cmake --build build-noprefix + go run ./util/read_symbols.go build-noprefix/crypto/libcrypto.a > symbols.txt + go run ./util/read_symbols.go build-noprefix/ssl/libssl.a >> symbols.txt + echo "Collected $(wc -l < symbols.txt) symbols" + + - name: Configure with Rust bindings generation + shell: bash + run: | + cmake_args="-DGENERATE_RUST_BINDINGS=ON -DBUILD_TESTING=OFF" + if [ -n "${{ matrix.prefix }}" ]; then + cmake_args="$cmake_args -DBORINGSSL_PREFIX=${{ matrix.prefix }}" + cmake_args="$cmake_args -DBORINGSSL_PREFIX_SYMBOLS=$(pwd)/symbols.txt" + fi + if [ "${{ matrix.build_libssl }}" = "OFF" ]; then + cmake_args="$cmake_args -DBUILD_LIBSSL=OFF" + fi + cmake -B build $cmake_args + + - name: Build libraries + run: cmake --build build --config Release + + - name: Generate bindings + run: cmake --build build --target rust_bindings --config Release --verbose + + - name: Verify bindings file exists + shell: bash + run: | + if [ ! -f build/rust/aws_lc_bindings.rs ]; then + echo "ERROR: Rust bindings file was not generated" + exit 1 + fi + echo "Generated bindings file size: $(wc -c < build/rust/aws_lc_bindings.rs) bytes" + echo "Generated bindings line count: $(wc -l < build/rust/aws_lc_bindings.rs) lines" + + - name: Verify bindings content + shell: bash + run: | + # Verify SSL bindings based on BUILD_LIBSSL setting (defaults to ON) + if [ "${{ matrix.build_libssl }}" != "OFF" ]; then + if ! grep -q "pub fn SSL_new" build/rust/aws_lc_bindings.rs; then + echo "ERROR: Expected SSL_new function not found" + exit 1 + fi + else + if grep -q "pub fn SSL_new" build/rust/aws_lc_bindings.rs; then + echo "ERROR: Unexpected SSL_new found in BUILD_LIBSSL=OFF build" + exit 1 + fi + echo "Confirmed: SSL bindings correctly excluded" + fi + if [ -n "${{ matrix.prefix }}" ]; then + # Prefix builds: link_name attributes should contain the prefix. + # The exact format varies by platform (e.g., _PREFIX_ on macOS vs PREFIX_ on Linux). + if ! grep -q 'link_name.*${{ matrix.prefix }}_' build/rust/aws_lc_bindings.rs; then + echo "ERROR: Expected prefixed link_name attributes not found" + exit 1 + fi + if ! grep -B1 "pub fn SSL_new" build/rust/aws_lc_bindings.rs | grep -q 'link_name.*${{ matrix.prefix }}_'; then + echo "ERROR: SSL_new should have ${{ matrix.prefix }}_ prefixed link_name" + exit 1 + fi + else + # Non-prefix builds should not have link_name attributes + if grep -q '#\[link_name' build/rust/aws_lc_bindings.rs; then + echo "ERROR: Unexpected link_name attributes found in no-prefix build" + exit 1 + fi + fi + echo "Bindings content verification passed" + + + - name: Verify bindings build and link + shell: bash + run: | + mkdir -p "${RUNNER_TEMP}/test-bindings/src" + cat > "${RUNNER_TEMP}/test-bindings/Cargo.toml" << 'EOF' + [package] + name = "test-bindings" + version = "0.1.0" + edition = "2021" + + [[bin]] + name = "test-bindings" + path = "src/main.rs" + EOF + cat > "${RUNNER_TEMP}/test-bindings/build.rs" << 'EOF' + use std::env; + fn main() { + let build_dir = env::var("CMAKE_BUILD_DIR").expect("CMAKE_BUILD_DIR must be set"); + // Library search paths for single-config generators (Unix Makefiles, Ninja) + println!("cargo:rustc-link-search=native={}/crypto", build_dir); + println!("cargo:rustc-link-search=native={}/ssl", build_dir); + // Library search paths for multi-config generators (Visual Studio) + println!("cargo:rustc-link-search=native={}/crypto/Release", build_dir); + println!("cargo:rustc-link-search=native={}/ssl/Release", build_dir); + println!("cargo:rustc-link-lib=static=crypto"); + if env::var("INCLUDE_SSL").unwrap_or_default() == "1" { + println!("cargo:rustc-link-lib=static=ssl"); + } + // Platform-specific system library dependencies required by aws-lc + let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap_or_default(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + if target_family == "unix" { + println!("cargo:rustc-link-lib=dylib=pthread"); + } + if target_os == "windows" { + println!("cargo:rustc-link-lib=dylib=ws2_32"); + } + } + EOF + cat > "${RUNNER_TEMP}/test-bindings/src/main.rs" << 'EOF' + #![allow(clippy::all)] + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] + #![allow(dead_code)] + #![allow(improper_ctypes)] + #![allow(unpredictable_function_pointer_comparisons)] + include!(concat!(env!("BINDINGS_PATH"), "/aws_lc_bindings.rs")); + fn main() { + unsafe { CRYPTO_library_init(); } + println!("Bindings link test passed"); + } + EOF + cd "${RUNNER_TEMP}/test-bindings" + include_ssl="0" + if [ "${{ matrix.build_libssl }}" != "OFF" ]; then + include_ssl="1" + fi + export CMAKE_BUILD_DIR="${GITHUB_WORKSPACE}/build" + export BINDINGS_PATH="${GITHUB_WORKSPACE}/build/rust" + export INCLUDE_SSL="${include_ssl}" + cargo run + echo "Bindings build, link, and run test passed" diff --git a/CMakeLists.txt b/CMakeLists.txt index a63e259d302..78e7b1345a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,9 @@ option(ENABLE_FIPS_ENTROPY_CPU_JITTER "Enable FIPS entropy source: CPU Jitter" O option(ENABLE_DATA_INDEPENDENT_TIMING "Enable automatic setting/resetting Data-Independent Timing (DIT) flag in cryptographic functions. Currently only applicable to Arm64 (except on Windows)" OFF) option(ENABLE_PRE_SONAME_BUILD "Build AWS-LC without SONAME configuration for shared library builds" ON) +option(GENERATE_RUST_BINDINGS "Generate Rust bindings using bindgen-cli" OFF) +set(RUST_BINDINGS_TARGET_VERSION "1.70" CACHE STRING "Minimum Rust version for generated bindings") + include(cmake/go.cmake) if(NOT ENABLE_PRE_SONAME_BUILD AND BUILD_SHARED_LIBS AND UNIX AND NOT APPLE) @@ -113,6 +116,60 @@ enable_language(C) # Entropy by default; because it's the root of the Tree DRBG. message(STATUS "Entropy source configured: Dynamic (default: CPU Jitter)") +# Validate Rust bindings prerequisites +if(GENERATE_RUST_BINDINGS) + find_program(BINDGEN_EXECUTABLE NAMES bindgen) + if(NOT BINDGEN_EXECUTABLE) + message(FATAL_ERROR "GENERATE_RUST_BINDINGS is enabled but bindgen-cli was not found. " + "Install it with: cargo install --force --locked bindgen-cli") + endif() + + # Verify minimum version (0.69.5) + execute_process( + COMMAND ${BINDGEN_EXECUTABLE} --version + OUTPUT_VARIABLE BINDGEN_VERSION_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE BINDGEN_VERSION_RESULT + ) + + if(NOT BINDGEN_VERSION_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to get bindgen version") + endif() + + # Extract version number (format: "bindgen X.Y.Z") + string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" BINDGEN_VERSION "${BINDGEN_VERSION_OUTPUT}") + + if(BINDGEN_VERSION VERSION_LESS "0.69.5") + message(FATAL_ERROR "bindgen version ${BINDGEN_VERSION} is too old. " + "Minimum required version is 0.69.5. " + "Upgrade with: cargo install --force --locked bindgen-cli") + endif() + + message(STATUS "Found bindgen-cli: ${BINDGEN_EXECUTABLE} (version ${BINDGEN_VERSION})") + message(STATUS "Rust bindings target version: ${RUST_BINDINGS_TARGET_VERSION}") + + # Check for rustfmt (required for --formatter rustfmt option) + find_program(RUSTFMT_EXECUTABLE NAMES rustfmt) + if(NOT RUSTFMT_EXECUTABLE) + message(FATAL_ERROR "GENERATE_RUST_BINDINGS requires rustfmt but it was not found. " + "Install it with: rustup component add rustfmt") + endif() + message(STATUS "Found rustfmt: ${RUSTFMT_EXECUTABLE}") +endif() + +if(DISABLE_CPU_JITTER_ENTROPY) + if(FIPS) + message(FATAL_ERROR "Cannot opt-out of CPU Jitter for the FIPS build") + endif() + add_definitions(-DDISABLE_CPU_JITTER_ENTROPY) + message(STATUS "Entropy source configuration: CPU Jitter opt-out") + message(STATUS "Entropy source configured: Dynamic (default: Operating system)") +else() + # The validated entropy source will always be configured to be CPU Jitter + # Entropy by default; because it's the root of the Tree DRBG. + message(STATUS "Entropy source configured: Dynamic (default: CPU Jitter)") +endif() + if(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") # OpenBSD by defaults links with --execute-only this is problematic for two reasons: # 1. The FIPS shared and static builds need to compute the module signature hash by reading the .text section @@ -347,6 +404,60 @@ else() ) endif() +# Rust bindings generation +if(GENERATE_RUST_BINDINGS) + include(cmake/rust_bindings.cmake) + + # Generate the rust_wrapper.h header from template + generate_rust_wrapper_header() + + set(RUST_BINDINGS_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/rust/aws_lc_bindings.rs") + + # Build list of include directories for bindgen. + # Prefix symbols header is intentionally excluded; see cmake/rust_bindings.cmake. + set(RUST_BINDINGS_INCLUDE_DIRS + "${CMAKE_CURRENT_BINARY_DIR}/include" # Generated rust_wrapper.h location + "${AWSLC_SOURCE_DIR}/include" # Main AWS-LC headers (unprefixed) + ) + + # Conditionally set optional arguments for generate_rust_bindings + if(BORINGSSL_PREFIX) + set(_rust_prefix_arg PREFIX "${BORINGSSL_PREFIX}") + else() + set(_rust_prefix_arg "") + endif() + + if(BUILD_LIBSSL) + set(_rust_ssl_arg INCLUDE_SSL) + else() + set(_rust_ssl_arg "") + endif() + + generate_rust_bindings( + OUTPUT_FILE "${RUST_BINDINGS_OUTPUT}" + INCLUDE_DIRS ${RUST_BINDINGS_INCLUDE_DIRS} + ${_rust_prefix_arg} + ${_rust_ssl_arg} + ) + + # Install the generated Rust bindings. + # The rust_bindings target is not part of ALL, so we build it on-demand during install. + install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_BINARY_DIR}\" --target rust_bindings)") + + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/rust/aws_lc_bindings.rs" + DESTINATION "share/rust" + COMPONENT Development + ) + + # Install the generated rust_wrapper.h header + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/include/rust_wrapper.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + COMPONENT Development + ) +endif() + if("${CMAKE_SYSTEM_NAME}" STREQUAL "Emscripten") set(EMSCRIPTEN 1) diff --git a/cmake/rust_bindings.cmake b/cmake/rust_bindings.cmake new file mode 100644 index 00000000000..583130cb653 --- /dev/null +++ b/cmake/rust_bindings.cmake @@ -0,0 +1,224 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 OR ISC + +# Module for generating Rust bindings using bindgen-cli +# +# Background: Symbol Prefix Mechanism +# ------------------------------------ +# AWS-LC supports building with a symbol prefix (via BORINGSSL_PREFIX) to avoid +# symbol collisions when multiple copies of the library are linked into one binary. +# The C build achieves this by generating a boringssl_prefix_symbols.h header that +# #define-renames every public symbol (e.g., #define SSL_new AWSLC_SSL_new), then +# force-including it during compilation. +# +# For Rust bindings, we must NOT include that prefix header when invoking bindgen. +# Instead, we use bindgen's --prefix-link-name option, which adds the prefix to +# #[link_name] attributes (for the linker) while keeping the Rust function names +# unprefixed. If we included the prefix header, bindgen would see already-prefixed +# names and --prefix-link-name would double-prefix them, producing broken bindings. +# +# This produces bindings like: +# extern "C" { +# #[link_name = "AWSLC_SSL_new"] // Prefixed for linker +# pub fn SSL_new(...) -> ...; // Unprefixed for Rust API +# } + +# Headers to exclude from Rust bindings generation. +# Each exclusion should have a comment explaining why. +set(RUST_WRAPPER_EXCLUDED_HEADERS + # Template files (not actual headers, used by configure_file) + "base.h.in" + "opensslv.h.in" + + # Prefix symbol headers must not be included. See module-level comment above. + "boringssl_prefix_symbols.h" + "boringssl_prefix_symbols_asm.h" + "boringssl_prefix_symbols_nasm.inc" + + # Platform/architecture-specific internal headers (not part of public API) + "arm_arch.h" + "asm_base.h" + "target.h" + + # SSL headers (conditionally included via AWS_LC_RUST_INCLUDE_SSL define) + "ssl.h" + "ssl3.h" + "tls1.h" + "dtls1.h" +) + +# Discover all OpenSSL headers for dependency tracking +# Uses CONFIGURE_DEPENDS on CMake 3.12+ for automatic reconfiguration +function(discover_openssl_headers OUT_VAR OUT_EXPERIMENTAL_VAR) + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12") + file(GLOB _all_headers + CONFIGURE_DEPENDS + "${AWSLC_SOURCE_DIR}/include/openssl/*.h") + file(GLOB _experimental_headers + CONFIGURE_DEPENDS + "${AWSLC_SOURCE_DIR}/include/openssl/experimental/*.h") + else() + file(GLOB _all_headers "${AWSLC_SOURCE_DIR}/include/openssl/*.h") + file(GLOB _experimental_headers "${AWSLC_SOURCE_DIR}/include/openssl/experimental/*.h") + endif() + + set(${OUT_VAR} "${_all_headers}" PARENT_SCOPE) + set(${OUT_EXPERIMENTAL_VAR} "${_experimental_headers}" PARENT_SCOPE) +endfunction() + +# Generate rust_wrapper.h from template by discovering headers +function(generate_rust_wrapper_header) + discover_openssl_headers(_all_headers _experimental_headers) + + # Build the include list, filtering out excluded headers + set(_includes "") + foreach(_header ${_all_headers}) + get_filename_component(_header_name "${_header}" NAME) + list(FIND RUST_WRAPPER_EXCLUDED_HEADERS "${_header_name}" _excluded_idx) + if(_excluded_idx EQUAL -1) + string(APPEND _includes "#include \n") + endif() + endforeach() + + # Build the experimental include list + set(_experimental_includes "") + foreach(_header ${_experimental_headers}) + get_filename_component(_header_name "${_header}" NAME) + string(APPEND _experimental_includes "#include \n") + endforeach() + + # Set variables for configure_file substitution + set(RUST_WRAPPER_INCLUDES "${_includes}") + set(RUST_WRAPPER_EXPERIMENTAL_INCLUDES "${_experimental_includes}") + + # Generate the header from template + configure_file( + "${AWSLC_SOURCE_DIR}/cmake/rust_wrapper.h.in" + "${AWSLC_BINARY_DIR}/include/rust_wrapper.h" + @ONLY + ) + + message(STATUS "Generated rust_wrapper.h with discovered headers") +endfunction() + +# Determine the symbol prefix format based on target platform +# +# Different platforms have different symbol naming conventions: +# - Apple platforms (macOS, iOS): Symbols have a leading underscore (_SSL_new) +# - 32-bit Windows: Symbols have a leading underscore (_SSL_new) +# - Other platforms (Linux, 64-bit Windows): No leading underscore (SSL_new) +# +# When we add our prefix, we need to account for this: +# - Apple/Win32: _AWSLC_SSL_new (prefix goes after the leading underscore) +# - Others: AWSLC_SSL_new +# +# The --prefix-link-name option prepends the given string to link names, +# so we format it appropriately for each platform. +function(get_symbol_prefix_format PREFIX OUT_VAR) + # Use CMAKE_SYSTEM_NAME for cross-compilation support + # (WIN32/APPLE variables reflect the HOST, not the TARGET) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS") + set(${OUT_VAR} "_${PREFIX}_" PARENT_SCOPE) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND CMAKE_SIZEOF_VOID_P EQUAL 4) + set(${OUT_VAR} "_${PREFIX}_" PARENT_SCOPE) + else() + set(${OUT_VAR} "${PREFIX}_" PARENT_SCOPE) + endif() +endfunction() + +# Generate Rust bindings using bindgen-cli +# +# Arguments: +# OUTPUT_FILE - Path where the generated .rs file will be written +# INCLUDE_DIRS - List of include directories for clang +# PREFIX - (Optional) Symbol prefix (e.g., "AWSLC") +# INCLUDE_SSL - (Optional) Flag to include SSL headers +function(generate_rust_bindings) + set(options INCLUDE_SSL) + set(oneValueArgs OUTPUT_FILE PREFIX) + set(multiValueArgs INCLUDE_DIRS) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Discover headers for dependency tracking + discover_openssl_headers(_all_openssl_headers _experimental_headers) + + # Build include path arguments for clang + set(_clang_include_args "") + foreach(_dir ${ARG_INCLUDE_DIRS}) + list(APPEND _clang_include_args "-I${_dir}") + endforeach() + + # Build bindgen arguments (based on aws-lc-rs/aws-lc-sys configuration) + # + # Note on regex escaping for --allowlist-file: + # - CMake requires \\ to represent a single backslash in strings + # - The regex itself needs \\ to match a literal backslash (for Windows paths) + # - Combined: \\\\ in CMake -> \\ passed to bindgen -> \\ in regex -> matches one backslash + # - The pattern matches paths like: .../openssl/ssl.h or ...\openssl\ssl.h + set(_bindgen_args + "--allowlist-file" ".*(/|\\\\)openssl((/|\\\\)[^/\\\\]+)+\\.h" + "--allowlist-file" ".*(/|\\\\)rust_wrapper\\.h" + "--rustified-enum" "point_conversion_form_t" + "--default-macro-constant-type" "signed" + "--with-derive-default" + "--with-derive-partialeq" + "--with-derive-eq" + "--generate" "functions,types,vars,methods,constructors,destructors" + "--rust-target" "${RUST_BINDINGS_TARGET_VERSION}" + "--formatter" "rustfmt" + ) + # Add symbol prefix if specified. See module-level comment for why we use + # --prefix-link-name instead of including the prefix symbols header. + if(ARG_PREFIX AND NOT ARG_PREFIX STREQUAL "") + get_symbol_prefix_format("${ARG_PREFIX}" _sym_prefix) + list(APPEND _bindgen_args "--prefix-link-name" "${_sym_prefix}") + message(STATUS "Rust bindings will use symbol prefix: ${_sym_prefix}") + endif() + + # Build clang arguments (prefix symbols header is intentionally excluded) + set(_clang_args "") + + # Add SSL support if requested + if(ARG_INCLUDE_SSL) + list(APPEND _clang_args "-DAWS_LC_RUST_INCLUDE_SSL") + message(STATUS "Rust bindings: SSL support enabled (INCLUDE_SSL=ON)") + else() + message(STATUS "Rust bindings: SSL support disabled (INCLUDE_SSL not set)") + endif() + + # Add include paths (unprefixed headers only) + list(APPEND _clang_args ${_clang_include_args}) + + # Ensure output directory exists + get_filename_component(_output_dir "${ARG_OUTPUT_FILE}" DIRECTORY) + + message(STATUS "Rust bindings clang args: ${_clang_args}") + message(STATUS "Rust bindings bindgen args: ${_bindgen_args}") + + # Create custom command for generating bindings + # Dependencies include all OpenSSL headers to ensure regeneration when headers change + # + # Note: VERBATIM is used to ensure proper argument escaping across platforms, + # especially important for the regex patterns on Windows. If debugging command-line + # issues, be aware that VERBATIM affects how CMake quotes arguments. + add_custom_command( + OUTPUT "${ARG_OUTPUT_FILE}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${_output_dir}" + COMMAND ${BINDGEN_EXECUTABLE} + ${_bindgen_args} + "${AWSLC_BINARY_DIR}/include/rust_wrapper.h" + "--output" "${ARG_OUTPUT_FILE}" + "--" + ${_clang_args} + DEPENDS + "${AWSLC_BINARY_DIR}/include/rust_wrapper.h" + "${AWSLC_SOURCE_DIR}/cmake/rust_wrapper.h.in" + ${_all_openssl_headers} + ${_experimental_headers} + COMMENT "Generating Rust bindings with bindgen-cli" + VERBATIM + ) + + # Create target for bindings generation (not part of ALL; built on-demand or via install) + add_custom_target(rust_bindings DEPENDS "${ARG_OUTPUT_FILE}") +endfunction() diff --git a/cmake/rust_wrapper.h.in b/cmake/rust_wrapper.h.in new file mode 100644 index 00000000000..92636eeb054 --- /dev/null +++ b/cmake/rust_wrapper.h.in @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +// AUTO-GENERATED FILE - DO NOT EDIT DIRECTLY +// Generated by CMake from cmake/rust_wrapper.h.in +// To modify the header list, update RUST_WRAPPER_EXCLUDED_HEADERS in cmake/rust_bindings.cmake + +#ifndef OPENSSL_HEADER_RUST_WRAPPER_H +#define OPENSSL_HEADER_RUST_WRAPPER_H + +// Core OpenSSL headers (auto-discovered) +@RUST_WRAPPER_INCLUDES@ + +// Experimental headers +@RUST_WRAPPER_EXPERIMENTAL_INCLUDES@ + +// SSL headers (conditionally included) +#if defined(AWS_LC_RUST_INCLUDE_SSL) +#include +#include +#include +#include +#endif + +#endif // OPENSSL_HEADER_RUST_WRAPPER_H