Unverified Commit dde9ffb3 authored by Alex Gaynor's avatar Alex Gaynor Committed by GitHub
Browse files

Merge pull request #1805 from skmcgrail/aws-lc-support-final

Add support for AWS-LC to openssl and openssl-sys crates
parents a5419bc0 71a9ac91
Loading
Loading
Loading
Loading
+36 −5
Original line number Diff line number Diff line
@@ -151,6 +151,10 @@ jobs:
            - true
            - false
          library:
            - name: aws-lc
              version: v1.48.2
            - name: aws-lc
              version: vendored
            - name: boringssl
              version: e23fe9b6eecc10e4f9ea1f0027fea5eaee7bd6b6
            - name: openssl
@@ -276,18 +280,25 @@ jobs:
              url="https://boringssl.googlesource.com/boringssl/+archive/${{ matrix.library.version }}.tar.gz"
              tar_flags=""
              ;;
            "aws-lc")
              url="https://github.com/aws/aws-lc/archive/refs/tags/${{ matrix.library.version }}.tar.gz"
              tar_flags="--strip-components=1"
              ;;
            esac

            case "${{ matrix.target}}" in
            "x86_64-unknown-linux-gnu")
              CPU=x86_64
              OS_COMPILER=linux-x86_64
              OS_FLAGS=""
              ;;
            "i686-unknown-linux-gnu")
              CPU=i686
              OS_COMPILER=linux-elf
              OS_FLAGS="-m32 -msse2"
              ;;
            "arm-unknown-linux-gnueabihf")
              CPU=armv4
              OS_COMPILER=linux-armv4
              OS_FLAGS=""
              export AR=arm-linux-gnueabihf-ar
@@ -317,7 +328,7 @@ jobs:
              cd build

              echo "set(CMAKE_SYSTEM_NAME Linux)" > toolchain.cmake
              echo "set(CMAKE_SYSTEM_PROCESSOR $cpu)" >> toolchain.cmake
              echo "set(CMAKE_SYSTEM_PROCESSOR $CPU)" >> toolchain.cmake
              echo "set(triple ${{ matrix.target }})" >> toolchain.cmake
              echo 'set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} '$OS_FLAGS '" CACHE STRING "c++ flags")' >> toolchain.cmake
              echo 'set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   '$OS_FLAGS '" CACHE STRING "c flags")' >> toolchain.cmake
@@ -330,6 +341,22 @@ jobs:
              # Copy stuff around so it's all as the build system expects.
              cp -r ../rust/ "$OPENSSL_DIR/rust"
              cp -r ./ "$OPENSSL_DIR/build"
              ;;
            "aws-lc")
              mkdir build
              cd build

              echo "set(CMAKE_SYSTEM_NAME Linux)" > toolchain.cmake
              echo "set(CMAKE_SYSTEM_PROCESSOR $CPU)" >> toolchain.cmake
              echo "set(triple ${{ matrix.target }})" >> toolchain.cmake
              echo 'set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} '$OS_FLAGS '" CACHE STRING "c++ flags")' >> toolchain.cmake
              echo 'set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   '$OS_FLAGS '" CACHE STRING "c flags")' >> toolchain.cmake
              echo 'set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} '$OS_FLAGS '" CACHE STRING "asm flags")' >> toolchain.cmake

              cmake .. -DCMAKE_INSTALL_PREFIX="${OPENSSL_DIR}" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
              make -j "$(nproc)"
              make install
              ;;
            esac

          if: matrix.library.version != 'vendored' && !steps.openssl-cache.outputs.cache-hit
@@ -359,11 +386,11 @@ jobs:
            if [[ "${{ matrix.library.version }}" == "vendored" ]]; then
              features="--features vendored"
            fi
            if [[ "${{ matrix.bindgen }}" == "true" && "${{ matrix.library.name }}" != "boringssl" ]]; then
            if [[ "${{ matrix.bindgen }}" == "true" ]]; then
              features="$features --features bindgen"
            fi
            cargo run --manifest-path=systest/Cargo.toml --target ${{ matrix.target }} $features
          if: matrix.library.name != 'boringssl'
          if: ${{ !(matrix.library.name == 'boringssl' || matrix.library.name == 'aws-lc') }}
        - name: Test openssl
          run: |
            if [[ "${{ matrix.library.name }}" == "boringssl" && "${{ matrix.bindgen }}" != "true" ]]; then
@@ -371,8 +398,12 @@ jobs:
              BORINGSSL_BUILD_DIR="$OPENSSL_DIR/build/"
            fi
            if [[ "${{ matrix.library.version }}" == "vendored" ]]; then
              if [[ "${{ matrix.library.name }}" == "aws-lc" ]]; then
                features="--features aws-lc"
              else
                features="--features vendored"
              fi
            fi
            if [[ "${{ matrix.bindgen }}" == "true" ]]; then
              features="$features --features bindgen"
            fi
@@ -386,4 +417,4 @@ jobs:
              features="$features --features openssl-sys/bindgen"
            fi
            cargo test --manifest-path=openssl-errors/Cargo.toml --target ${{ matrix.target }} $features
          if: matrix.library.name != 'boringssl'
          if: ${{ !(matrix.library.name == 'boringssl' || matrix.library.name == 'aws-lc') }}
+2 −0
Original line number Diff line number Diff line
@@ -18,10 +18,12 @@ rust-version = "1.63.0"
[features]
vendored = ['openssl-src']
unstable_boringssl = ['bssl-sys']
aws-lc = ['dep:aws-lc-sys']

[dependencies]
libc = "0.2"
bssl-sys = { version = "0.1.0", optional = true }
aws-lc-sys = { version = "0.27", features = ["ssl"], optional = true }

[build-dependencies]
bindgen = { version = "0.69.0", optional = true, features = ["experimental"] }
+10 −0
Original line number Diff line number Diff line
@@ -19,6 +19,10 @@ VERSION(OPENSSL, OPENSSL_VERSION_NUMBER)
RUST_OPENSSL_IS_BORINGSSL
#endif

#ifdef OPENSSL_IS_AWSLC
RUST_OPENSSL_IS_AWSLC
#endif

#ifdef OPENSSL_NO_BF
RUST_CONF_OPENSSL_NO_BF
#endif
@@ -142,3 +146,9 @@ RUST_CONF_OPENSSL_NO_SEED
#ifdef OPENSSL_NO_SCRYPT
RUST_CONF_OPENSSL_NO_SCRYPT
#endif

#define SYMBOL_PREFIX2(X) RUST_BINDGEN_SYMBOL_PREFIX_##X##_
#define SYMBOL_PREFIX(X) SYMBOL_PREFIX2(X)
#if defined(OPENSSL_IS_AWSLC) && defined(BORINGSSL_PREFIX)
SYMBOL_PREFIX(BORINGSSL_PREFIX)
#endif
+69 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ enum Version {
    Openssl10x,
    Libressl,
    Boringssl,
    AwsLc,
}

fn env_inner(name: &str) -> Option<OsString> {
@@ -71,6 +72,51 @@ fn check_ssl_kind() {
        // BoringSSL does not have any build logic, exit early
        std::process::exit(0);
    }

    let is_aws_lc = cfg!(feature = "aws-lc");

    if is_aws_lc {
        println!("cargo:rustc-cfg=awslc");
        println!("cargo:awslc=true");

        // The aws-lc-sys crate uses a link name that embeds
        // the version number of crate. Examples (crate-name => links name):
        //   * aws-lc-sys => aws_lc_0_26_0
        // This is done to avoid issues if the cargo dependency graph for an application
        // were to resolve to multiple versions for the same crate.
        //
        // Due to this we need to determine what version of the AWS-LC has been selected (fips or non-fips)
        // and then need to parse out the pieces we are interested in ignoring the version componenet of the name.
        const AWS_LC_ENV_VAR_PREFIX: &str = "DEP_AWS_LC_";

        let mut version = None;
        for (name, _) in std::env::vars() {
            if let Some(name) = name.strip_prefix(AWS_LC_ENV_VAR_PREFIX) {
                if let Some(name) = name.strip_suffix("_INCLUDE") {
                    version = Some(name.to_owned());
                    break;
                }
            }
        }
        let version = version.expect("aws-lc version detected");

        // Read the OpenSSL configuration statements and emit rust-cfg for each.
        if let Ok(vars) = std::env::var(format!("{AWS_LC_ENV_VAR_PREFIX}{version}_CONF")) {
            for var in vars.split(',') {
                println!("cargo:rustc-cfg=osslconf=\"{var}\"");
            }
            println!("cargo:conf={vars}");
        }

        // Emit the include header directory from the aws-lc(-fips)-sys crate so that it can be used if needed
        // by crates consuming openssl-sys.
        if let Ok(val) = std::env::var(format!("{AWS_LC_ENV_VAR_PREFIX}{version}_INCLUDE")) {
            println!("cargo:include={val}");
        }

        // AWS-LC does not have any build logic, exit early
        std::process::exit(0);
    }
}

fn main() {
@@ -79,6 +125,7 @@ fn main() {
    println!("cargo:rustc-check-cfg=cfg(openssl)");
    println!("cargo:rustc-check-cfg=cfg(libressl)");
    println!("cargo:rustc-check-cfg=cfg(boringssl)");
    println!("cargo:rustc-check-cfg=cfg(awslc)");

    println!("cargo:rustc-check-cfg=cfg(libressl250)");
    println!("cargo:rustc-check-cfg=cfg(libressl251)");
@@ -201,7 +248,10 @@ fn main() {
    // try to match the behavior for common platforms. For a more robust option,
    // this likely needs to be deferred to the caller with an environment
    // variable.
    if version == Version::Boringssl && kind == "static" && env::var("CARGO_CFG_UNIX").is_ok() {
    if (version == Version::Boringssl || version == Version::AwsLc)
        && kind == "static"
        && env::var("CARGO_CFG_UNIX").is_ok()
    {
        let cpp_lib = match env::var("CARGO_CFG_TARGET_OS").unwrap().as_ref() {
            "macos" => "c++",
            _ => "stdc++",
@@ -231,8 +281,8 @@ fn main() {
fn postprocess(include_dirs: &[PathBuf]) -> Version {
    let version = validate_headers(include_dirs);

    // Never run bindgen for BoringSSL, if it was needed we already ran it.
    if version != Version::Boringssl {
    // Never run bindgen for BoringSSL or AWS-LC, if it was needed we already ran it.
    if !(version == Version::Boringssl || version == Version::AwsLc) {
        #[cfg(feature = "bindgen")]
        run_bindgen::run(&include_dirs);
    }
@@ -296,6 +346,8 @@ See rust-openssl documentation for more information:
    let mut openssl_version = None;
    let mut libressl_version = None;
    let mut is_boringssl = false;
    let mut is_awslc = false;
    let mut bindgen_symbol_prefix: Option<String> = None;
    for line in expanded.lines() {
        let line = line.trim();

@@ -303,7 +355,9 @@ See rust-openssl documentation for more information:
        let new_openssl_prefix = "RUST_VERSION_NEW_OPENSSL_";
        let libressl_prefix = "RUST_VERSION_LIBRESSL_";
        let boringssl_prefix = "RUST_OPENSSL_IS_BORINGSSL";
        let awslc_prefix = "RUST_OPENSSL_IS_AWSLC";
        let conf_prefix = "RUST_CONF_";
        let symbol_prefix = "RUST_BINDGEN_SYMBOL_PREFIX_";
        if let Some(version) = line.strip_prefix(openssl_prefix) {
            openssl_version = Some(parse_version(version));
        } else if let Some(version) = line.strip_prefix(new_openssl_prefix) {
@@ -314,6 +368,11 @@ See rust-openssl documentation for more information:
            enabled.push(conf);
        } else if line.starts_with(boringssl_prefix) {
            is_boringssl = true;
        } else if line.starts_with(awslc_prefix) {
            is_awslc = true;
        } else if line.starts_with(symbol_prefix) {
            let sym_prefix = String::from(line.strip_prefix(symbol_prefix).unwrap());
            bindgen_symbol_prefix = Some(sym_prefix);
        }
    }

@@ -329,6 +388,13 @@ See rust-openssl documentation for more information:
        return Version::Boringssl;
    }

    if is_awslc {
        println!("cargo:rustc-cfg=awslc");
        println!("cargo:awslc=true");
        run_bindgen::run_awslc(include_dirs, bindgen_symbol_prefix);
        return Version::AwsLc;
    }

    // We set this for any non-BoringSSL lib.
    println!("cargo:rustc-cfg=openssl");

+129 −3
Original line number Diff line number Diff line
@@ -36,15 +36,20 @@ const INCLUDES: &str = "
#include <openssl/x509_vfy.h>
#include <openssl/x509v3.h>

#if !defined(OPENSSL_IS_AWSLC)
// this must be included after ssl.h for libressl!
#include <openssl/srtp.h>
#endif

#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
#if !(defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC))
#include <openssl/cms.h>
#endif

#if !defined(OPENSSL_IS_BORINGSSL)
#if !(defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC))
#include <openssl/comp.h>
#endif

#if !defined(OPENSSL_IS_BORINGSSL)
#include <openssl/ocsp.h>
#endif

@@ -60,7 +65,7 @@ const INCLUDES: &str = "
#include <openssl/quic.h>
#endif

#if defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL)
#if defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
#include <openssl/poly1305.h>
#endif

@@ -216,6 +221,127 @@ pub fn run_boringssl(include_dirs: &[PathBuf]) {
        .compile("boring_static_wrapper");
}

#[cfg(feature = "bindgen")]
mod bindgen_options {
    use bindgen::callbacks::{ItemInfo, ParseCallbacks};

    #[derive(Debug)]
    pub struct StripPrefixCallback {
        remove_prefix: Option<String>,
    }

    impl StripPrefixCallback {
        pub fn new(prefix: &str) -> StripPrefixCallback {
            StripPrefixCallback {
                remove_prefix: Some(prefix.to_string()),
            }
        }
    }

    impl ParseCallbacks for StripPrefixCallback {
        fn generated_name_override(&self, item_info: ItemInfo<'_>) -> Option<String> {
            self.remove_prefix
                .as_ref()
                .and_then(|s| item_info.name.strip_prefix(s.as_str()).map(String::from))
        }
    }
}

#[cfg(feature = "bindgen")]
pub fn run_awslc(include_dirs: &[PathBuf], symbol_prefix: Option<String>) {
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    fs::File::create(out_dir.join("awslc_static_wrapper.h"))
        .expect("Failed to create awslc_static_wrapper.h")
        .write_all(INCLUDES.as_bytes())
        .expect("Failed to write contents to awslc_static_wrapper.h");

    let mut builder = bindgen::builder()
        .rust_target(RustTarget::Stable_1_47)
        .ctypes_prefix("::libc")
        .raw_line("use libc::*;")
        .derive_default(false)
        .enable_function_attribute_detection()
        .default_macro_constant_type(MacroTypeVariation::Signed)
        .rustified_enum("point_conversion_form_t")
        .allowlist_file(r".*(/|\\)openssl((/|\\)[^/\\]+)+\.h")
        .wrap_static_fns(true)
        .wrap_static_fns_path(out_dir.join("awslc_static_wrapper").display().to_string())
        .layout_tests(false)
        .header(out_dir.join("awslc_static_wrapper.h").display().to_string());

    if let Some(prefix) = symbol_prefix {
        use bindgen_options::StripPrefixCallback;
        let callback = StripPrefixCallback::new(prefix.as_str());
        builder = builder.parse_callbacks(Box::from(callback));
    }

    for include_dir in include_dirs {
        builder = builder
            .clang_arg("-I")
            .clang_arg(include_dir.display().to_string());
    }

    builder
        .generate()
        .unwrap()
        .write_to_file(out_dir.join("bindgen.rs"))
        .unwrap();

    cc::Build::new()
        .file(out_dir.join("awslc_static_wrapper.c"))
        .includes(include_dirs)
        .compile("awslc_static_wrapper");
}

#[cfg(not(feature = "bindgen"))]
pub fn run_awslc(include_dirs: &[PathBuf], symbol_prefix: Option<String>) {
    if symbol_prefix.is_some() {
        panic!("aws-lc installation has prefixed symbols, but bindgen-cli does not support removing prefixes. \
        Enable the bindgen crate feature to support this installation.")
    }

    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    fs::File::create(out_dir.join("awslc_static_wrapper.h"))
        .expect("Failed to create awslc_static_wrapper.h")
        .write_all(INCLUDES.as_bytes())
        .expect("Failed to write contents to awslc_static_wrapper.h");

    let mut bindgen_cmd = process::Command::new("bindgen");
    bindgen_cmd
        .arg("-o")
        .arg(out_dir.join("bindgen.rs"))
        // Must be a valid version from
        // https://docs.rs/bindgen/latest/bindgen/enum.RustTarget.html
        .arg("--rust-target=1.47")
        .arg("--ctypes-prefix=::libc")
        .arg("--raw-line=use libc::*;")
        .arg("--no-derive-default")
        .arg("--enable-function-attribute-detection")
        .arg("--default-macro-constant-type=signed")
        .arg("--rustified-enum=point_conversion_form_t")
        .arg(r"--allowlist-file=.*(/|\\)openssl((/|\\)[^/\\]+)+\.h")
        .arg("--wrap-static-fns")
        .arg("--wrap-static-fns-path")
        .arg(out_dir.join("awslc_static_wrapper").display().to_string())
        .arg(out_dir.join("awslc_static_wrapper.h"))
        .arg("--")
        .arg(format!("--target={}", env::var("TARGET").unwrap()));

    for include_dir in include_dirs {
        bindgen_cmd.arg("-I").arg(include_dir.display().to_string());
    }

    let result = bindgen_cmd.status().expect("bindgen failed to execute");
    assert!(result.success());

    cc::Build::new()
        .file(out_dir.join("awslc_static_wrapper.c"))
        .includes(include_dirs)
        .compile("awslc_static_wrapper");
}

#[cfg(feature = "bindgen")]
#[derive(Debug)]
struct OpensslCallbacks;
Loading