diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9090ca194d..33c352cd2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,12 +16,15 @@ concurrency: group: ${{ github.ref }} cancel-in-progress: true +permissions: + contents: read # to fetch code (actions/checkout) + jobs: rustfmt: name: rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - uses: sfackler/actions/rustfmt@master @@ -29,23 +32,23 @@ jobs: name: clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - - run: echo "::set-output name=version::$(rustc --version)" + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} restore-keys: | index-${{ runner.os }}- - run: cargo generate-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo fetch - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: target key: target-${{ github.job }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} @@ -55,25 +58,26 @@ jobs: name: min-version runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + # Remember to also update `--rust-target` in `openssl-sys/build/run_bindgen.rs` - uses: sfackler/actions/rustup@master with: version: 1.56.0 - - run: echo "::set-output name=version::$(rustc --version)" + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} restore-keys: | index-${{ runner.os }}- - run: cargo generate-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo fetch - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: target key: target-${{ github.job }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} @@ -83,25 +87,25 @@ jobs: name: windows-vcpkg runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - - run: echo "::set-output name=version::$(rustc --version)" + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - run: echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append - run: vcpkg install openssl:x64-windows-static-md - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} restore-keys: | index-${{ runner.os }}- - run: cargo generate-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo fetch - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: target key: target-${{ github.job }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} @@ -113,23 +117,23 @@ jobs: name: macos-homebrew runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - - run: echo "::set-output name=version::$(rustc --version)" + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} restore-keys: | index-${{ runner.os }}- - run: cargo generate-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo fetch - # - uses: actions/cache@v1 + # - uses: actions/cache@v3 # with: # path: target # key: target-${{ github.job }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} @@ -150,14 +154,14 @@ jobs: - false library: - name: boringssl - version: 5697a9202615925696f8dc7f4e286d44d474769e + version: bcecc7d834fc44ad257b2f23f88e1cf597ab2736 - name: openssl version: vendored - name: openssl - version: 3.0.5 + version: 3.1.0 dl-path: / - name: openssl - version: 1.1.1q + version: 1.1.1t dl-path: / - name: openssl version: 1.1.0l @@ -178,12 +182,12 @@ jobs: bindgen: true library: name: libressl - version: 3.5.3 + version: 3.7.3 - target: x86_64-unknown-linux-gnu bindgen: true library: name: libressl - version: 3.6.1 + version: 3.8.0 - target: x86_64-unknown-linux-gnu bindgen: false library: @@ -193,16 +197,12 @@ jobs: bindgen: false library: name: libressl - version: 3.5.3 + version: 3.7.3 - target: x86_64-unknown-linux-gnu bindgen: false library: name: libressl - version: 3.6.1 - exclude: - - library: - name: boringssl - bindgen: true + version: 3.8.0 name: ${{ matrix.target }}-${{ matrix.library.name }}-${{ matrix.library.version }}-${{ matrix.bindgen }} runs-on: ubuntu-latest env: @@ -211,9 +211,9 @@ jobs: CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_AR: arm-linux-gnueabihf-ar CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER: qemu-arm -L /usr/arm-linux-gnueabihf steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - - run: echo "::set-output name=version::$(rustc --version)" + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - run: rustup target add ${{ matrix.target }} - name: Install packages @@ -233,7 +233,7 @@ jobs: sudo apt-get update sudo apt-get install -y $packages - run: sudo apt-get remove -y libssl-dev - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: /opt/openssl key: openssl-${{ matrix.target }}-${{ matrix.library.name }}-${{ matrix.library.version }}-2 @@ -295,37 +295,47 @@ jobs: make install_sw ;; "boringssl") - sed -i rust/CMakeLists.txt -e '1s%^%include_directories(../include)\n%' - cpu=`echo ${{ matrix.target }} | cut -d - -f 1` + 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 -DRUST_BINDINGS="${{ matrix.target }}" -B $OPENSSL_DIR -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake - make -C $OPENSSL_DIR + + cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DRUST_BINDINGS="${{ matrix.target }}" -DCMAKE_INSTALL_PREFIX="${OPENSSL_DIR}" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake + make -j "$(nproc)" + make install + + # Copy stuff around so it's all as the build system expects. + cp -r rust/ "$OPENSSL_DIR/rust" + mkdir -p "$OPENSSL_DIR/crypto/" + mkdir -p "$OPENSSL_DIR/ssl/" + cp "$OPENSSL_DIR/lib/libcrypto.a" "$OPENSSL_DIR/crypto/" + cp "$OPENSSL_DIR/lib/libssl.a" "$OPENSSL_DIR/ssl/" esac if: matrix.library.version != 'vendored' && !steps.openssl-cache.outputs.cache-hit - run: | mkdir -p .cargo echo '[patch.crates-io]' > .cargo/config.toml - echo 'bssl-sys = { path = "'$OPENSSL_DIR'/rust" }' >> .cargo/config.toml - if: matrix.library.name == 'boringssl' - - uses: actions/cache@v1 + echo 'bssl-sys = { path = "'$OPENSSL_DIR'/rust/bssl-sys" }' >> .cargo/config.toml + if: matrix.library.name == 'boringssl' && !matrix.bindgen + - uses: actions/cache@v3 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} restore-keys: | index-${{ runner.os }}- - run: cargo generate-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo fetch - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: target key: target-${{ matrix.target }}-${{ matrix.bindgen }}-${{ matrix.library.name }}-${{ matrix.library.version }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} @@ -334,14 +344,14 @@ jobs: if [[ "${{ matrix.library.version }}" == "vendored" ]]; then features="--features vendored" fi - if [[ "${{ matrix.bindgen }}" == "true" ]]; then + if [[ "${{ matrix.bindgen }}" == "true" && "${{ matrix.library.name }}" != "boringssl" ]]; then features="$features --features bindgen" fi cargo run --manifest-path=systest/Cargo.toml --target ${{ matrix.target }} $features if: matrix.library.name != 'boringssl' - name: Test openssl run: | - if [[ "${{ matrix.library.name }}" == "boringssl" ]]; then + if [[ "${{ matrix.library.name }}" == "boringssl" && "${{ matrix.bindgen }}" != "true" ]]; then features="--features unstable_boringssl" fi if [[ "${{ matrix.library.version }}" == "vendored" ]]; then diff --git a/openssl-macros/Cargo.toml b/openssl-macros/Cargo.toml index d55f2267d8..5337de751e 100644 --- a/openssl-macros/Cargo.toml +++ b/openssl-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-macros" -version = "0.1.0" +version = "0.1.1" edition = "2018" license = "MIT/Apache-2.0" description = "Internal macros used by the openssl crate." @@ -11,4 +11,4 @@ proc-macro = true [dependencies] proc-macro2 = "1" quote = "1" -syn = { version = "1", features = ["full"] } +syn = { version = "2", features = ["full"] } diff --git a/openssl-macros/src/lib.rs b/openssl-macros/src/lib.rs index c007409ace..99db988818 100644 --- a/openssl-macros/src/lib.rs +++ b/openssl-macros/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + use proc_macro::TokenStream; use proc_macro2::Ident; use quote::quote; diff --git a/openssl-sys/CHANGELOG.md b/openssl-sys/CHANGELOG.md index ec815325f7..13c3f32a6c 100644 --- a/openssl-sys/CHANGELOG.md +++ b/openssl-sys/CHANGELOG.md @@ -2,6 +2,122 @@ ## [Unreleased] +## [v0.9.89] - 2023-06-20 + +### Fixed + +* Fixed compilation with recent versions of BoringSSL. + +### Added + +* Added support for detecting OpenSSL compiled with `OPENSSL_NO_OCB`. +* Added `EVP_PKEY_SM2` and `NID_sm2`. +* Added `EVP_PKEY_assign_RSA`, `EVP_PKEY_assign_DSA`, `EVP_PKEY_assign_DH`, and `EVP_PKEY_assign_EC_KEY`. +* Added `EC_GROUP_get_asn1_flag`. +* Expose `EC_POINT_get_affine_coordinates` on BoringSSL and LibreSSL. +* Added `EVP_PKEY_derive_set_peer_ex`. + +## [v0.9.88] - 2023-05-30 + +### Added + +* Added support for the LibreSSL 3.8.0. +* Added support for detecting `OPENSSL_NO_RC4`. +* Added `OBJ_dup`. +* Added `ASN1_TYPE_new`, `ASN1_TYPE_set`, `d2i_ASN1_TYPE`, and `i2d_ASN1_TYPE`. +* Added `SSL_bytes_to_cipher_list`, `SSL_CTX_get_num_tickets`, and `SSL_get_num_tickets`. +* Added `GENERAL_NAME_set0_othername`. +* Added `X509_get_pathlen`. + +## [v0.9.87] - 2023-04-24 + +### Added + +* Added `DH_CHECK`. +* Added `CMAC_CTX_new`, `CMAC_CTX_free`, `CMAC_Init`, `CMAC_Update`, `CMAC_Final`, and `CMAC_CTX_copy`. +* Added `EVP_default_properties_is_fips_enabled`. +* Added `X509_get0_subject_key_id`, `X509_get0_authority_key_id`, `X509_get0_authority_issuer`, and `X509_get0_authority_serial`. +* Added `NID_poly1305`. + + +## [v0.9.86] - 2023-04-20 + +### Fixed + +* Fixed BoringSSL support with the latest bindgen release. + +### Added + +* Added bindings for PKCS#7 functions and more X.509 functions. + + +## [v0.9.85] - 2023-04-09 + +### Added + +* Added support for LibreSSL 3.7.x. + +## [v0.9.84] - 2023-04-01 + +### Added + +* Added `ASN1_INTEGER_dup` and `ASN1_INTEGER_cmp`. +* Added `stack_st_X509_NAME_ENTRY`. +* Added `DIST_POINT_NAME`, `DIST_POINT`, `stack_st_DIST_POINT`, `DIST_POINT_free`, and `DIST_POINT_NAME_free`. + +## [v0.9.83] - 2023-03-23 + +### Fixed + +* Fixed version checks for LibreSSL. + +### Added + +* Added `i2d_X509_EXTENSION`. +* Added `GENERAL_NAME_new`. + +## [v0.9.82] - 2023-03-19 + +### Added + +* Added support for LibreSSL 3.7.1. +* Added support for X25519 and Ed25519 on LibreSSL and BoringSSL. + +## [v0.9.81] - 2023-03-14 + +### Fixed + +Fixed builds against OpenSSL built with `no-cast`. + +### Added + +* Added experimental bindgen support for BoringSSL. +* Added `X509_VERIFY_PARAM_set_auth_level`, `X509_VERIFY_PARAM_get_auth_level`, and `X509_VERIFY_PARAM_set_purpose`. +* Added `X509_PURPOSE_*` consts. +* Added `X509_NAME_add_entry`. +* Added `X509_load_crl_file`. +* Added `SSL_set_cipher_list`, `SSL_set_ssl_method`, `SSL_use_PrivateKey_file`, `SSL_use_PrivateKey`, `SSL_use_certificate`, `SSL_use_certificate_chain_file`, `SSL_set_client_CA_list`, `SSL_add_client_CA`, and `SSL_set0_verify_cert_store`. +* Added `X509_PURPOSE`, `X509_STORE_set_purpose`, and `X509_STORE_set_trust`. +* Added `SSL_CTX_set_num_tickets`, `SSL_set_num_tickets`, `SSL_CTX_get_num_tickets`, and `SSL_get_num_tickets`. +* Added `CMS_verify`. + +### Removed + +* Removed an unnecessary link to libatomic for 32-bit android targets. + +## [v0.9.80] - 2022-12-20 + +### Fixed + +* Added `NO_DEPRECATED_3_0` cfg checks for more APIs. + +### Added + +* Added support for LibreSSL 3.7.0. +* Added `SSL_CTRL_CHAIN_CERT` and `SSL_add0_chain_cert`. +* Added `EVP_PKEY_get_security_bits` and `EVP_PKEY_security_bits`. +* Added `OSSL_PROVIDER_set_default_search_path`. + ## [v0.9.79] - 2022-12-06 ### Added @@ -357,7 +473,17 @@ * Added `X509_verify` and `X509_REQ_verify`. * Added `EVP_MD_type` and `EVP_GROUP_get_curve_name`. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.79..master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.89..master +[v0.9.89]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.88...openssl-sys-v0.9.89 +[v0.9.88]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.87...openssl-sys-v0.9.88 +[v0.9.87]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.86...openssl-sys-v0.9.87 +[v0.9.86]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.85...openssl-sys-v0.9.86 +[v0.9.85]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.84...openssl-sys-v0.9.85 +[v0.9.84]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.83...openssl-sys-v0.9.84 +[v0.9.83]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.82...openssl-sys-v0.9.83 +[v0.9.82]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.81...openssl-sys-v0.9.82 +[v0.9.81]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.80...openssl-sys-v0.9.81 +[v0.9.80]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.79...openssl-sys-v0.9.80 [v0.9.79]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.78...openssl-sys-v0.9.79 [v0.9.78]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.77...openssl-sys-v0.9.78 [v0.9.77]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.76...openssl-sys-v0.9.77 diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index de6b33e80b..0c261c5719 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.79" +version = "0.9.89" authors = [ "Alex Crichton ", "Steven Fackler ", @@ -12,6 +12,7 @@ readme = "README.md" categories = ["cryptography", "external-ffi-bindings"] links = "openssl" build = "build/main.rs" +edition = "2018" [features] vendored = ['openssl-src'] @@ -22,11 +23,10 @@ libc = "0.2" bssl-sys = { version = "0.1.0", optional = true } [build-dependencies] -bindgen = { version = "0.60.1", optional = true } -cc = "1.0" +bindgen = { version = "0.64.0", optional = true, features = ["experimental"] } +cc = "1.0.61" openssl-src = { version = "111", optional = true } pkg-config = "0.3.9" -autocfg = "1.0" [target.'cfg(target_env = "msvc")'.build-dependencies] vcpkg = "0.2.8" diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs index 9ae7748cc6..2f3ff3eafd 100644 --- a/openssl-sys/build/cfgs.rs +++ b/openssl-sys/build/cfgs.rs @@ -1,3 +1,4 @@ +#[allow(clippy::unusual_byte_groupings)] pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<&'static str> { let mut cfgs = vec![]; @@ -31,6 +32,9 @@ pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<& if libressl_version >= 0x2_09_01_00_0 { cfgs.push("libressl291"); } + if libressl_version >= 0x3_01_00_00_0 { + cfgs.push("libressl310"); + } if libressl_version >= 0x3_02_01_00_0 { cfgs.push("libressl321"); } @@ -43,6 +47,12 @@ pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<& if libressl_version >= 0x3_05_00_00_0 { cfgs.push("libressl350"); } + if libressl_version >= 0x3_06_00_00_0 { + cfgs.push("libressl360"); + } + if libressl_version >= 0x3_07_00_00_0 { + cfgs.push("libressl370"); + } } else { let openssl_version = openssl_version.unwrap(); @@ -82,6 +92,9 @@ pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<& if openssl_version >= 0x1_01_01_03_0 { cfgs.push("ossl111c"); } + if openssl_version >= 0x1_01_01_04_0 { + cfgs.push("ossl111d"); + } } cfgs diff --git a/openssl-sys/build/expando.c b/openssl-sys/build/expando.c index 2ec63ec046..5d003d9022 100644 --- a/openssl-sys/build/expando.c +++ b/openssl-sys/build/expando.c @@ -15,6 +15,10 @@ NEW_VERSION(OPENSSL_VERSION_MAJOR, OPENSSL_VERSION_MINOR, OPENSSL_VERSION_PATCH) VERSION(OPENSSL, OPENSSL_VERSION_NUMBER) #endif +#ifdef OPENSSL_IS_BORINGSSL +RUST_OPENSSL_IS_BORINGSSL +#endif + #ifdef OPENSSL_NO_BF RUST_CONF_OPENSSL_NO_BF #endif @@ -35,6 +39,10 @@ RUST_CONF_OPENSSL_NO_IDEA RUST_CONF_OPENSSL_NO_CAMELLIA #endif +#ifdef OPENSSL_NO_CAST +RUST_CONF_OPENSSL_NO_CAST +#endif + #ifdef OPENSSL_NO_CMS RUST_CONF_OPENSSL_NO_CMS #endif @@ -67,10 +75,18 @@ RUST_CONF_OPENSSL_NO_NEXTPROTONEG RUST_CONF_OPENSSL_NO_OCSP #endif +#ifdef OPENSSL_NO_OCB +RUST_CONF_OPENSSL_NO_OCB +#endif + #ifdef OPENSSL_NO_PSK RUST_CONF_OPENSSL_NO_PSK #endif +#ifdef OPENSSL_NO_RC4 +RUST_CONF_OPENSSL_NO_RC4 +#endif + #ifdef OPENSSL_NO_RFC3779 RUST_CONF_OPENSSL_NO_RFC3779 #endif diff --git a/openssl-sys/build/find_normal.rs b/openssl-sys/build/find_normal.rs index df451438ad..791fc33985 100644 --- a/openssl-sys/build/find_normal.rs +++ b/openssl-sys/build/find_normal.rs @@ -1,4 +1,3 @@ -use pkg_config; use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::process::{self, Command}; @@ -211,7 +210,7 @@ fn try_pkg_config() { let lib = match pkg_config::Config::new() .print_system_libs(false) - .find("openssl") + .probe("openssl") { Ok(lib) => lib, Err(e) => { diff --git a/openssl-sys/build/main.rs b/openssl-sys/build/main.rs index 71b36c2309..3359165a33 100644 --- a/openssl-sys/build/main.rs +++ b/openssl-sys/build/main.rs @@ -1,6 +1,3 @@ -#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] - -extern crate autocfg; #[cfg(feature = "bindgen")] extern crate bindgen; extern crate cc; @@ -19,7 +16,6 @@ mod cfgs; mod find_normal; #[cfg(feature = "vendored")] mod find_vendored; -#[cfg(feature = "bindgen")] mod run_bindgen; #[derive(PartialEq)] @@ -28,6 +24,7 @@ enum Version { Openssl11x, Openssl10x, Libressl, + Boringssl, } fn env_inner(name: &str) -> Option { @@ -63,16 +60,13 @@ fn find_openssl(target: &str) -> (Vec, PathBuf) { fn check_ssl_kind() { if cfg!(feature = "unstable_boringssl") { println!("cargo:rustc-cfg=boringssl"); + println!("cargo:boringssl=true"); // BoringSSL does not have any build logic, exit early std::process::exit(0); - } else { - println!("cargo:rustc-cfg=openssl"); } } fn main() { - check_rustc_versions(); - check_ssl_kind(); let target = env::var("TARGET").unwrap(); @@ -122,16 +116,6 @@ fn main() { println!("cargo:rustc-link-lib={}={}", kind, lib); } - // https://github.com/openssl/openssl/pull/15086 - if version == Version::Openssl3xx - && kind == "static" - && (env::var("CARGO_CFG_TARGET_OS").unwrap() == "linux" - || env::var("CARGO_CFG_TARGET_OS").unwrap() == "android") - && env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" - { - println!("cargo:rustc-link-lib=dylib=atomic"); - } - if kind == "static" && target.contains("windows") { println!("cargo:rustc-link-lib=dylib=gdi32"); println!("cargo:rustc-link-lib=dylib=user32"); @@ -141,26 +125,21 @@ fn main() { } } -fn check_rustc_versions() { - let cfg = autocfg::new(); - - if cfg.probe_rustc_version(1, 31) { - println!("cargo:rustc-cfg=const_fn"); - } -} - -#[allow(clippy::let_and_return)] fn postprocess(include_dirs: &[PathBuf]) -> Version { let version = validate_headers(include_dirs); - #[cfg(feature = "bindgen")] - run_bindgen::run(&include_dirs); + + // Never run bindgen for BoringSSL, if it was needed we already ran it. + if version != Version::Boringssl { + #[cfg(feature = "bindgen")] + run_bindgen::run(&include_dirs); + } version } /// Validates the header files found in `include_dir` and then returns the /// version string of OpenSSL. -#[allow(clippy::manual_strip)] // we need to support pre-1.45.0 +#[allow(clippy::unusual_byte_groupings)] fn validate_headers(include_dirs: &[PathBuf]) -> Version { // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, 1.1.0, 1.1.1 and 3.0.0. // To correctly expose the right API from this crate, take a look at @@ -176,9 +155,7 @@ fn validate_headers(include_dirs: &[PathBuf]) -> Version { // account for compile differences and such. println!("cargo:rerun-if-changed=build/expando.c"); let mut gcc = cc::Build::new(); - for include_dir in include_dirs { - gcc.include(include_dir); - } + gcc.includes(include_dirs); let expanded = match gcc.file("build/expando.c").try_expand() { Ok(expanded) => expanded, Err(e) => { @@ -215,27 +192,38 @@ See rust-openssl documentation for more information: let mut enabled = vec![]; let mut openssl_version = None; let mut libressl_version = None; + let mut is_boringssl = false; for line in expanded.lines() { let line = line.trim(); let openssl_prefix = "RUST_VERSION_OPENSSL_"; let new_openssl_prefix = "RUST_VERSION_NEW_OPENSSL_"; let libressl_prefix = "RUST_VERSION_LIBRESSL_"; + let boringsl_prefix = "RUST_OPENSSL_IS_BORINGSSL"; let conf_prefix = "RUST_CONF_"; - if line.starts_with(openssl_prefix) { - let version = &line[openssl_prefix.len()..]; + if let Some(version) = line.strip_prefix(openssl_prefix) { openssl_version = Some(parse_version(version)); - } else if line.starts_with(new_openssl_prefix) { - let version = &line[new_openssl_prefix.len()..]; + } else if let Some(version) = line.strip_prefix(new_openssl_prefix) { openssl_version = Some(parse_new_version(version)); - } else if line.starts_with(libressl_prefix) { - let version = &line[libressl_prefix.len()..]; + } else if let Some(version) = line.strip_prefix(libressl_prefix) { libressl_version = Some(parse_version(version)); - } else if line.starts_with(conf_prefix) { - enabled.push(&line[conf_prefix.len()..]); + } else if let Some(conf) = line.strip_prefix(conf_prefix) { + enabled.push(conf); + } else if line.starts_with(boringsl_prefix) { + is_boringssl = true; } } + if is_boringssl { + println!("cargo:rustc-cfg=boringssl"); + println!("cargo:boringssl=true"); + run_bindgen::run_boringssl(include_dirs); + return Version::Boringssl; + } + + // We set this for any non-BoringSSL lib. + println!("cargo:rustc-cfg=openssl"); + for enabled in &enabled { println!("cargo:rustc-cfg=osslconf=\"{}\"", enabled); } @@ -282,6 +270,10 @@ See rust-openssl documentation for more information: (3, 5, _) => ('3', '5', 'x'), (3, 6, 0) => ('3', '6', '0'), (3, 6, _) => ('3', '6', 'x'), + (3, 7, 0) => ('3', '7', '0'), + (3, 7, 1) => ('3', '7', '1'), + (3, 7, _) => ('3', '7', 'x'), + (3, 8, 0) => ('3', '8', '0'), _ => version_error(), }; @@ -324,7 +316,7 @@ fn version_error() -> ! { " This crate is only compatible with OpenSSL (version 1.0.1 through 1.1.1, or 3.0.0), or LibreSSL 2.5 -through 3.6.x, but a different version of OpenSSL was found. The build is now aborting +through 3.8.0, but a different version of OpenSSL was found. The build is now aborting due to this version mismatch. " @@ -332,18 +324,13 @@ due to this version mismatch. } // parses a string that looks like "0x100020cfL" -#[allow(deprecated)] // trim_right_matches is now trim_end_matches -#[allow(clippy::match_like_matches_macro)] // matches macro requires rust 1.42.0 fn parse_version(version: &str) -> u64 { // cut off the 0x prefix assert!(version.starts_with("0x")); let version = &version[2..]; // and the type specifier suffix - let version = version.trim_right_matches(|c: char| match c { - '0'..='9' | 'a'..='f' | 'A'..='F' => false, - _ => true, - }); + let version = version.trim_end_matches(|c: char| !c.is_ascii_hexdigit()); u64::from_str_radix(version, 16).unwrap() } diff --git a/openssl-sys/build/run_bindgen.rs b/openssl-sys/build/run_bindgen.rs index 9531e6e8bb..6743403161 100644 --- a/openssl-sys/build/run_bindgen.rs +++ b/openssl-sys/build/run_bindgen.rs @@ -1,13 +1,18 @@ +#[cfg(feature = "bindgen")] use bindgen::callbacks::{MacroParsingBehavior, ParseCallbacks}; -use bindgen::RustTarget; -use std::env; +#[cfg(feature = "bindgen")] +use bindgen::{MacroTypeVariation, RustTarget}; +use std::io::Write; use std::path::PathBuf; +#[cfg(not(feature = "bindgen"))] +use std::process; +use std::{env, fs}; const INCLUDES: &str = " #include #include #include -#include +#include #include #include #include @@ -17,7 +22,6 @@ const INCLUDES: &str = " #include #include #include -#include #include #include #include @@ -35,10 +39,15 @@ const INCLUDES: &str = " // this must be included after ssl.h for libressl! #include -#if !defined(LIBRESSL_VERSION_NUMBER) +#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) #include #endif +#if !defined(OPENSSL_IS_BORINGSSL) +#include +#include +#endif + #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000 #include #endif @@ -48,6 +57,7 @@ const INCLUDES: &str = " #endif "; +#[cfg(feature = "bindgen")] pub fn run(include_dirs: &[PathBuf]) { let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); @@ -94,9 +104,113 @@ pub fn run(include_dirs: &[PathBuf]) { .unwrap(); } +#[cfg(feature = "bindgen")] +pub fn run_boringssl(include_dirs: &[PathBuf]) { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + 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(".*/openssl/[^/]+\\.h") + .allowlist_recursively(false) + .blocklist_function("BIO_vsnprintf") + .blocklist_function("OPENSSL_vasprintf") + .wrap_static_fns(true) + .wrap_static_fns_path(out_dir.join("boring_static_wrapper").display().to_string()) + .layout_tests(false) + .header_contents("includes.h", INCLUDES); + + 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(); + + fs::File::create(out_dir.join("boring_static_wrapper.h")) + .expect("Failed to create boring_static_wrapper.h") + .write_all(INCLUDES.as_bytes()) + .expect("Failed to write contents to boring_static_wrapper.h"); + + cc::Build::new() + .file(out_dir.join("boring_static_wrapper.c")) + .includes(include_dirs) + .flag("-include") + .flag( + &out_dir + .join("boring_static_wrapper.h") + .display() + .to_string(), + ) + .compile("boring_static_wrapper"); +} + +#[cfg(not(feature = "bindgen"))] +pub fn run_boringssl(include_dirs: &[PathBuf]) { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + fs::File::create(out_dir.join("boring_static_wrapper.h")) + .expect("Failed to create boring_static_wrapper.h") + .write_all(INCLUDES.as_bytes()) + .expect("Failed to write contents to boring_static_wrapper.h"); + + let mut bindgen_cmd = process::Command::new("bindgen"); + bindgen_cmd + .arg("-o") + .arg(out_dir.join("bindgen.rs")) + .arg("--rust-target=1.56") + .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("--allowlist-file=.*/openssl/[^/]+\\.h") + .arg("--no-recursive-allowlist") + .arg("--blocklist-function=BIO_vsnprintf") + .arg("--blocklist-function=OPENSSL_vasprintf") + .arg("--experimental") + .arg("--wrap-static-fns") + .arg("--wrap-static-fns-path") + .arg(out_dir.join("boring_static_wrapper").display().to_string()) + .arg("--no-layout-tests") + .arg(out_dir.join("boring_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("boring_static_wrapper.c")) + .includes(include_dirs) + .flag("-include") + .flag( + &out_dir + .join("boring_static_wrapper.h") + .display() + .to_string(), + ) + .compile("boring_static_wrapper"); +} + #[derive(Debug)] struct OpensslCallbacks; +#[cfg(feature = "bindgen")] impl ParseCallbacks for OpensslCallbacks { // for now we'll continue hand-writing constants fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior { diff --git a/openssl-sys/src/asn1.rs b/openssl-sys/src/asn1.rs index a5106d4676..caf14f7b96 100644 --- a/openssl-sys/src/asn1.rs +++ b/openssl-sys/src/asn1.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::*; // ASN.1 tag values pub const V_ASN1_EOC: c_int = 0; diff --git a/openssl-sys/src/bio.rs b/openssl-sys/src/bio.rs index b4beab6ca1..ea6053b592 100644 --- a/openssl-sys/src/bio.rs +++ b/openssl-sys/src/bio.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::*; pub const BIO_TYPE_NONE: c_int = 0; diff --git a/openssl-sys/src/bn.rs b/openssl-sys/src/bn.rs index f7393d0f50..a6bbcce883 100644 --- a/openssl-sys/src/bn.rs +++ b/openssl-sys/src/bn.rs @@ -1,7 +1,5 @@ use libc::*; -use *; - #[cfg(target_pointer_width = "64")] pub type BN_ULONG = c_ulonglong; #[cfg(target_pointer_width = "32")] diff --git a/openssl-sys/src/cms.rs b/openssl-sys/src/cms.rs index 59c770e5dc..f008adb1c7 100644 --- a/openssl-sys/src/cms.rs +++ b/openssl-sys/src/cms.rs @@ -1,5 +1,4 @@ use libc::*; -use *; #[cfg(ossl101)] pub const CMS_TEXT: c_uint = 0x1; diff --git a/openssl-sys/src/crypto.rs b/openssl-sys/src/crypto.rs index 842faa4e2f..35be07eada 100644 --- a/openssl-sys/src/crypto.rs +++ b/openssl-sys/src/crypto.rs @@ -1,5 +1,5 @@ +use super::*; use libc::*; -use *; extern "C" { #[deprecated(note = "use CRYPTO_set_locking_callback__fixed_rust instead")] diff --git a/openssl-sys/src/ec.rs b/openssl-sys/src/ec.rs index c01d6f22af..995a84ff64 100644 --- a/openssl-sys/src/ec.rs +++ b/openssl-sys/src/ec.rs @@ -1,7 +1,7 @@ use libc::*; use std::ptr; -use *; +use super::*; pub const OPENSSL_EC_NAMED_CURVE: c_int = 1; diff --git a/openssl-sys/src/err.rs b/openssl-sys/src/err.rs index 5e84e6208a..4a6a2775e4 100644 --- a/openssl-sys/src/err.rs +++ b/openssl-sys/src/err.rs @@ -20,51 +20,47 @@ cfg_if! { pub const ERR_RFLAG_FATAL: c_ulong = 0x1 << ERR_RFLAGS_OFFSET; - const_fn! { - pub const fn ERR_SYSTEM_ERROR(errcode: c_ulong) -> bool { - errcode & ERR_SYSTEM_FLAG != 0 - } + pub const fn ERR_SYSTEM_ERROR(errcode: c_ulong) -> bool { + errcode & ERR_SYSTEM_FLAG != 0 + } - pub const fn ERR_GET_LIB(errcode: c_ulong) -> c_int { - // hacks since `if` isn't yet stable in const functions :( - ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | - (((errcode >> ERR_LIB_OFFSET) & ERR_LIB_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int - } + pub const fn ERR_GET_LIB(errcode: c_ulong) -> c_int { + // hacks since `if` isn't yet stable in const functions :( + ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | + (((errcode >> ERR_LIB_OFFSET) & ERR_LIB_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int + } - pub const fn ERR_GET_FUNC(_errcode: c_ulong) -> c_int { - 0 - } + pub const fn ERR_GET_FUNC(_errcode: c_ulong) -> c_int { + 0 + } - pub const fn ERR_GET_REASON(errcode: c_ulong) -> c_int { - // hacks since `if` isn't yet stable in const functions :( - ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | - ((errcode & ERR_REASON_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int - } + pub const fn ERR_GET_REASON(errcode: c_ulong) -> c_int { + // hacks since `if` isn't yet stable in const functions :( + ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | + ((errcode & ERR_REASON_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int + } - pub const fn ERR_PACK(lib: c_int, _func: c_int, reason: c_int) -> c_ulong { - ((lib as c_ulong & ERR_LIB_MASK) << ERR_LIB_OFFSET) | - (reason as c_ulong & ERR_REASON_MASK) - } + pub const fn ERR_PACK(lib: c_int, _func: c_int, reason: c_int) -> c_ulong { + ((lib as c_ulong & ERR_LIB_MASK) << ERR_LIB_OFFSET) | + (reason as c_ulong & ERR_REASON_MASK) } } else { - const_fn! { - pub const fn ERR_PACK(l: c_int, f: c_int, r: c_int) -> c_ulong { - ((l as c_ulong & 0x0FF) << 24) | - ((f as c_ulong & 0xFFF) << 12) | - (r as c_ulong & 0xFFF) - } + pub const fn ERR_PACK(l: c_int, f: c_int, r: c_int) -> c_ulong { + ((l as c_ulong & 0x0FF) << 24) | + ((f as c_ulong & 0xFFF) << 12) | + (r as c_ulong & 0xFFF) + } - pub const fn ERR_GET_LIB(l: c_ulong) -> c_int { - ((l >> 24) & 0x0FF) as c_int - } + pub const fn ERR_GET_LIB(l: c_ulong) -> c_int { + ((l >> 24) & 0x0FF) as c_int + } - pub const fn ERR_GET_FUNC(l: c_ulong) -> c_int { - ((l >> 12) & 0xFFF) as c_int - } + pub const fn ERR_GET_FUNC(l: c_ulong) -> c_int { + ((l >> 12) & 0xFFF) as c_int + } - pub const fn ERR_GET_REASON(l: c_ulong) -> c_int { - (l & 0xFFF) as c_int - } + pub const fn ERR_GET_REASON(l: c_ulong) -> c_int { + (l & 0xFFF) as c_int } } } diff --git a/openssl-sys/src/evp.rs b/openssl-sys/src/evp.rs index fc3003f7bd..56eaa4bbff 100644 --- a/openssl-sys/src/evp.rs +++ b/openssl-sys/src/evp.rs @@ -1,5 +1,5 @@ +use super::*; use libc::*; -use *; pub const EVP_MAX_MD_SIZE: c_uint = 64; @@ -11,8 +11,10 @@ pub const EVP_PKEY_DSA: c_int = NID_dsa; pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; #[cfg(ossl111)] +pub const EVP_PKEY_SM2: c_int = NID_sm2; +#[cfg(any(ossl111, libressl370))] pub const EVP_PKEY_X25519: c_int = NID_X25519; -#[cfg(ossl111)] +#[cfg(any(ossl111, libressl370))] pub const EVP_PKEY_ED25519: c_int = NID_ED25519; #[cfg(ossl111)] pub const EVP_PKEY_X448: c_int = NID_X448; @@ -20,6 +22,8 @@ pub const EVP_PKEY_X448: c_int = NID_X448; pub const EVP_PKEY_ED448: c_int = NID_ED448; pub const EVP_PKEY_HMAC: c_int = NID_hmac; pub const EVP_PKEY_CMAC: c_int = NID_cmac; +#[cfg(ossl111)] +pub const EVP_PKEY_POLY1305: c_int = NID_poly1305; #[cfg(ossl110)] pub const EVP_PKEY_HKDF: c_int = NID_hkdf; @@ -143,6 +147,11 @@ cfg_if! { pub unsafe fn EVP_PKEY_bits(pkey: *const EVP_PKEY) -> c_int { EVP_PKEY_get_bits(pkey) } + + #[inline] + pub unsafe fn EVP_PKEY_security_bits(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_security_bits(pkey) + } } } @@ -278,3 +287,19 @@ pub unsafe fn EVP_PKEY_CTX_add1_hkdf_info( info as *mut c_void, ) } + +pub unsafe fn EVP_PKEY_assign_RSA(pkey: *mut EVP_PKEY, rsa: *mut RSA) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_RSA, rsa as *mut c_void) +} + +pub unsafe fn EVP_PKEY_assign_DSA(pkey: *mut EVP_PKEY, dsa: *mut DSA) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_DSA, dsa as *mut c_void) +} + +pub unsafe fn EVP_PKEY_assign_DH(pkey: *mut EVP_PKEY, dh: *mut DH) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_DH, dh as *mut c_void) +} + +pub unsafe fn EVP_PKEY_assign_EC_KEY(pkey: *mut EVP_PKEY, ec_key: *mut EC_KEY) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_EC, ec_key as *mut c_void) +} diff --git a/openssl-sys/src/handwritten/aes.rs b/openssl-sys/src/handwritten/aes.rs index 241848eccf..ba249362cb 100644 --- a/openssl-sys/src/handwritten/aes.rs +++ b/openssl-sys/src/handwritten/aes.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; #[repr(C)] pub struct AES_KEY { @@ -12,6 +12,7 @@ extern "C" { pub fn AES_set_encrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] pub fn AES_ige_encrypt( in_: *const c_uchar, out: *mut c_uchar, diff --git a/openssl-sys/src/handwritten/asn1.rs b/openssl-sys/src/handwritten/asn1.rs index 844f9102a9..16ffcccfe7 100644 --- a/openssl-sys/src/handwritten/asn1.rs +++ b/openssl-sys/src/handwritten/asn1.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; #[repr(C)] pub struct ASN1_ENCODING { @@ -10,23 +10,60 @@ pub struct ASN1_ENCODING { extern "C" { pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); + pub fn OBJ_dup(x: *const ASN1_OBJECT) -> *mut ASN1_OBJECT; } stack!(stack_st_ASN1_OBJECT); +#[repr(C)] +pub struct ASN1_TYPE { + pub type_: c_int, + pub value: ASN1_TYPE_value, +} +#[repr(C)] +pub union ASN1_TYPE_value { + pub ptr: *mut c_char, + pub boolean: ASN1_BOOLEAN, + pub asn1_string: *mut ASN1_STRING, + pub object: *mut ASN1_OBJECT, + pub integer: *mut ASN1_INTEGER, + pub enumerated: *mut ASN1_ENUMERATED, + pub bit_string: *mut ASN1_BIT_STRING, + pub octet_string: *mut ASN1_OCTET_STRING, + pub printablestring: *mut ASN1_PRINTABLESTRING, + pub t61string: *mut ASN1_T61STRING, + pub ia5string: *mut ASN1_IA5STRING, + pub generalstring: *mut ASN1_GENERALSTRING, + pub bmpstring: *mut ASN1_BMPSTRING, + pub universalstring: *mut ASN1_UNIVERSALSTRING, + pub utctime: *mut ASN1_UTCTIME, + pub generalizedtime: *mut ASN1_GENERALIZEDTIME, + pub visiblestring: *mut ASN1_VISIBLESTRING, + pub utf8string: *mut ASN1_UTF8STRING, + pub set: *mut ASN1_STRING, + pub sequence: *mut ASN1_STRING, + pub asn1_value: *mut ASN1_VALUE, +} + extern "C" { pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; #[cfg(any(ossl110, libressl273))] pub fn ASN1_STRING_get0_data(x: *const ASN1_STRING) -> *const c_uchar; #[cfg(any(all(ossl101, not(ossl110)), libressl))] pub fn ASN1_STRING_data(x: *mut ASN1_STRING) -> *mut c_uchar; - - pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); - + pub fn ASN1_STRING_new() -> *mut ASN1_STRING; + pub fn ASN1_OCTET_STRING_new() -> *mut ASN1_OCTET_STRING; pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len_in: c_int) -> c_int; + pub fn ASN1_OCTET_STRING_set( + x: *mut ASN1_OCTET_STRING, + data: *const c_uchar, + len_in: c_int, + ) -> c_int; - pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len: c_int) -> c_int; + pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); + pub fn ASN1_OCTET_STRING_free(x: *mut ASN1_OCTET_STRING); pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; @@ -43,18 +80,36 @@ extern "C" { pub fn ASN1_TIME_set(from: *mut ASN1_TIME, to: time_t) -> *mut ASN1_TIME; pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER); + pub fn ASN1_INTEGER_dup(a: *const ASN1_INTEGER) -> *mut ASN1_INTEGER; pub fn ASN1_INTEGER_get(dest: *const ASN1_INTEGER) -> c_long; pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; + pub fn ASN1_INTEGER_cmp(a: *const ASN1_INTEGER, b: *const ASN1_INTEGER) -> c_int; pub fn BN_to_ASN1_INTEGER(bn: *const BIGNUM, ai: *mut ASN1_INTEGER) -> *mut ASN1_INTEGER; pub fn ASN1_INTEGER_to_BN(ai: *const ASN1_INTEGER, bn: *mut BIGNUM) -> *mut BIGNUM; pub fn ASN1_TIME_set_string(s: *mut ASN1_TIME, str: *const c_char) -> c_int; #[cfg(ossl111)] pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; + + pub fn ASN1_ENUMERATED_free(a: *mut ASN1_ENUMERATED); + #[cfg(ossl110)] + pub fn ASN1_ENUMERATED_get_int64(pr: *mut i64, a: *const ASN1_ENUMERATED) -> c_int; + + pub fn ASN1_TYPE_new() -> *mut ASN1_TYPE; + pub fn ASN1_TYPE_set(a: *mut ASN1_TYPE, type_: c_int, value: *mut c_void); + pub fn ASN1_TYPE_free(x: *mut ASN1_TYPE); + pub fn d2i_ASN1_TYPE( + k: *mut *mut ASN1_TYPE, + buf: *mut *const u8, + len: c_long, + ) -> *mut ASN1_TYPE; } const_ptr_api! { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_STRING_type(x: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_generate_v3(str: #[const_ptr_if(any(ossl110, libressl280))] c_char, cnf: *mut X509V3_CTX) -> *mut ASN1_TYPE; + pub fn i2d_ASN1_TYPE(a: #[const_ptr_if(ossl300)] ASN1_TYPE, pp: *mut *mut c_uchar) -> c_int; } } diff --git a/openssl-sys/src/handwritten/bio.rs b/openssl-sys/src/handwritten/bio.rs index 7241df0f3e..7d97522251 100644 --- a/openssl-sys/src/handwritten/bio.rs +++ b/openssl-sys/src/handwritten/bio.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; extern "C" { pub fn BIO_set_flags(b: *mut BIO, flags: c_int); @@ -17,14 +17,14 @@ cfg_if! { pub struct BIO_METHOD { pub type_: c_int, pub name: *const c_char, - pub bwrite: Option c_int>, - pub bread: Option c_int>, - pub bputs: Option c_int>, - pub bgets: Option c_int>, - pub ctrl: Option c_long>, - pub create: Option c_int>, - pub destroy: Option c_int>, - pub callback_ctrl: Option c_long>, + pub bwrite: Option c_int>, + pub bread: Option c_int>, + pub bputs: Option c_int>, + pub bgets: Option c_int>, + pub ctrl: Option c_long>, + pub create: Option c_int>, + pub destroy: Option c_int>, + pub callback_ctrl: Option c_long>, } } } @@ -39,11 +39,11 @@ extern "C" { #[cfg(not(osslconf = "OPENSSL_NO_STDIO"))] pub fn BIO_new_fp(stream: *mut FILE, close_flag: c_int) -> *mut BIO; #[cfg(any(ossl110, libressl273))] - pub fn BIO_set_data(a: *mut ::BIO, data: *mut c_void); + pub fn BIO_set_data(a: *mut BIO, data: *mut c_void); #[cfg(any(ossl110, libressl273))] - pub fn BIO_get_data(a: *mut ::BIO) -> *mut c_void; + pub fn BIO_get_data(a: *mut BIO) -> *mut c_void; #[cfg(any(ossl110, libressl273))] - pub fn BIO_set_init(a: *mut ::BIO, init: c_int); + pub fn BIO_set_init(a: *mut BIO, init: c_int); pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; diff --git a/openssl-sys/src/handwritten/bn.rs b/openssl-sys/src/handwritten/bn.rs index d523f24d34..5457f61710 100644 --- a/openssl-sys/src/handwritten/bn.rs +++ b/openssl-sys/src/handwritten/bn.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; extern "C" { pub fn BN_CTX_new() -> *mut BN_CTX; @@ -7,8 +7,10 @@ extern "C" { pub fn BN_CTX_secure_new() -> *mut BN_CTX; pub fn BN_CTX_free(ctx: *mut BN_CTX); pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; pub fn BN_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; pub fn BN_new() -> *mut BIGNUM; #[cfg(ossl110)] @@ -21,7 +23,7 @@ extern "C" { pub fn BN_clear_free(bn: *mut BIGNUM); pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; pub fn BN_bn2bin(a: *const BIGNUM, to: *mut u8) -> c_int; - #[cfg(ossl110)] + #[cfg(any(ossl110, libressl340))] pub fn BN_bn2binpad(a: *const BIGNUM, to: *mut u8, tolen: c_int) -> c_int; pub fn BN_sub(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; pub fn BN_add(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; @@ -29,7 +31,7 @@ extern "C" { pub fn BN_sqr(r: *mut BIGNUM, a: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); #[cfg(any(ossl110, libressl350))] - pub fn BN_is_negative(b: *const ::BIGNUM) -> c_int; + pub fn BN_is_negative(b: *const BIGNUM) -> c_int; pub fn BN_div( dv: *mut BIGNUM, @@ -122,12 +124,14 @@ extern "C" { rem: *const BIGNUM, cb: *mut BN_GENCB, ) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] pub fn BN_is_prime_ex( p: *const BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *mut BN_GENCB, ) -> c_int; + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] pub fn BN_is_prime_fasttest_ex( p: *const BIGNUM, checks: c_int, diff --git a/openssl-sys/src/handwritten/cmac.rs b/openssl-sys/src/handwritten/cmac.rs new file mode 100644 index 0000000000..e44094d21a --- /dev/null +++ b/openssl-sys/src/handwritten/cmac.rs @@ -0,0 +1,18 @@ +use libc::*; + +use super::super::*; + +extern "C" { + pub fn CMAC_CTX_new() -> *mut CMAC_CTX; + pub fn CMAC_CTX_free(ctx: *mut CMAC_CTX); + pub fn CMAC_Init( + ctx: *mut CMAC_CTX, + key: *const c_void, + len: size_t, + cipher: *const EVP_CIPHER, + impl_: *mut ENGINE, + ) -> c_int; + pub fn CMAC_Update(ctx: *mut CMAC_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn CMAC_Final(ctx: *mut CMAC_CTX, out: *mut c_uchar, len: *mut size_t) -> c_int; + pub fn CMAC_CTX_copy(dst: *mut CMAC_CTX, src: *const CMAC_CTX) -> c_int; +} diff --git a/openssl-sys/src/handwritten/cms.rs b/openssl-sys/src/handwritten/cms.rs index 291bc798b7..a13ea423c4 100644 --- a/openssl-sys/src/handwritten/cms.rs +++ b/openssl-sys/src/handwritten/cms.rs @@ -1,11 +1,11 @@ +use super::super::*; use libc::*; -use *; pub enum CMS_ContentInfo {} extern "C" { #[cfg(ossl101)] - pub fn CMS_ContentInfo_free(cms: *mut ::CMS_ContentInfo); + pub fn CMS_ContentInfo_free(cms: *mut CMS_ContentInfo); } const_ptr_api! { @@ -18,38 +18,48 @@ const_ptr_api! { extern "C" { #[cfg(ossl101)] pub fn d2i_CMS_ContentInfo( - a: *mut *mut ::CMS_ContentInfo, + a: *mut *mut CMS_ContentInfo, pp: *mut *const c_uchar, length: c_long, - ) -> *mut ::CMS_ContentInfo; + ) -> *mut CMS_ContentInfo; #[cfg(ossl101)] - pub fn SMIME_read_CMS(bio: *mut ::BIO, bcont: *mut *mut ::BIO) -> *mut ::CMS_ContentInfo; + pub fn SMIME_read_CMS(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut CMS_ContentInfo; #[cfg(ossl101)] pub fn CMS_sign( - signcert: *mut ::X509, - pkey: *mut ::EVP_PKEY, - certs: *mut ::stack_st_X509, - data: *mut ::BIO, + signcert: *mut X509, + pkey: *mut EVP_PKEY, + certs: *mut stack_st_X509, + data: *mut BIO, + flags: c_uint, + ) -> *mut CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn CMS_verify( + cms: *mut CMS_ContentInfo, + certs: *mut stack_st_X509, + store: *mut X509_STORE, + detached_data: *mut BIO, + out: *mut BIO, flags: c_uint, - ) -> *mut ::CMS_ContentInfo; + ) -> c_int; #[cfg(ossl101)] pub fn CMS_encrypt( certs: *mut stack_st_X509, - data: *mut ::BIO, + data: *mut BIO, cipher: *const EVP_CIPHER, flags: c_uint, - ) -> *mut ::CMS_ContentInfo; + ) -> *mut CMS_ContentInfo; #[cfg(ossl101)] pub fn CMS_decrypt( - cms: *mut ::CMS_ContentInfo, - pkey: *mut ::EVP_PKEY, - cert: *mut ::X509, - dcont: *mut ::BIO, - out: *mut ::BIO, + cms: *mut CMS_ContentInfo, + pkey: *mut EVP_PKEY, + cert: *mut X509, + dcont: *mut BIO, + out: *mut BIO, flags: c_uint, ) -> c_int; } diff --git a/openssl-sys/src/handwritten/conf.rs b/openssl-sys/src/handwritten/conf.rs index 9b9d4b26ff..2348d7d4c9 100644 --- a/openssl-sys/src/handwritten/conf.rs +++ b/openssl-sys/src/handwritten/conf.rs @@ -1,4 +1,4 @@ -use *; +use super::super::*; extern "C" { pub fn NCONF_new(meth: *mut CONF_METHOD) -> *mut CONF; diff --git a/openssl-sys/src/handwritten/crypto.rs b/openssl-sys/src/handwritten/crypto.rs index ab17d2fa9e..62ccbce1ec 100644 --- a/openssl-sys/src/handwritten/crypto.rs +++ b/openssl-sys/src/handwritten/crypto.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; stack!(stack_st_void); diff --git a/openssl-sys/src/handwritten/dh.rs b/openssl-sys/src/handwritten/dh.rs index d55326bc80..87a0817ce5 100644 --- a/openssl-sys/src/handwritten/dh.rs +++ b/openssl-sys/src/handwritten/dh.rs @@ -1,8 +1,9 @@ -use *; +use super::super::*; extern "C" { pub fn DH_new() -> *mut DH; pub fn DH_free(dh: *mut DH); + pub fn DH_check(dh: *const DH, codes: *mut c_int) -> c_int; pub fn DH_generate_parameters( prime_len: c_int, diff --git a/openssl-sys/src/handwritten/dsa.rs b/openssl-sys/src/handwritten/dsa.rs index c676c6b0ad..be25f23b67 100644 --- a/openssl-sys/src/handwritten/dsa.rs +++ b/openssl-sys/src/handwritten/dsa.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::super::*; cfg_if! { if #[cfg(any(ossl110, libressl280))] { diff --git a/openssl-sys/src/handwritten/ec.rs b/openssl-sys/src/handwritten/ec.rs index ed0b1a7074..182a5559a3 100644 --- a/openssl-sys/src/handwritten/ec.rs +++ b/openssl-sys/src/handwritten/ec.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; #[repr(C)] #[derive(Copy, Clone)] @@ -46,6 +46,8 @@ extern "C" { pub fn EC_GROUP_set_asn1_flag(key: *mut EC_GROUP, flag: c_int); + pub fn EC_GROUP_get_asn1_flag(group: *const EC_GROUP) -> c_int; + pub fn EC_GROUP_get_curve_GFp( group: *const EC_GROUP, p: *mut BIGNUM, @@ -99,7 +101,7 @@ extern "C" { pub fn EC_POINT_dup(p: *const EC_POINT, group: *const EC_GROUP) -> *mut EC_POINT; - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl350))] pub fn EC_POINT_get_affine_coordinates( group: *const EC_GROUP, p: *const EC_POINT, diff --git a/openssl-sys/src/handwritten/err.rs b/openssl-sys/src/handwritten/err.rs index d8f36e4970..5653c1d18a 100644 --- a/openssl-sys/src/handwritten/err.rs +++ b/openssl-sys/src/handwritten/err.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; #[repr(C)] pub struct ERR_STRING_DATA { diff --git a/openssl-sys/src/handwritten/evp.rs b/openssl-sys/src/handwritten/evp.rs index a85d628ade..4041d8b671 100644 --- a/openssl-sys/src/handwritten/evp.rs +++ b/openssl-sys/src/handwritten/evp.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; cfg_if! { if #[cfg(ossl300)] { @@ -65,6 +65,14 @@ cfg_if! { } } +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn EVP_default_properties_is_fips_enabled(libctx: *mut OSSL_LIB_CTX) -> c_int; + } + } +} + extern "C" { pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *mut ENGINE) -> c_int; @@ -230,7 +238,7 @@ cfg_if! { } } cfg_if! { - if #[cfg(ossl111)] { + if #[cfg(any(ossl111, libressl370))] { extern "C" { pub fn EVP_DigestSign( ctx: *mut EVP_MD_CTX, @@ -303,6 +311,7 @@ extern "C" { pub fn EVP_des_ede3_cbc() -> *const EVP_CIPHER; pub fn EVP_des_ede3_cfb64() -> *const EVP_CIPHER; pub fn EVP_des_cbc() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn EVP_rc4() -> *const EVP_CIPHER; pub fn EVP_bf_ecb() -> *const EVP_CIPHER; pub fn EVP_bf_cbc() -> *const EVP_CIPHER; @@ -344,9 +353,9 @@ extern "C" { #[cfg(ossl110)] pub fn EVP_aes_256_ocb() -> *const EVP_CIPHER; #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] - pub fn EVP_chacha20() -> *const ::EVP_CIPHER; + pub fn EVP_chacha20() -> *const EVP_CIPHER; #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] - pub fn EVP_chacha20_poly1305() -> *const ::EVP_CIPHER; + pub fn EVP_chacha20_poly1305() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn EVP_seed_cbc() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] @@ -380,9 +389,9 @@ extern "C" { #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))] pub fn EVP_camellia_256_ecb() -> *const EVP_CIPHER; - #[cfg(not(boringssl))] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] pub fn EVP_cast5_cfb64() -> *const EVP_CIPHER; - #[cfg(not(boringssl))] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] pub fn EVP_cast5_ecb() -> *const EVP_CIPHER; #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_IDEA")))] @@ -402,6 +411,7 @@ cfg_if! { extern "C" { pub fn EVP_PKEY_get_id(pkey: *const EVP_PKEY) -> c_int; pub fn EVP_PKEY_get_bits(key: *const EVP_PKEY) -> c_int; + pub fn EVP_PKEY_get_security_bits(key: *const EVP_PKEY) -> c_int; } #[inline] @@ -413,6 +423,12 @@ cfg_if! { pub unsafe fn EVP_PKEY_bits(pkey: *const EVP_PKEY) -> c_int { EVP_PKEY_get_bits(pkey) } + + #[inline] + pub unsafe fn EVP_PKEY_security_bits(pkey: *const EVP_PKEY) -> c_int { + EVP_PKEY_get_security_bits(pkey) + } + } else { extern "C" { pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int; @@ -420,6 +436,8 @@ cfg_if! { const_ptr_api! { extern "C" { pub fn EVP_PKEY_bits(key: #[const_ptr_if(any(ossl110, libressl280))] EVP_PKEY) -> c_int; + #[cfg(any(ossl110, libressl360))] + pub fn EVP_PKEY_security_bits(pkey: #[const_ptr_if(any(ossl110, libressl280))] EVP_PKEY) -> c_int; } } } @@ -504,6 +522,12 @@ extern "C" { pub fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int; pub fn EVP_PKEY_derive_set_peer(ctx: *mut EVP_PKEY_CTX, peer: *mut EVP_PKEY) -> c_int; + #[cfg(ossl300)] + pub fn EVP_PKEY_derive_set_peer_ex( + ctx: *mut EVP_PKEY_CTX, + peer: *mut EVP_PKEY, + validate_peer: c_int, + ) -> c_int; pub fn EVP_PKEY_derive(ctx: *mut EVP_PKEY_CTX, key: *mut c_uchar, size: *mut size_t) -> c_int; #[cfg(ossl300)] @@ -557,7 +581,7 @@ const_ptr_api! { } cfg_if! { - if #[cfg(any(ossl111))] { + if #[cfg(any(ossl111, libressl370))] { extern "C" { pub fn EVP_PKEY_get_raw_public_key( pkey: *const EVP_PKEY, diff --git a/openssl-sys/src/handwritten/hmac.rs b/openssl-sys/src/handwritten/hmac.rs index 7cbb7cc9ad..b52d63fb1f 100644 --- a/openssl-sys/src/handwritten/hmac.rs +++ b/openssl-sys/src/handwritten/hmac.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::super::*; cfg_if! { if #[cfg(any(ossl110, libressl350))] { diff --git a/openssl-sys/src/handwritten/kdf.rs b/openssl-sys/src/handwritten/kdf.rs index b8e6c63bb1..0f14b63a9c 100644 --- a/openssl-sys/src/handwritten/kdf.rs +++ b/openssl-sys/src/handwritten/kdf.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; cfg_if! { if #[cfg(ossl300)] { diff --git a/openssl-sys/src/handwritten/mod.rs b/openssl-sys/src/handwritten/mod.rs index 28aa4aecd0..9c0f844501 100644 --- a/openssl-sys/src/handwritten/mod.rs +++ b/openssl-sys/src/handwritten/mod.rs @@ -2,6 +2,7 @@ pub use self::aes::*; pub use self::asn1::*; pub use self::bio::*; pub use self::bn::*; +pub use self::cmac::*; pub use self::cms::*; pub use self::conf::*; pub use self::crypto::*; @@ -35,6 +36,7 @@ mod aes; mod asn1; mod bio; mod bn; +mod cmac; mod cms; mod conf; mod crypto; diff --git a/openssl-sys/src/handwritten/object.rs b/openssl-sys/src/handwritten/object.rs index d2c525b806..6160fad5b3 100644 --- a/openssl-sys/src/handwritten/object.rs +++ b/openssl-sys/src/handwritten/object.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::super::*; extern "C" { pub fn OBJ_nid2ln(nid: c_int) -> *const c_char; @@ -27,4 +27,5 @@ extern "C" { pub fn OBJ_length(obj: *const ASN1_OBJECT) -> libc::size_t; #[cfg(ossl111)] pub fn OBJ_get0_data(obj: *const ASN1_OBJECT) -> *const c_uchar; + pub fn OBJ_cmp(a: *const ASN1_OBJECT, b: *const ASN1_OBJECT) -> c_int; } diff --git a/openssl-sys/src/handwritten/ocsp.rs b/openssl-sys/src/handwritten/ocsp.rs index bb194c2860..c194a831b9 100644 --- a/openssl-sys/src/handwritten/ocsp.rs +++ b/openssl-sys/src/handwritten/ocsp.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; pub enum OCSP_CERTID {} diff --git a/openssl-sys/src/handwritten/pem.rs b/openssl-sys/src/handwritten/pem.rs index ebce932b6c..42997177e4 100644 --- a/openssl-sys/src/handwritten/pem.rs +++ b/openssl-sys/src/handwritten/pem.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; pub type pem_password_cb = Option< unsafe extern "C" fn( diff --git a/openssl-sys/src/handwritten/pkcs12.rs b/openssl-sys/src/handwritten/pkcs12.rs index 792ab3527a..728c333ad2 100644 --- a/openssl-sys/src/handwritten/pkcs12.rs +++ b/openssl-sys/src/handwritten/pkcs12.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::super::*; pub enum PKCS12 {} diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs index fc0239e7b8..f46922df33 100644 --- a/openssl-sys/src/handwritten/pkcs7.rs +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -1,12 +1,149 @@ +use super::super::*; use libc::*; -use *; -pub enum PKCS7_SIGNED {} -pub enum PKCS7_ENVELOPE {} -pub enum PKCS7_SIGN_ENVELOPE {} -pub enum PKCS7_DIGEST {} -pub enum PKCS7_ENCRYPT {} -pub enum PKCS7 {} +#[cfg(ossl300)] +#[repr(C)] +pub struct PKCS7_CTX { + libctx: *mut OSSL_LIB_CTX, + propq: *mut c_char, +} + +#[repr(C)] +pub struct PKCS7_SIGNED { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub contents: *mut PKCS7, +} +#[repr(C)] +pub struct PKCS7_ENC_CONTENT { + pub content_type: *mut ASN1_OBJECT, + pub algorithm: *mut X509_ALGOR, + pub enc_data: *mut ASN1_OCTET_STRING, /* [ 0 ] */ + pub cipher: *const EVP_CIPHER, + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, +} +#[repr(C)] +pub struct PKCS7_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, +} +#[repr(C)] +pub struct PKCS7_SIGN_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, +} +#[repr(C)] +pub struct PKCS7_DIGEST { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub md: *mut X509_ALGOR, /* md used */ + pub contents: *mut PKCS7, + pub digest: *mut ASN1_OCTET_STRING, +} +#[repr(C)] +pub struct PKCS7_ENCRYPT { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub enc_data: *mut PKCS7_ENC_CONTENT, +} + +extern "C" { + pub fn PKCS7_SIGNED_free(info: *mut PKCS7_SIGNED); + pub fn PKCS7_ENC_CONTENT_free(info: *mut PKCS7_ENC_CONTENT); + pub fn PKCS7_ENVELOPE_free(info: *mut PKCS7_ENVELOPE); + pub fn PKCS7_SIGN_ENVELOPE_free(info: *mut PKCS7_SIGN_ENVELOPE); + pub fn PKCS7_DIGEST_free(info: *mut PKCS7_DIGEST); + pub fn PKCS7_SIGNER_INFO_free(info: *mut PKCS7_SIGNER_INFO); + pub fn PKCS7_ENCRYPT_free(enc: *mut PKCS7_ENCRYPT); + pub fn PKCS7_ISSUER_AND_SERIAL_free(ias: *mut PKCS7_ISSUER_AND_SERIAL); + pub fn PKCS7_RECIP_INFO_free(info: *mut PKCS7_RECIP_INFO); +} + +#[repr(C)] +pub struct PKCS7 { + /* + * The following is non NULL if it contains ASN1 encoding of this + * structure + */ + pub asn1: *mut c_uchar, + pub length: c_long, + // # define PKCS7_S_HEADER 0 + // # define PKCS7_S_BODY 1 + // # define PKCS7_S_TAIL 2 + pub state: c_int, /* used during processing */ + pub detached: c_int, + pub type_: *mut ASN1_OBJECT, + /* content as defined by the type */ + /* + * all encryption/message digests are applied to the 'contents', leaving + * out the 'type' field. + */ + pub d: PKCS7_data, + #[cfg(ossl300)] + pub ctx: PKCS7_CTX, +} + +#[repr(C)] +pub union PKCS7_data { + pub ptr: *mut c_char, + /* NID_pkcs7_data */ + pub data: *mut ASN1_OCTET_STRING, + /* NID_pkcs7_signed */ + pub sign: *mut PKCS7_SIGNED, + /* NID_pkcs7_enveloped */ + pub enveloped: *mut PKCS7_ENVELOPE, + /* NID_pkcs7_signedAndEnveloped */ + pub signed_and_enveloped: *mut PKCS7_SIGN_ENVELOPE, + /* NID_pkcs7_digest */ + pub digest: *mut PKCS7_DIGEST, + /* NID_pkcs7_encrypted */ + pub encrypted: *mut PKCS7_ENCRYPT, + /* Anything else */ + pub other: *mut ASN1_TYPE, +} + +#[repr(C)] +pub struct PKCS7_ISSUER_AND_SERIAL { + pub issuer: *mut X509_NAME, + pub serial: *mut ASN1_INTEGER, +} + +#[repr(C)] +pub struct PKCS7_SIGNER_INFO { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub digest_alg: *mut X509_ALGOR, + pub auth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 0 ] */ + pub digest_enc_alg: *mut X509_ALGOR, + pub enc_digest: *mut ASN1_OCTET_STRING, + pub unauth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 1 ] */ + pub pkey: *mut EVP_PKEY, /* The private key to sign with */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, +} + +stack!(stack_st_PKCS7_SIGNER_INFO); + +#[repr(C)] +pub struct PKCS7_RECIP_INFO { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub key_enc_algor: *mut X509_ALGOR, + pub enc_key: *mut ASN1_OCTET_STRING, + pub cert: *mut X509, /* get the pub-key from this */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, +} + +stack!(stack_st_PKCS7_RECIP_INFO); extern "C" { pub fn d2i_PKCS7(a: *mut *mut PKCS7, pp: *mut *const c_uchar, length: c_long) -> *mut PKCS7; @@ -15,6 +152,7 @@ extern "C" { const_ptr_api! { extern "C" { pub fn i2d_PKCS7(a: #[const_ptr_if(ossl300)] PKCS7, buf: *mut *mut u8) -> c_int; + pub fn i2d_PKCS7_bio(bio: *mut BIO, p7: #[const_ptr_if(ossl300)] PKCS7) -> c_int; } } @@ -67,4 +205,53 @@ extern "C" { ) -> c_int; pub fn SMIME_read_PKCS7(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut PKCS7; + + pub fn PKCS7_new() -> *mut PKCS7; + + pub fn PKCS7_set_type(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_add_certificate(p7: *mut PKCS7, x509: *mut X509) -> c_int; + + pub fn PKCS7_add_signature( + p7: *mut PKCS7, + x509: *mut X509, + pkey: *mut EVP_PKEY, + digest: *const EVP_MD, + ) -> *mut PKCS7_SIGNER_INFO; + + pub fn PKCS7_set_signed_attributes( + p7si: *mut PKCS7_SIGNER_INFO, + attributes: *mut stack_st_X509_ATTRIBUTE, + ) -> c_int; + + pub fn PKCS7_add_signed_attribute( + p7si: *mut PKCS7_SIGNER_INFO, + nid: c_int, + attrtype: c_int, + data: *mut c_void, + ) -> c_int; + + pub fn PKCS7_content_new(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_dataInit(p7: *mut PKCS7, bio: *mut BIO) -> *mut BIO; + + pub fn PKCS7_dataFinal(p7: *mut PKCS7, bio: *mut BIO) -> c_int; + + pub fn PKCS7_get_signer_info(p7: *mut PKCS7) -> *mut stack_st_PKCS7_SIGNER_INFO; + + pub fn PKCS7_SIGNER_INFO_get0_algs( + si: *mut PKCS7_SIGNER_INFO, + pk: *mut *mut EVP_PKEY, + pdig: *mut *mut X509_ALGOR, + psig: *mut *mut X509_ALGOR, + ); +} + +const_ptr_api! { + extern "C" { + pub fn PKCS7_get_signed_attribute( + si: #[const_ptr_if(ossl300)] PKCS7_SIGNER_INFO, + nid: c_int + ) -> *mut ASN1_TYPE; + } } diff --git a/openssl-sys/src/handwritten/provider.rs b/openssl-sys/src/handwritten/provider.rs index ffa7cc580e..3e18a02be7 100644 --- a/openssl-sys/src/handwritten/provider.rs +++ b/openssl-sys/src/handwritten/provider.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; extern "C" { #[cfg(ossl300)] @@ -12,4 +12,9 @@ extern "C" { ) -> *mut OSSL_PROVIDER; #[cfg(ossl300)] pub fn OSSL_PROVIDER_unload(prov: *mut OSSL_PROVIDER) -> c_int; + #[cfg(ossl300)] + pub fn OSSL_PROVIDER_set_default_search_path( + ctx: *mut OSSL_LIB_CTX, + path: *const c_char, + ) -> c_int; } diff --git a/openssl-sys/src/handwritten/rsa.rs b/openssl-sys/src/handwritten/rsa.rs index d2a1439bee..d05edfc301 100644 --- a/openssl-sys/src/handwritten/rsa.rs +++ b/openssl-sys/src/handwritten/rsa.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; cfg_if! { if #[cfg(ossl300)] { @@ -18,36 +18,31 @@ extern "C" { pub fn RSA_size(k: *const RSA) -> c_int; #[cfg(any(ossl110, libressl273))] - pub fn RSA_set0_key( - r: *mut ::RSA, - n: *mut ::BIGNUM, - e: *mut ::BIGNUM, - d: *mut ::BIGNUM, - ) -> c_int; + pub fn RSA_set0_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int; #[cfg(any(ossl110, libressl273))] - pub fn RSA_set0_factors(r: *mut ::RSA, p: *mut ::BIGNUM, q: *mut ::BIGNUM) -> c_int; + pub fn RSA_set0_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int; #[cfg(any(ossl110, libressl273))] pub fn RSA_set0_crt_params( - r: *mut ::RSA, - dmp1: *mut ::BIGNUM, - dmq1: *mut ::BIGNUM, - iqmp: *mut ::BIGNUM, + r: *mut RSA, + dmp1: *mut BIGNUM, + dmq1: *mut BIGNUM, + iqmp: *mut BIGNUM, ) -> c_int; #[cfg(any(ossl110, libressl273))] pub fn RSA_get0_key( - r: *const ::RSA, - n: *mut *const ::BIGNUM, - e: *mut *const ::BIGNUM, - d: *mut *const ::BIGNUM, + r: *const RSA, + n: *mut *const BIGNUM, + e: *mut *const BIGNUM, + d: *mut *const BIGNUM, ); #[cfg(any(ossl110, libressl273))] - pub fn RSA_get0_factors(r: *const ::RSA, p: *mut *const ::BIGNUM, q: *mut *const ::BIGNUM); + pub fn RSA_get0_factors(r: *const RSA, p: *mut *const BIGNUM, q: *mut *const BIGNUM); #[cfg(any(ossl110, libressl273))] pub fn RSA_get0_crt_params( - r: *const ::RSA, - dmp1: *mut *const ::BIGNUM, - dmq1: *mut *const ::BIGNUM, - iqmp: *mut *const ::BIGNUM, + r: *const RSA, + dmp1: *mut *const BIGNUM, + dmq1: *mut *const BIGNUM, + iqmp: *mut *const BIGNUM, ); #[cfg(not(ossl110))] @@ -93,7 +88,7 @@ extern "C" { k: *mut RSA, pad: c_int, ) -> c_int; - pub fn RSA_check_key(r: *const ::RSA) -> c_int; + pub fn RSA_check_key(r: *const RSA) -> c_int; pub fn RSA_free(rsa: *mut RSA); pub fn RSA_up_ref(rsa: *mut RSA) -> c_int; diff --git a/openssl-sys/src/handwritten/sha.rs b/openssl-sys/src/handwritten/sha.rs index 64fe2ce883..7d00b592f1 100644 --- a/openssl-sys/src/handwritten/sha.rs +++ b/openssl-sys/src/handwritten/sha.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; cfg_if! { if #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] { diff --git a/openssl-sys/src/handwritten/srtp.rs b/openssl-sys/src/handwritten/srtp.rs index 7500584be8..d4c7af8ebd 100644 --- a/openssl-sys/src/handwritten/srtp.rs +++ b/openssl-sys/src/handwritten/srtp.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; extern "C" { pub fn SSL_CTX_set_tlsext_use_srtp(ctx: *mut SSL_CTX, profiles: *const c_char) -> c_int; diff --git a/openssl-sys/src/handwritten/ssl.rs b/openssl-sys/src/handwritten/ssl.rs index 35b99de3b5..d4f4b619f4 100644 --- a/openssl-sys/src/handwritten/ssl.rs +++ b/openssl-sys/src/handwritten/ssl.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; pub enum SSL_METHOD {} pub enum SSL_CIPHER {} @@ -13,15 +13,15 @@ cfg_if! { pub master_key_length: c_int, pub master_key: [c_uchar; 48], session_id_length: c_uint, - session_id: [c_uchar; ::SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - peer: *mut ::X509, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + peer: *mut X509, verify_result: c_long, timeout: c_long, time: time_t, pub references: c_int, - cipher: *const ::SSL_CIPHER, + cipher: *const SSL_CIPHER, cipher_id: c_long, ciphers: *mut stack_st_SSL_CIPHER, tlsext_hostname: *mut c_char, @@ -50,7 +50,7 @@ cfg_if! { cipher: *const c_void, cipher_id: c_ulong, ciphers: *mut c_void, - ex_data: ::CRYPTO_EX_DATA, + ex_data: CRYPTO_EX_DATA, prev: *mut c_void, next: *mut c_void, tlsext_hostname: *mut c_char, @@ -93,7 +93,7 @@ cfg_if! { cipher: *const c_void, cipher_id: c_ulong, ciphers: *mut c_void, - ex_data: ::CRYPTO_EX_DATA, + ex_data: CRYPTO_EX_DATA, prev: *mut c_void, next: *mut c_void, #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] @@ -156,12 +156,12 @@ pub type tls_session_secret_cb_fn = Option< #[cfg(ossl111)] pub type SSL_custom_ext_add_cb_ex = Option< unsafe extern "C" fn( - ssl: *mut ::SSL, + ssl: *mut SSL, ext_type: c_uint, context: c_uint, out: *mut *const c_uchar, outlen: *mut size_t, - x: *mut ::X509, + x: *mut X509, chainidx: size_t, al: *mut c_int, add_arg: *mut c_void, @@ -171,7 +171,7 @@ pub type SSL_custom_ext_add_cb_ex = Option< #[cfg(ossl111)] pub type SSL_custom_ext_free_cb_ex = Option< unsafe extern "C" fn( - ssl: *mut ::SSL, + ssl: *mut SSL, ext_type: c_uint, context: c_uint, out: *const c_uchar, @@ -182,12 +182,12 @@ pub type SSL_custom_ext_free_cb_ex = Option< #[cfg(ossl111)] pub type SSL_custom_ext_parse_cb_ex = Option< unsafe extern "C" fn( - ssl: *mut ::SSL, + ssl: *mut SSL, ext_type: c_uint, context: c_uint, input: *const c_uchar, inlen: size_t, - x: *mut ::X509, + x: *mut X509, chainidx: size_t, al: *mut c_int, parse_arg: *mut c_void, @@ -228,18 +228,18 @@ cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn SSL_CTX_sess_set_get_cb( - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, get_session_cb: Option< - unsafe extern "C" fn(*mut ::SSL, *const c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, + unsafe extern "C" fn(*mut SSL, *const c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, >, ); } } else { extern "C" { pub fn SSL_CTX_sess_set_get_cb( - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, get_session_cb: Option< - unsafe extern "C" fn(*mut ::SSL, *mut c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, + unsafe extern "C" fn(*mut SSL, *mut c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, >, ); } @@ -391,7 +391,7 @@ extern "C" { extern "C" { #[cfg(ossl111)] pub fn SSL_CTX_add_custom_ext( - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, ext_type: c_uint, context: c_uint, add_cb: SSL_custom_ext_add_cb_ex, @@ -439,8 +439,8 @@ const_ptr_api! { cfg_if! { if #[cfg(libressl261)] { extern "C" { - pub fn SSL_CTX_set_min_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; - pub fn SSL_CTX_set_max_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; + pub fn SSL_CTX_set_min_proto_version(ctx: *mut SSL_CTX, version: u16) -> c_int; + pub fn SSL_CTX_set_max_proto_version(ctx: *mut SSL_CTX, version: u16) -> c_int; pub fn SSL_set_min_proto_version(s: *mut SSL, version: u16) -> c_int; pub fn SSL_set_max_proto_version(s: *mut SSL, version: u16) -> c_int; } @@ -450,8 +450,8 @@ cfg_if! { cfg_if! { if #[cfg(libressl270)] { extern "C" { - pub fn SSL_CTX_get_min_proto_version(ctx: *mut ::SSL_CTX) -> c_int; - pub fn SSL_CTX_get_max_proto_version(ctx: *mut ::SSL_CTX) -> c_int; + pub fn SSL_CTX_get_min_proto_version(ctx: *mut SSL_CTX) -> c_int; + pub fn SSL_CTX_get_max_proto_version(ctx: *mut SSL_CTX) -> c_int; pub fn SSL_get_min_proto_version(s: *mut SSL) -> c_int; pub fn SSL_get_max_proto_version(s: *mut SSL) -> c_int; } @@ -477,7 +477,7 @@ const_ptr_api! { } extern "C" { #[cfg(ossl111)] - pub fn SSL_CIPHER_get_handshake_digest(cipher: *const ::SSL_CIPHER) -> *const ::EVP_MD; + pub fn SSL_CIPHER_get_handshake_digest(cipher: *const SSL_CIPHER) -> *const EVP_MD; pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char; #[cfg(ossl111)] pub fn SSL_CIPHER_standard_name(cipher: *const SSL_CIPHER) -> *const c_char; @@ -491,7 +491,9 @@ extern "C" { #[cfg(any(ossl111, libressl340))] pub fn SSL_CTX_set_ciphersuites(ctx: *mut SSL_CTX, str: *const c_char) -> c_int; #[cfg(any(ossl111, libressl340))] - pub fn SSL_set_ciphersuites(ssl: *mut ::SSL, str: *const c_char) -> c_int; + pub fn SSL_set_ciphersuites(ssl: *mut SSL, str: *const c_char) -> c_int; + pub fn SSL_set_cipher_list(ssl: *mut SSL, s: *const c_char) -> c_int; + pub fn SSL_set_ssl_method(s: *mut SSL, method: *const SSL_METHOD) -> c_int; pub fn SSL_set_verify( ssl: *mut SSL, mode: c_int, @@ -515,6 +517,13 @@ extern "C" { ctx: *mut SSL_CTX, cert_chain_file: *const c_char, ) -> c_int; + pub fn SSL_use_PrivateKey_file(ssl: *mut SSL, file: *const c_char, type_: c_int) -> c_int; + pub fn SSL_use_PrivateKey(ssl: *mut SSL, pkey: *mut EVP_PKEY) -> c_int; + pub fn SSL_use_certificate(ssl: *mut SSL, x: *mut X509) -> c_int; + #[cfg(any(ossl110, libressl332))] + pub fn SSL_use_certificate_chain_file(ssl: *mut SSL, file: *const c_char) -> c_int; + pub fn SSL_set_client_CA_list(s: *mut SSL, name_list: *mut stack_st_X509_NAME); + pub fn SSL_add_client_CA(ssl: *mut SSL, x: *mut X509) -> c_int; pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; #[cfg(not(ossl110))] @@ -634,11 +643,20 @@ extern "C" { pub fn SSL_peek(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; #[cfg(any(ossl111, libressl340))] pub fn SSL_read_early_data( - s: *mut ::SSL, + s: *mut SSL, buf: *mut c_void, num: size_t, readbytes: *mut size_t, ) -> c_int; + #[cfg(ossl111)] + pub fn SSL_bytes_to_cipher_list( + s: *mut SSL, + bytes: *const c_uchar, + len: size_t, + isv2format: c_int, + sk: *mut *mut stack_st_SSL_CIPHER, + scsvs: *mut *mut stack_st_SSL_CIPHER, + ) -> c_int; } extern "C" { @@ -788,9 +806,9 @@ extern "C" { pub fn SSL_CTX_get_ex_new_index( argl: c_long, argp: *mut c_void, - new_func: Option<::CRYPTO_EX_new>, - dup_func: Option<::CRYPTO_EX_dup>, - free_func: Option<::CRYPTO_EX_free>, + new_func: Option, + dup_func: Option, + free_func: Option, ) -> c_int; pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) -> c_int; @@ -817,13 +835,9 @@ extern "C" { #[cfg(not(ossl110))] #[link_name = "SSL_CTX_set_tmp_ecdh_callback"] pub fn SSL_CTX_set_tmp_ecdh_callback__fixed_rust( - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, ecdh: Option< - unsafe extern "C" fn( - ssl: *mut ::SSL, - is_export: c_int, - keylength: c_int, - ) -> *mut ::EC_KEY, + unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut EC_KEY, >, ); #[cfg(not(ossl110))] @@ -892,3 +906,21 @@ extern "C" { #[cfg(ossl110)] pub fn OPENSSL_init_ssl(opts: u64, settings: *const OPENSSL_INIT_SETTINGS) -> c_int; } + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_num_tickets(ctx: *mut SSL_CTX, num_tickets: size_t) -> c_int; + + #[cfg(ossl111)] + pub fn SSL_set_num_tickets(s: *mut SSL, num_tickets: size_t) -> c_int; + + #[cfg(ossl111b)] + pub fn SSL_CTX_get_num_tickets(ctx: *const SSL_CTX) -> size_t; + #[cfg(all(ossl111, not(ossl111b)))] + pub fn SSL_CTX_get_num_tickets(ctx: *mut SSL_CTX) -> size_t; + + #[cfg(ossl111b)] + pub fn SSL_get_num_tickets(s: *const SSL) -> size_t; + #[cfg(all(ossl111, not(ossl111b)))] + pub fn SSL_get_num_tickets(s: *mut SSL) -> size_t; +} diff --git a/openssl-sys/src/handwritten/tls1.rs b/openssl-sys/src/handwritten/tls1.rs index a54dcbc80d..8cf992fbce 100644 --- a/openssl-sys/src/handwritten/tls1.rs +++ b/openssl-sys/src/handwritten/tls1.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; extern "C" { pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; @@ -17,7 +17,7 @@ extern "C" { #[cfg(ossl111)] pub fn SSL_export_keying_material_early( - s: *mut ::SSL, + s: *mut SSL, out: *mut c_uchar, olen: size_t, label: *const c_char, diff --git a/openssl-sys/src/handwritten/types.rs b/openssl-sys/src/handwritten/types.rs index 476578c051..06354728f2 100644 --- a/openssl-sys/src/handwritten/types.rs +++ b/openssl-sys/src/handwritten/types.rs @@ -1,16 +1,29 @@ use libc::*; #[allow(unused_imports)] -use *; +use super::super::*; +pub enum ASN1_OBJECT {} +pub enum ASN1_VALUE {} + +pub type ASN1_BOOLEAN = c_int; pub enum ASN1_INTEGER {} +pub enum ASN1_ENUMERATED {} pub enum ASN1_GENERALIZEDTIME {} pub enum ASN1_STRING {} pub enum ASN1_BIT_STRING {} pub enum ASN1_TIME {} -pub enum ASN1_TYPE {} -pub enum ASN1_OBJECT {} pub enum ASN1_OCTET_STRING {} +pub enum ASN1_NULL {} +pub enum ASN1_PRINTABLESTRING {} +pub enum ASN1_T61STRING {} +pub enum ASN1_IA5STRING {} +pub enum ASN1_GENERALSTRING {} +pub enum ASN1_BMPSTRING {} +pub enum ASN1_UNIVERSALSTRING {} +pub enum ASN1_UTCTIME {} +pub enum ASN1_VISIBLESTRING {} +pub enum ASN1_UTF8STRING {} pub enum bio_st {} // FIXME remove cfg_if! { @@ -112,6 +125,8 @@ pub enum EVP_PKEY_ASN1_METHOD {} pub enum EVP_PKEY_CTX {} +pub enum CMAC_CTX {} + cfg_if! { if #[cfg(any(ossl110, libressl280))] { pub enum HMAC_CTX {} @@ -136,22 +151,22 @@ cfg_if! { pub struct DH { pub pad: c_int, pub version: c_int, - pub p: *mut ::BIGNUM, - pub g: *mut ::BIGNUM, + pub p: *mut BIGNUM, + pub g: *mut BIGNUM, pub length: c_long, - pub pub_key: *mut ::BIGNUM, - pub priv_key: *mut ::BIGNUM, + pub pub_key: *mut BIGNUM, + pub priv_key: *mut BIGNUM, pub flags: c_int, - pub method_mont_p: *mut ::BN_MONT_CTX, - pub q: *mut ::BIGNUM, - pub j: *mut ::BIGNUM, + pub method_mont_p: *mut BN_MONT_CTX, + pub q: *mut BIGNUM, + pub j: *mut BIGNUM, pub seed: *mut c_uchar, pub seedlen: c_int, - pub counter: *mut ::BIGNUM, + pub counter: *mut BIGNUM, pub references: c_int, - pub ex_data: ::CRYPTO_EX_DATA, - pub meth: *const ::DH_METHOD, - pub engine: *mut ::ENGINE, + pub ex_data: CRYPTO_EX_DATA, + pub meth: *const DH_METHOD, + pub engine: *mut ENGINE, } } } @@ -194,57 +209,57 @@ cfg_if! { pub struct RSA { pub pad: c_int, pub version: c_long, - pub meth: *const ::RSA_METHOD, + pub meth: *const RSA_METHOD, - pub engine: *mut ::ENGINE, - pub n: *mut ::BIGNUM, - pub e: *mut ::BIGNUM, - pub d: *mut ::BIGNUM, - pub p: *mut ::BIGNUM, - pub q: *mut ::BIGNUM, - pub dmp1: *mut ::BIGNUM, - pub dmq1: *mut ::BIGNUM, - pub iqmp: *mut ::BIGNUM, + pub engine: *mut ENGINE, + pub n: *mut BIGNUM, + pub e: *mut BIGNUM, + pub d: *mut BIGNUM, + pub p: *mut BIGNUM, + pub q: *mut BIGNUM, + pub dmp1: *mut BIGNUM, + pub dmq1: *mut BIGNUM, + pub iqmp: *mut BIGNUM, - pub ex_data: ::CRYPTO_EX_DATA, + pub ex_data: CRYPTO_EX_DATA, pub references: c_int, pub flags: c_int, - pub _method_mod_n: *mut ::BN_MONT_CTX, - pub _method_mod_p: *mut ::BN_MONT_CTX, - pub _method_mod_q: *mut ::BN_MONT_CTX, + pub _method_mod_n: *mut BN_MONT_CTX, + pub _method_mod_p: *mut BN_MONT_CTX, + pub _method_mod_q: *mut BN_MONT_CTX, - pub blinding: *mut ::BN_BLINDING, - pub mt_blinding: *mut ::BN_BLINDING, + pub blinding: *mut BN_BLINDING, + pub mt_blinding: *mut BN_BLINDING, } } else { #[repr(C)] pub struct RSA { pub pad: c_int, pub version: c_long, - pub meth: *const ::RSA_METHOD, + pub meth: *const RSA_METHOD, - pub engine: *mut ::ENGINE, - pub n: *mut ::BIGNUM, - pub e: *mut ::BIGNUM, - pub d: *mut ::BIGNUM, - pub p: *mut ::BIGNUM, - pub q: *mut ::BIGNUM, - pub dmp1: *mut ::BIGNUM, - pub dmq1: *mut ::BIGNUM, - pub iqmp: *mut ::BIGNUM, + pub engine: *mut ENGINE, + pub n: *mut BIGNUM, + pub e: *mut BIGNUM, + pub d: *mut BIGNUM, + pub p: *mut BIGNUM, + pub q: *mut BIGNUM, + pub dmp1: *mut BIGNUM, + pub dmq1: *mut BIGNUM, + pub iqmp: *mut BIGNUM, - pub ex_data: ::CRYPTO_EX_DATA, + pub ex_data: CRYPTO_EX_DATA, pub references: c_int, pub flags: c_int, - pub _method_mod_n: *mut ::BN_MONT_CTX, - pub _method_mod_p: *mut ::BN_MONT_CTX, - pub _method_mod_q: *mut ::BN_MONT_CTX, + pub _method_mod_n: *mut BN_MONT_CTX, + pub _method_mod_p: *mut BN_MONT_CTX, + pub _method_mod_q: *mut BN_MONT_CTX, pub bignum_data: *mut c_char, - pub blinding: *mut ::BN_BLINDING, - pub mt_blinding: *mut ::BN_BLINDING, + pub blinding: *mut BN_BLINDING, + pub mt_blinding: *mut BN_BLINDING, } } } @@ -259,12 +274,12 @@ cfg_if! { #[repr(C)] pub struct X509 { pub cert_info: *mut X509_CINF, - pub sig_alg: *mut ::X509_ALGOR, - pub signature: *mut ::ASN1_BIT_STRING, + pub sig_alg: *mut X509_ALGOR, + pub signature: *mut ASN1_BIT_STRING, pub valid: c_int, pub references: c_int, pub name: *mut c_char, - pub ex_data: ::CRYPTO_EX_DATA, + pub ex_data: CRYPTO_EX_DATA, pub ex_pathlen: c_long, pub ex_pcpathlen: c_long, pub ex_flags: c_ulong, @@ -319,12 +334,14 @@ cfg_if! { } else { #[repr(C)] pub struct X509_ALGOR { - pub algorithm: *mut ::ASN1_OBJECT, + pub algorithm: *mut ASN1_OBJECT, parameter: *mut c_void, } } } +stack!(stack_st_X509_ALGOR); + pub enum X509_LOOKUP_METHOD {} pub enum X509_NAME {} @@ -460,10 +477,10 @@ cfg_if! { #[repr(C)] pub struct SSL { version: c_int, - method: *const ::SSL_METHOD, - rbio: *mut ::BIO, - wbio: *mut ::BIO, - bbio: *mut ::BIO, + method: *const SSL_METHOD, + rbio: *mut BIO, + wbio: *mut BIO, + bbio: *mut BIO, pub server: c_int, s3: *mut c_void, d1: *mut c_void, @@ -471,20 +488,20 @@ cfg_if! { cipher_list: *mut stack_st_SSL_CIPHER, cert: *mut c_void, sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - session: *mut ::SSL_SESSION, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut SSL_SESSION, verify_mode: c_int, error: c_int, error_code: c_int, - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, verify_result: c_long, references: c_int, client_version: c_int, max_send_fragment: c_uint, tlsext_hostname: *mut c_char, tlsext_status_type: c_int, - initial_ctx: *mut ::SSL_CTX, - enc_read_ctx: *mut ::EVP_CIPHER_CTX, + initial_ctx: *mut SSL_CTX, + enc_read_ctx: *mut EVP_CIPHER_CTX, read_hash: *mut EVP_MD_CTX, internal: *mut c_void, } @@ -493,7 +510,7 @@ cfg_if! { pub struct SSL { version: c_int, type_: c_int, - method: *const ::SSL_METHOD, + method: *const SSL_METHOD, rbio: *mut c_void, wbio: *mut c_void, bbio: *mut c_void, @@ -531,25 +548,25 @@ cfg_if! { cipher_list_by_id: *mut stack_st_SSL_CIPHER, mac_flags: c_int, aead_read_ctx: *mut c_void, - enc_read_ctx: *mut ::EVP_CIPHER_CTX, - read_hash: *mut ::EVP_MD_CTX, + enc_read_ctx: *mut EVP_CIPHER_CTX, + read_hash: *mut EVP_MD_CTX, aead_write_ctx: *mut c_void, - enc_write_ctx: *mut ::EVP_CIPHER_CTX, - write_hash: *mut ::EVP_MD_CTX, + enc_write_ctx: *mut EVP_CIPHER_CTX, + write_hash: *mut EVP_MD_CTX, cert: *mut c_void, sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - session: *mut ::SSL_SESSION, - generate_session_id: ::GEN_SESSION_CB, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut SSL_SESSION, + generate_session_id: GEN_SESSION_CB, verify_mode: c_int, - verify_callback: Option c_int>, + verify_callback: Option c_int>, info_callback: Option, error: c_int, error_code: c_int, - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, debug: c_int, verify_result: c_long, - ex_data: ::CRYPTO_EX_DATA, + ex_data: CRYPTO_EX_DATA, client_CA: *mut stack_st_X509_NAME, references: c_int, options: c_ulong, @@ -575,11 +592,11 @@ cfg_if! { tlsext_ellipticcurvelist_length: size_t, tlsext_ellipticcurvelist: *mut c_uchar, tlsext_session_ticket: *mut c_void, - tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, + tlsext_session_ticket_ext_cb: tls_session_ticket_ext_cb_fn, tls_session_ticket_ext_cb_arg: *mut c_void, - tls_session_secret_cb: ::tls_session_secret_cb_fn, + tls_session_secret_cb: tls_session_secret_cb_fn, tls_session_secret_cb_arg: *mut c_void, - initial_ctx: *mut ::SSL_CTX, + initial_ctx: *mut SSL_CTX, next_proto_negotiated: *mut c_uchar, next_proto_negotiated_len: c_uchar, srtp_profiles: *mut c_void, @@ -596,7 +613,7 @@ cfg_if! { pub struct SSL { version: c_int, type_: c_int, - method: *const ::SSL_METHOD, + method: *const SSL_METHOD, rbio: *mut c_void, wbio: *mut c_void, bbio: *mut c_void, @@ -628,19 +645,19 @@ cfg_if! { cipher_list: *mut stack_st_SSL_CIPHER, cipher_list_by_id: *mut stack_st_SSL_CIPHER, mac_flags: c_int, - enc_read_ctx: *mut ::EVP_CIPHER_CTX, - read_hash: *mut ::EVP_MD_CTX, + enc_read_ctx: *mut EVP_CIPHER_CTX, + read_hash: *mut EVP_MD_CTX, expand: *mut c_void, - enc_write_ctx: *mut ::EVP_CIPHER_CTX, - write_hash: *mut ::EVP_MD_CTX, + enc_write_ctx: *mut EVP_CIPHER_CTX, + write_hash: *mut EVP_MD_CTX, compress: *mut c_void, cert: *mut c_void, sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - session: *mut ::SSL_SESSION, - generate_session_id: ::GEN_SESSION_CB, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut SSL_SESSION, + generate_session_id: GEN_SESSION_CB, verify_mode: c_int, - verify_callback: Option c_int>, + verify_callback: Option c_int>, info_callback: Option, error: c_int, error_code: c_int, @@ -654,10 +671,10 @@ cfg_if! { #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] psk_server_callback: Option c_uint>, - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, debug: c_int, verify_result: c_long, - ex_data: ::CRYPTO_EX_DATA, + ex_data: CRYPTO_EX_DATA, client_CA: *mut stack_st_X509_NAME, references: c_int, options: c_ulong, @@ -716,15 +733,15 @@ cfg_if! { #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_session_ticket: *mut c_void, #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, + tlsext_session_ticket_ext_cb: tls_session_ticket_ext_cb_fn, #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tls_session_ticket_ext_cb_arg: *mut c_void, #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - tls_session_secret_cb: ::tls_session_secret_cb_fn, + tls_session_secret_cb: tls_session_secret_cb_fn, #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tls_session_secret_cb_arg: *mut c_void, #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] - initial_ctx: *mut ::SSL_CTX, + initial_ctx: *mut SSL_CTX, #[cfg(all( not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG") @@ -747,7 +764,7 @@ cfg_if! { tlsext_hb_seq: c_uint, renegotiate: c_int, #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] - srp_ctx: ::SRP_CTX, + srp_ctx: SRP_CTX, #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] alpn_client_proto_list: *mut c_uchar, #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] @@ -761,7 +778,7 @@ cfg_if! { } else if #[cfg(libressl251)] { #[repr(C)] pub struct SSL_CTX { - method: *const ::SSL_METHOD, + method: *const SSL_METHOD, cipher_list: *mut stack_st_SSL_CIPHER, cert_store: *mut c_void, session_timeout: c_long, @@ -769,8 +786,8 @@ cfg_if! { extra_certs: *mut stack_st_X509, verify_mode: c_int, sid_ctx_length: c_uint, - sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], - param: *mut ::X509_VERIFY_PARAM, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + param: *mut X509_VERIFY_PARAM, default_passwd_callback: *mut c_void, default_passwd_callback_userdata: *mut c_void, internal: *mut c_void, @@ -800,7 +817,7 @@ cfg_if! { client_cert_cb: *mut c_void, app_gen_cookie_cb: *mut c_void, app_verify_cookie_cb: *mut c_void, - ex_dat: ::CRYPTO_EX_DATA, + ex_dat: CRYPTO_EX_DATA, rsa_md5: *mut c_void, md5: *mut c_void, sha1: *mut c_void, @@ -870,7 +887,7 @@ cfg_if! { client_cert_cb: *mut c_void, app_gen_cookie_cb: *mut c_void, app_verify_cookie_cb: *mut c_void, - ex_dat: ::CRYPTO_EX_DATA, + ex_dat: CRYPTO_EX_DATA, rsa_md5: *mut c_void, md5: *mut c_void, sha1: *mut c_void, @@ -1058,7 +1075,7 @@ cfg_if! { } else if #[cfg(libressl)] { #[repr(C)] pub struct CRYPTO_EX_DATA { - pub sk: *mut ::stack_st_void, + pub sk: *mut stack_st_void, } } else { #[repr(C)] diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 2203b6081d..f5e3c24289 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; #[repr(C)] pub struct X509_VAL { @@ -9,12 +9,16 @@ pub struct X509_VAL { pub enum X509_NAME_ENTRY {} +stack!(stack_st_X509_NAME_ENTRY); + stack!(stack_st_X509_NAME); pub enum X509_EXTENSION {} stack!(stack_st_X509_EXTENSION); +pub enum X509_ATTRIBUTE {} + stack!(stack_st_X509_ATTRIBUTE); cfg_if! { @@ -24,8 +28,8 @@ cfg_if! { #[repr(C)] pub struct X509_REQ_INFO { pub enc: ASN1_ENCODING, - pub version: *mut ::ASN1_INTEGER, - pub subject: *mut ::X509_NAME, + pub version: *mut ASN1_INTEGER, + pub subject: *mut X509_NAME, pubkey: *mut c_void, pub attributes: *mut stack_st_X509_ATTRIBUTE, } @@ -274,6 +278,7 @@ extern "C" { pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); pub fn X509_NAME_new() -> *mut X509_NAME; + pub fn X509_NAME_cmp(x: *const X509_NAME, y: *const X509_NAME) -> c_int; pub fn X509_NAME_free(x: *mut X509_NAME); pub fn X509_new() -> *mut X509; @@ -286,6 +291,13 @@ const_ptr_api! { pub fn X509_NAME_dup(x: #[const_ptr_if(ossl300)] X509_NAME) -> *mut X509_NAME; #[cfg(any(ossl110, libressl270))] pub fn X509_dup(x: #[const_ptr_if(ossl300)] X509) -> *mut X509; + #[cfg(any(ossl101, libressl350))] + pub fn X509_NAME_add_entry( + name: *mut X509_NAME, + ne: #[const_ptr_if(any(ossl110, libressl))] X509_NAME_ENTRY, + loc: c_int, + set: c_int, + ) -> c_int; } } extern "C" { @@ -306,26 +318,26 @@ const_ptr_api! { } } extern "C" { - pub fn X509_issuer_name_hash(x: *mut ::X509) -> c_ulong; - pub fn X509_subject_name_hash(x: *mut ::X509) -> c_ulong; + pub fn X509_issuer_name_hash(x: *mut X509) -> c_ulong; + pub fn X509_subject_name_hash(x: *mut X509) -> c_ulong; } const_ptr_api! { extern "C" { - pub fn X509_get_issuer_name(x: #[const_ptr_if(any(ossl110, libressl280))] ::X509) -> *mut ::X509_NAME; + pub fn X509_get_issuer_name(x: #[const_ptr_if(any(ossl110, libressl280))] X509) -> *mut X509_NAME; pub fn X509_set_subject_name(x: *mut X509, name: #[const_ptr_if(ossl300)] X509_NAME) -> c_int; - pub fn X509_get_subject_name(x: #[const_ptr_if(any(ossl110, libressl280))] ::X509) -> *mut ::X509_NAME; + pub fn X509_get_subject_name(x: #[const_ptr_if(any(ossl110, libressl280))] X509) -> *mut X509_NAME; } } cfg_if! { if #[cfg(any(ossl110, libressl350))] { extern "C" { - pub fn X509_set1_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_set1_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_set1_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set1_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; } } else { extern "C" { - pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; - pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; } } } @@ -352,6 +364,33 @@ const_ptr_api! { -> c_int; } } +extern "C" { + pub fn X509_REQ_get_attr_count(req: *const X509_REQ) -> c_int; + pub fn X509_REQ_get_attr_by_NID(req: *const X509_REQ, nid: c_int, lastpos: c_int) -> c_int; + pub fn X509_REQ_get_attr(req: *const X509_REQ, loc: c_int) -> *mut X509_ATTRIBUTE; + pub fn X509_REQ_delete_attr(req: *mut X509_REQ, loc: c_int) -> *mut X509_ATTRIBUTE; + pub fn X509_REQ_add1_attr_by_txt( + req: *mut X509_REQ, + attrname: *const c_char, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_NID( + req: *mut X509_REQ, + nid: c_int, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_OBJ( + req: *mut X509_REQ, + obj: *const ASN1_OBJECT, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; +} extern "C" { pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; pub fn X509_REQ_verify(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; @@ -407,7 +446,7 @@ extern "C" { pub fn X509_CRL_get_issuer(x: *const X509_CRL) -> *mut X509_NAME; #[cfg(ossl110)] - pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION; + pub fn X509_get0_extensions(req: *const X509) -> *const stack_st_X509_EXTENSION; pub fn X509_CRL_set_version(crl: *mut X509_CRL, version: c_long) -> c_int; } @@ -543,6 +582,13 @@ extern "C" { pub fn X509_EXTENSION_get_object(ext: *mut X509_EXTENSION) -> *mut ASN1_OBJECT; pub fn X509_EXTENSION_get_data(ext: *mut X509_EXTENSION) -> *mut ASN1_OCTET_STRING; } + +const_ptr_api! { + extern "C" { + pub fn i2d_X509_EXTENSION(ext: #[const_ptr_if(ossl300)] X509_EXTENSION, pp: *mut *mut c_uchar) -> c_int; + } +} + const_ptr_api! { extern "C" { // in X509 @@ -552,7 +598,7 @@ const_ptr_api! { pub fn X509_get_ext_by_critical(x: #[const_ptr_if(any(ossl110, libressl280))] X509, crit: c_int, lastpos: c_int) -> c_int; pub fn X509_get_ext(x: #[const_ptr_if(any(ossl110, libressl280))] X509, loc: c_int) -> *mut X509_EXTENSION; pub fn X509_get_ext_d2i( - x: #[const_ptr_if(any(ossl110, libressl280))] ::X509, + x: #[const_ptr_if(any(ossl110, libressl280))] X509, nid: c_int, crit: *mut c_int, idx: *mut c_int, @@ -564,7 +610,7 @@ const_ptr_api! { pub fn X509_CRL_get_ext_by_critical(x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, crit: c_int, lastpos: c_int) -> c_int; pub fn X509_CRL_get_ext(x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, loc: c_int) -> *mut X509_EXTENSION; pub fn X509_CRL_get_ext_d2i( - x: #[const_ptr_if(any(ossl110, libressl280))] ::X509_CRL, + x: #[const_ptr_if(any(ossl110, libressl280))] X509_CRL, nid: c_int, crit: *mut c_int, idx: *mut c_int, @@ -576,7 +622,7 @@ const_ptr_api! { pub fn X509_REVOKED_get_ext_by_critical(x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, crit: c_int, lastpos: c_int) -> c_int; pub fn X509_REVOKED_get_ext(x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, loc: c_int) -> *mut X509_EXTENSION; pub fn X509_REVOKED_get_ext_d2i( - x: #[const_ptr_if(any(ossl110, libressl280))] ::X509_REVOKED, + x: #[const_ptr_if(any(ossl110, libressl280))] X509_REVOKED, nid: c_int, crit: *mut c_int, idx: *mut c_int, @@ -600,6 +646,7 @@ const_ptr_api! { pub fn X509_STORE_get0_objects(ctx: #[const_ptr_if(ossl300)] X509_STORE) -> *mut stack_st_X509_OBJECT; } } + #[cfg(any(ossl110, libressl270))] extern "C" { pub fn X509_OBJECT_get0_X509(x: *const X509_OBJECT) -> *mut X509; @@ -626,7 +673,6 @@ extern "C" { extern "C" { pub fn X509_cmp(a: *const X509, b: *const X509) -> c_int; - pub fn X509_NAME_cmp(a: *const X509_NAME, b: *const X509_NAME) -> c_int; pub fn X509_issuer_and_serial_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_issuer_name_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_subject_name_cmp(a: *const X509, b: *const X509) -> c_int; @@ -638,3 +684,84 @@ extern "C" { pub fn X509_print(bio: *mut BIO, x509: *mut X509) -> c_int; pub fn X509_REQ_print(bio: *mut BIO, req: *mut X509_REQ) -> c_int; } + +#[repr(C)] +pub struct X509_PURPOSE { + pub purpose: c_int, + pub trust: c_int, // Default trust ID + pub flags: c_int, + pub check_purpose: + Option c_int>, + pub name: *mut c_char, + pub sname: *mut c_char, + pub usr_data: *mut c_void, +} + +const_ptr_api! { + extern "C" { + pub fn X509_PURPOSE_get_by_sname(sname: #[const_ptr_if(any(ossl110, libressl280))] c_char) -> c_int; + } +} +extern "C" { + pub fn X509_PURPOSE_get0(idx: c_int) -> *mut X509_PURPOSE; +} + +extern "C" { + pub fn X509_ATTRIBUTE_new() -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_free(attr: *mut X509_ATTRIBUTE); + pub fn X509_ATTRIBUTE_create( + nid: c_int, + atrtype: c_int, + value: *mut c_void, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_NID( + attr: *mut *mut X509_ATTRIBUTE, + nid: c_int, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_OBJ( + attr: *mut *mut X509_ATTRIBUTE, + obj: *const ASN1_OBJECT, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_txt( + attr: *mut *mut X509_ATTRIBUTE, + atrname: *const c_char, + atrtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_set1_object(attr: *mut X509_ATTRIBUTE, obj: *const ASN1_OBJECT) -> c_int; + pub fn X509_ATTRIBUTE_set1_data( + attr: *mut X509_ATTRIBUTE, + attrtype: c_int, + data: *const c_void, + len: c_int, + ) -> c_int; + pub fn X509_ATTRIBUTE_get0_data( + attr: *mut X509_ATTRIBUTE, + idx: c_int, + atrtype: c_int, + data: *mut c_void, + ) -> *mut c_void; + pub fn X509_ATTRIBUTE_get0_object(attr: *mut X509_ATTRIBUTE) -> *mut ASN1_OBJECT; + pub fn X509_ATTRIBUTE_get0_type(attr: *mut X509_ATTRIBUTE, idx: c_int) -> *mut ASN1_TYPE; + pub fn d2i_X509_ATTRIBUTE( + a: *mut *mut X509_ATTRIBUTE, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_ATTRIBUTE; +} +const_ptr_api! { + extern "C" { + pub fn X509_ATTRIBUTE_count( + attr: #[const_ptr_if(any(ossl110, libressl280))] X509_ATTRIBUTE // const since OpenSSL v1.1.0 + ) -> c_int; + pub fn i2d_X509_ATTRIBUTE(x: #[const_ptr_if(ossl300)] X509_ATTRIBUTE, buf: *mut *mut u8) -> c_int; + pub fn X509_ATTRIBUTE_dup(x: #[const_ptr_if(ossl300)] X509_ATTRIBUTE) -> *mut X509_ATTRIBUTE; + } +} diff --git a/openssl-sys/src/handwritten/x509_vfy.rs b/openssl-sys/src/handwritten/x509_vfy.rs index 632bb9f689..9adf63fa0e 100644 --- a/openssl-sys/src/handwritten/x509_vfy.rs +++ b/openssl-sys/src/handwritten/x509_vfy.rs @@ -1,5 +1,5 @@ +use super::super::*; use libc::*; -use *; #[cfg(any(libressl, all(ossl102, not(ossl110))))] pub enum X509_VERIFY_PARAM_ID {} @@ -21,6 +21,7 @@ extern "C" { ret: *mut *mut c_char, ) -> c_int; pub fn X509_load_cert_file(ctx: *mut X509_LOOKUP, file: *const c_char, _type: c_int) -> c_int; + pub fn X509_load_crl_file(ctx: *mut X509_LOOKUP, file: *const c_char, _type: c_int) -> c_int; } extern "C" { @@ -47,6 +48,9 @@ extern "C" { pub fn X509_STORE_set_default_paths(store: *mut X509_STORE) -> c_int; pub fn X509_STORE_set_flags(store: *mut X509_STORE, flags: c_ulong) -> c_int; + pub fn X509_STORE_set_purpose(ctx: *mut X509_STORE, purpose: c_int) -> c_int; + pub fn X509_STORE_set_trust(ctx: *mut X509_STORE, trust: c_int) -> c_int; + } const_ptr_api! { @@ -119,4 +123,10 @@ extern "C" { ip: *const c_uchar, iplen: size_t, ) -> c_int; + #[cfg(ossl110)] + pub fn X509_VERIFY_PARAM_set_auth_level(param: *mut X509_VERIFY_PARAM, lvl: c_int); + #[cfg(ossl110)] + pub fn X509_VERIFY_PARAM_get_auth_level(param: *const X509_VERIFY_PARAM) -> c_int; + #[cfg(ossl102)] + pub fn X509_VERIFY_PARAM_set_purpose(param: *mut X509_VERIFY_PARAM, purpose: c_int) -> c_int; } diff --git a/openssl-sys/src/handwritten/x509v3.rs b/openssl-sys/src/handwritten/x509v3.rs index a47b815ad9..2ee0452597 100644 --- a/openssl-sys/src/handwritten/x509v3.rs +++ b/openssl-sys/src/handwritten/x509v3.rs @@ -1,10 +1,16 @@ +use super::super::*; use libc::*; -use *; pub enum CONF_METHOD {} extern "C" { + pub fn GENERAL_NAME_new() -> *mut GENERAL_NAME; pub fn GENERAL_NAME_free(name: *mut GENERAL_NAME); + pub fn GENERAL_NAME_set0_othername( + gen: *mut GENERAL_NAME, + oid: *mut ASN1_OBJECT, + value: *mut ASN1_TYPE, + ) -> c_int; } #[repr(C)] @@ -95,10 +101,47 @@ extern "C" { indent: c_int, ) -> c_int; + #[cfg(ossl110)] + pub fn X509_get_pathlen(x: *mut X509) -> c_long; #[cfg(ossl110)] pub fn X509_get_extension_flags(x: *mut X509) -> u32; #[cfg(ossl110)] pub fn X509_get_key_usage(x: *mut X509) -> u32; #[cfg(ossl110)] pub fn X509_get_extended_key_usage(x: *mut X509) -> u32; + #[cfg(ossl110)] + pub fn X509_get0_subject_key_id(x: *mut X509) -> *const ASN1_OCTET_STRING; + #[cfg(ossl110)] + pub fn X509_get0_authority_key_id(x: *mut X509) -> *const ASN1_OCTET_STRING; + #[cfg(ossl111d)] + pub fn X509_get0_authority_issuer(x: *mut X509) -> *const stack_st_GENERAL_NAME; + #[cfg(ossl111d)] + pub fn X509_get0_authority_serial(x: *mut X509) -> *const ASN1_INTEGER; +} + +#[repr(C)] +pub struct DIST_POINT_NAME { + pub type_: c_int, + pub name: DIST_POINT_NAME_st_anon_union, + pub dpname: *mut X509_NAME, +} + +#[repr(C)] +pub union DIST_POINT_NAME_st_anon_union { + pub fullname: *mut stack_st_GENERAL_NAME, + pub relativename: *mut stack_st_X509_NAME_ENTRY, +} + +#[repr(C)] +pub struct DIST_POINT { + pub distpoint: *mut DIST_POINT_NAME, + pub reasons: *mut ASN1_BIT_STRING, + pub CRLissuer: *mut stack_st_GENERAL_NAME, + pub dp_reasons: c_int, +} +stack!(stack_st_DIST_POINT); + +extern "C" { + pub fn DIST_POINT_free(dist_point: *mut DIST_POINT); + pub fn DIST_POINT_NAME_free(dist_point: *mut DIST_POINT_NAME); } diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0d6676827e..784b7637e1 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,25 +1,37 @@ #![allow( clippy::missing_safety_doc, - clippy::unreadable_literal, - clippy::upper_case_acronyms, dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals, - overflowing_literals, unused_imports )] +#![cfg_attr(feature = "unstable_boringssl", allow(ambiguous_glob_reexports))] #![doc(html_root_url = "https://docs.rs/openssl-sys/0.9")] #![recursion_limit = "128"] // configure fixed limit across all rust versions extern crate libc; pub use libc::*; -#[cfg(boringssl)] +#[cfg(feature = "unstable_boringssl")] extern crate bssl_sys; -#[cfg(boringssl)] +#[cfg(feature = "unstable_boringssl")] pub use bssl_sys::*; +#[cfg(all(boringssl, not(feature = "unstable_boringssl")))] +#[path = "."] +mod boringssl { + include!(concat!(env!("OUT_DIR"), "/bindgen.rs")); + + pub fn init() { + unsafe { + CRYPTO_library_init(); + } + } +} +#[cfg(all(boringssl, not(feature = "unstable_boringssl")))] +pub use boringssl::*; + #[cfg(openssl)] #[path = "."] mod openssl { @@ -130,7 +142,7 @@ mod openssl { ) { let mutex = &(*MUTEXES)[n as usize]; - if mode & ::CRYPTO_LOCK != 0 { + if mode & CRYPTO_LOCK != 0 { (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); } else { if let None = (*GUARDS)[n as usize].take() { @@ -165,7 +177,7 @@ mod openssl { SSL_load_error_strings(); OPENSSL_add_all_algorithms_noconf(); - let num_locks = ::CRYPTO_num_locks(); + let num_locks = CRYPTO_num_locks(); let mut mutexes = Box::new(Vec::new()); for _ in 0..num_locks { mutexes.push(Mutex::new(())); diff --git a/openssl-sys/src/macros.rs b/openssl-sys/src/macros.rs index cb675f6e41..96523db8f4 100644 --- a/openssl-sys/src/macros.rs +++ b/openssl-sys/src/macros.rs @@ -63,31 +63,13 @@ macro_rules! stack { } else { #[repr(C)] pub struct $t { - pub stack: ::_STACK, + pub stack: $crate::_STACK, } } } }; } -#[cfg(const_fn)] -macro_rules! const_fn { - ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { - $( - pub const fn $name($($arg: $t),*) -> $ret $b - )* - } -} - -#[cfg(not(const_fn))] -macro_rules! const_fn { - ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { - $( - pub fn $name($($arg: $t),*) -> $ret $b - )* - } -} - // openssl changes `*mut` to `*const` in certain parameters in certain versions; // in C this is ABI and (mostly) API compatible. // diff --git a/openssl-sys/src/obj_mac.rs b/openssl-sys/src/obj_mac.rs index ed50ebcc5f..6ae48834b5 100644 --- a/openssl-sys/src/obj_mac.rs +++ b/openssl-sys/src/obj_mac.rs @@ -920,15 +920,23 @@ pub const NID_aes_192_cbc_hmac_sha1: c_int = 917; pub const NID_aes_256_cbc_hmac_sha1: c_int = 918; #[cfg(ossl111)] pub const NID_X25519: c_int = 1034; +#[cfg(libressl370)] +pub const NID_X25519: c_int = 950; #[cfg(ossl111)] pub const NID_X448: c_int = 1035; #[cfg(ossl110)] pub const NID_hkdf: c_int = 1036; #[cfg(ossl111)] +pub const NID_poly1305: c_int = 1061; +#[cfg(ossl111)] pub const NID_ED25519: c_int = 1087; +#[cfg(libressl370)] +pub const NID_ED25519: c_int = 952; #[cfg(ossl111)] pub const NID_ED448: c_int = 1088; #[cfg(ossl111)] +pub const NID_sm2: c_int = 1172; +#[cfg(ossl111)] pub const NID_sm3: c_int = 1143; #[cfg(libressl291)] pub const NID_sm3: c_int = 968; diff --git a/openssl-sys/src/ocsp.rs b/openssl-sys/src/ocsp.rs index 7efac4d449..fc0db39e90 100644 --- a/openssl-sys/src/ocsp.rs +++ b/openssl-sys/src/ocsp.rs @@ -1,7 +1,5 @@ use libc::*; -use *; - pub const OCSP_REVOKED_STATUS_NOSTATUS: c_int = -1; pub const OCSP_REVOKED_STATUS_UNSPECIFIED: c_int = 0; pub const OCSP_REVOKED_STATUS_KEYCOMPROMISE: c_int = 1; diff --git a/openssl-sys/src/pem.rs b/openssl-sys/src/pem.rs index 2a05ad58cd..f7dd8ac30d 100644 --- a/openssl-sys/src/pem.rs +++ b/openssl-sys/src/pem.rs @@ -1,5 +1,3 @@ use libc::*; -use *; - pub const PEM_R_NO_START_LINE: c_int = 108; diff --git a/openssl-sys/src/pkcs7.rs b/openssl-sys/src/pkcs7.rs index 188693f9f2..0a56225a91 100644 --- a/openssl-sys/src/pkcs7.rs +++ b/openssl-sys/src/pkcs7.rs @@ -1,7 +1,5 @@ use libc::*; -use *; - pub const PKCS7_TEXT: c_int = 0x1; pub const PKCS7_NOCERTS: c_int = 0x2; pub const PKCS7_NOSIGS: c_int = 0x4; diff --git a/openssl-sys/src/rsa.rs b/openssl-sys/src/rsa.rs index 351ac84c03..ff30cf1e23 100644 --- a/openssl-sys/src/rsa.rs +++ b/openssl-sys/src/rsa.rs @@ -1,7 +1,7 @@ use libc::*; use std::ptr; -use *; +use super::super::*; pub const RSA_F4: c_long = 0x10001; diff --git a/openssl-sys/src/sha.rs b/openssl-sys/src/sha.rs index 8b77f546c6..4ad0c17cda 100644 --- a/openssl-sys/src/sha.rs +++ b/openssl-sys/src/sha.rs @@ -1,6 +1,6 @@ +use super::*; use libc::*; use std::ptr; -use *; #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] pub const SHA_LBLOCK: c_int = 16; diff --git a/openssl-sys/src/srtp.rs b/openssl-sys/src/srtp.rs index 78298d23ec..93c77970c9 100644 --- a/openssl-sys/src/srtp.rs +++ b/openssl-sys/src/srtp.rs @@ -1,7 +1,5 @@ use libc::*; -use *; - pub const SRTP_AES128_CM_SHA1_80: c_ulong = 0x0001; pub const SRTP_AES128_CM_SHA1_32: c_ulong = 0x0002; pub const SRTP_AES128_F8_SHA1_80: c_ulong = 0x0003; diff --git a/openssl-sys/src/ssl.rs b/openssl-sys/src/ssl.rs index 12243dc4fc..e812673333 100644 --- a/openssl-sys/src/ssl.rs +++ b/openssl-sys/src/ssl.rs @@ -1,7 +1,7 @@ use libc::*; use std::ptr; -use *; +use super::*; #[cfg(not(ossl110))] pub const SSL_MAX_KRB5_PRINCIPAL_LENGTH: c_int = 256; @@ -339,6 +339,8 @@ pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 71; #[cfg(any(libressl, all(ossl101, not(ossl110))))] pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; pub const SSL_CTRL_GET_EXTRA_CHAIN_CERTS: c_int = 82; +#[cfg(ossl102)] +pub const SSL_CTRL_CHAIN_CERT: c_int = 89; #[cfg(any(ossl111, libressl252))] pub const SSL_CTRL_SET_GROUPS_LIST: c_int = 92; #[cfg(any(libressl, all(ossl102, not(ossl110))))] @@ -390,6 +392,11 @@ pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_ST SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) } +#[cfg(ossl102)] +pub unsafe fn SSL_set0_verify_cert_store(ssl: *mut SSL, st: *mut X509_STORE) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) +} + cfg_if! { if #[cfg(ossl111)] { pub unsafe fn SSL_CTX_set1_groups_list(ctx: *mut SSL_CTX, s: *const c_char) -> c_long { @@ -407,6 +414,11 @@ cfg_if! { } } +#[cfg(ossl102)] +pub unsafe fn SSL_add0_chain_cert(ssl: *mut SSL, ptr: *mut X509) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_CHAIN_CERT, 0, ptr as *mut c_void) +} + #[cfg(ossl102)] pub unsafe fn SSL_CTX_set1_sigalgs_list(ctx: *mut SSL_CTX, s: *const c_char) -> c_long { SSL_CTX_ctrl( @@ -428,7 +440,7 @@ pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { } #[cfg(any(libressl, all(ossl102, not(ossl110))))] -pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { +pub unsafe fn SSL_set_ecdh_auto(ssl: *mut SSL, onoff: c_int) -> c_int { SSL_ctrl( ssl, SSL_CTRL_SET_ECDH_AUTO, @@ -567,12 +579,12 @@ extern "C" { #[deprecated(note = "use SSL_CTX_set_tmp_ecdh_callback__fixed_rust instead")] #[cfg(not(ossl110))] pub fn SSL_CTX_set_tmp_ecdh_callback( - ctx: *mut ::SSL_CTX, + ctx: *mut SSL_CTX, ecdh: unsafe extern "C" fn( - ssl: *mut ::SSL, + ssl: *mut SSL, is_export: c_int, keylength: c_int, - ) -> *mut ::EC_KEY, + ) -> *mut EC_KEY, ); #[deprecated(note = "use SSL_set_tmp_ecdh_callback__fixed_rust instead")] #[cfg(not(ossl110))] diff --git a/openssl-sys/src/tls1.rs b/openssl-sys/src/tls1.rs index d02f5c0497..2cb08a91f3 100644 --- a/openssl-sys/src/tls1.rs +++ b/openssl-sys/src/tls1.rs @@ -2,7 +2,7 @@ use libc::*; use std::mem; use std::ptr; -use *; +use super::*; pub const TLS1_VERSION: c_int = 0x301; pub const TLS1_1_VERSION: c_int = 0x302; @@ -10,6 +10,10 @@ pub const TLS1_2_VERSION: c_int = 0x303; #[cfg(any(ossl111, libressl340))] pub const TLS1_3_VERSION: c_int = 0x304; +pub const DTLS1_VERSION: c_int = 0xFEFF; +#[cfg(any(ossl102, libressl332))] +pub const DTLS1_2_VERSION: c_int = 0xFEFD; + pub const TLS1_AD_DECODE_ERROR: c_int = 50; pub const TLS1_AD_UNRECOGNIZED_NAME: c_int = 112; diff --git a/openssl-sys/src/types.rs b/openssl-sys/src/types.rs index dbf11291af..10c8f6771a 100644 --- a/openssl-sys/src/types.rs +++ b/openssl-sys/src/types.rs @@ -1,5 +1,6 @@ use libc::*; -use *; + +use super::*; cfg_if! { if #[cfg(any(ossl110, libressl280))] { diff --git a/openssl-sys/src/x509.rs b/openssl-sys/src/x509.rs index 0263c00b69..714b06c9bc 100644 --- a/openssl-sys/src/x509.rs +++ b/openssl-sys/src/x509.rs @@ -1,7 +1,5 @@ use libc::*; -use *; - pub const X509_FILETYPE_PEM: c_int = 1; pub const X509_FILETYPE_ASN1: c_int = 2; pub const X509_FILETYPE_DEFAULT: c_int = 3; diff --git a/openssl-sys/src/x509_vfy.rs b/openssl-sys/src/x509_vfy.rs index 8deaeeaaf3..2fa176fed5 100644 --- a/openssl-sys/src/x509_vfy.rs +++ b/openssl-sys/src/x509_vfy.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::*; pub const X509_V_OK: c_int = 0; #[cfg(ossl102f)] @@ -100,9 +100,9 @@ cfg_if! { #[cfg(ossl300)] pub const X509_V_ERR_INVALID_CA: c_int = 79; -#[cfg(not(ossl110))] +#[cfg(not(any(ossl110, libressl370)))] pub const X509_V_FLAG_CB_ISSUER_CHECK: c_ulong = 0x1; -#[cfg(ossl110)] +#[cfg(any(ossl110, libressl370))] pub const X509_V_FLAG_CB_ISSUER_CHECK: c_ulong = 0x0; pub const X509_V_FLAG_USE_CHECK_TIME: c_ulong = 0x2; pub const X509_V_FLAG_CRL_CHECK: c_ulong = 0x4; diff --git a/openssl-sys/src/x509v3.rs b/openssl-sys/src/x509v3.rs index ac826b601b..d2ff53489e 100644 --- a/openssl-sys/src/x509v3.rs +++ b/openssl-sys/src/x509v3.rs @@ -1,6 +1,6 @@ use libc::*; -use *; +use super::*; #[repr(C)] pub struct GENERAL_NAME { @@ -79,3 +79,26 @@ pub const XKU_TIMESTAMP: u32 = 0x40; pub const XKU_DVCS: u32 = 0x80; #[cfg(ossl110)] pub const XKU_ANYEKU: u32 = 0x100; + +pub const X509_PURPOSE_SSL_CLIENT: c_int = 1; +pub const X509_PURPOSE_SSL_SERVER: c_int = 2; +pub const X509_PURPOSE_NS_SSL_SERVER: c_int = 3; +pub const X509_PURPOSE_SMIME_SIGN: c_int = 4; +pub const X509_PURPOSE_SMIME_ENCRYPT: c_int = 5; +pub const X509_PURPOSE_CRL_SIGN: c_int = 6; +pub const X509_PURPOSE_ANY: c_int = 7; +pub const X509_PURPOSE_OCSP_HELPER: c_int = 8; +pub const X509_PURPOSE_TIMESTAMP_SIGN: c_int = 9; +pub const X509_PURPOSE_MIN: c_int = 1; +pub const X509_PURPOSE_MAX: c_int = 9; + +pub const CRL_REASON_UNSPECIFIED: c_int = 0; +pub const CRL_REASON_KEY_COMPROMISE: c_int = 1; +pub const CRL_REASON_CA_COMPROMISE: c_int = 2; +pub const CRL_REASON_AFFILIATION_CHANGED: c_int = 3; +pub const CRL_REASON_SUPERSEDED: c_int = 4; +pub const CRL_REASON_CESSATION_OF_OPERATION: c_int = 5; +pub const CRL_REASON_CERTIFICATE_HOLD: c_int = 6; +pub const CRL_REASON_REMOVE_FROM_CRL: c_int = 8; +pub const CRL_REASON_PRIVILEGE_WITHDRAWN: c_int = 9; +pub const CRL_REASON_AA_COMPROMISE: c_int = 10; diff --git a/openssl/CHANGELOG.md b/openssl/CHANGELOG.md index f66bcb7501..a0622ecccd 100644 --- a/openssl/CHANGELOG.md +++ b/openssl/CHANGELOG.md @@ -2,6 +2,133 @@ ## [Unreleased] +## [v0.10.55] - 2023-06-20 + +### Fixed + +* Fixed compilation with the latest version of BoringSSL. +* Fixed compilation when OpenSSL is compiled with `OPENSSL_NO_OCB`. +* Fixed a segfault in `X509VerifyParamRef::set_host` when called with an empty string. + +### Added + +* Added `Deriver::set_peer_ex`. +* Added `EcGroupRef::asn1_flag`. +* Exposed `EcPointRef::affine_coordinates` on BoringSSL and LibreSSL. +* Added `Nid::SM2` and `Id::SM2` + +## [v0.10.54] - 2023-05-31 + +### Fixed + +* `PKey::private_key_to_pkcs8_passphrase` no longer panics if a `passphrase` contains a NUL byte. + +## [v0.10.53] - 2023-05-30 + +### Added + +* Added `Dsa::from_pqg`, `Dsa::generate_key`, and `Dsa::generate_params`. +* Added `SslRef::bytes_to_cipher_list`. +* Added `SubjectAlternativeName::other_name2` + +## [v0.10.52] - 2023-04-24 + +### Added + +* Added `DhRef::check_key`. +* Added `Id::POLY1305`. +* Added `X509Ref::subject_key_id`, `X509Ref::authority_key_id`, `X509Ref::authority_issuer`, and `X509Ref::authority_serial`. + + +## [v0.10.51] - 2023-04-20 + +### Added + +* Added `X509RevokedRef::issuer_name` and `X509RevokedRef::reason_code`. +* Added `Dh::set_key` and `Dh::set_public_key` +* Added `Asn1OctetString` and `Asn1OctetStringRef1` +* Added `X509Extension::new_from_der` + +### Deprecated + +* Deprecated `X509Extension::new` and `X509Extension::new_nid` in favor of `X509Extension::new_from_der` and the `extensions` module. +* Deprecated `X509Extension::add_alias`, it is not required with `new_from_der` or the `extensions` module. + +## [v0.10.50] - 2023-04-09 + +### Added + +* Added `CipherCtxRef::cipher_update_inplace`. + +## [v0.10.49] - 2023-04-01 + +### Fixed + +* `SslConnector` no longer sets the SNI extension when connecting to an IP address. + +### Added + +* Implemented `Ord`, `PartialOrd`, `Eq`, and `PartialEq` for `Asn1Integer` and `Asn1IntegerRef`. +* Added `X509Ref::crl_distribution_points`, and `DistPoint`. + +## [v0.10.48] - 2023-03-23 + +### Fixed + +* Fixed injection vulnerabilities where OpenSSL's configuration mini-language could be used via `x509::extension::SubjectAlternativeName` and `x509::extension::ExtendedKeyUsage`. The mini-language can read arbitrary files amongst other things. + * As part of fixing this `SubjectAlternativeName::dir_name` and `SubjectAlternativeName::other_name` are deprecated and their implementations always `panic!`. If you have a use case for these, please file an issue. +* Fixed several NULL pointer dereferences in OpenSSL that could be triggered via `x509::X509Extension::new` and `x509::X509Extension::new_nid`. Note that these methods still accept OpenSSL's configuration mini-language, and therefore should not be used with untrusted data. +* Fixed a data-race with `x509::X509Name` that are created with `x509::X509NameBuilder` and then used concurrently. +* Fixed LibreSSL version checking. More functions should now be correctly available on LibreSSL. + +## [v0.10.47] - 2023-03-19 + +### Added + +* Added support for X25519 and Ed25519 on LibreSSL and BoringSSL. +* Added `Error::library_code` and `Error::reason_code`. + +## [v0.10.46] - 2023-03-14 + +### Fixed + +* Fixed a potential null-pointer deref when parsing a PKCS#12 archive with no identity. +* Fixed builds against OpenSSL built with `no-cast`. +* Fixed debug formatting of `GeneralName`. + +### Deprecated + +* Deprecated `PKcs12Ref::parse` in favor of `Pkcs12Ref::parse2`. +* Deprecated `ParsedPkcs12` in favor of `ParsedPkcs12_2`. +* Deprecated `Pkcs12Builder::build` in favor of `Pkcs12Builder::build2`. + +### Added + +* Added `X509VerifyParamRef::set_auth_level`, `X509VerifyParamRef::auth_level`, and `X509VerifyParamRef::set_purpose`. +* Added `X509PurposeId` and `X509Purpose`. +* Added `X509NameBuilder::append_entry`. +* Added `PKeyRef::private_key_to_pkcs8`. +* Added `X509LookupRef::load_crl_file`. +* Added `Pkcs12Builder::name`, `Pkcs12Builder::pkey`, and `Pkcs12Builder::cert`. +* Added `SslRef::set_method`, `SslRef::set_private_key_file`, `SslRef::set_private_key`, `SslRef::set_certificate`, `SslRef::set_certificate_chain_file`, `SslRef::add_client_ca`, `SslRef::set_client_ca_list`, `SslRef::set_min_proto_version`, `SslREf::set_max_proto_version`, `SslRef::set_ciphersuites`, `SslRef::set_cipher_list`, `SslRef::set_verify_cert_store`. +* Added `X509NameRef::to_owned`. +* Added `SslContextBuilder::set_num_tickets`, `SslContextRef::num_tickets`, `SslRef::set_num_tickets`, and `SslRef::num_tickets`. +* Added `CmsContentInfo::verify`. + +## [v0.10.45] - 2022-12-20 + +### Fixed + +* Removed the newly added `CipherCtxRef::minimal_output_size` method, which did not work properly. +* Added `NO_DEPRECATED_3_0` cfg checks for more APIs. + +### Added + +* Added `SslRef::add_chain_cert`. +* Added `PKeyRef::security_bits`. +* Added `Provider::set_default_search_path`. +* Added `CipherCtxRef::cipher_final_unchecked`. + ## [v0.10.44] - 2022-12-06 ### Added @@ -649,8 +776,19 @@ Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.44...master -[v0.10.44]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.44...openssl-v0.10.44 +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.55...master +[v0.10.55]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.54...openssl-v0.10.55 +[v0.10.54]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.53...openssl-v0.10.54 +[v0.10.53]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.52...openssl-v0.10.53 +[v0.10.52]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.51...openssl-v0.10.52 +[v0.10.51]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.50...openssl-v0.10.51 +[v0.10.50]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.49...openssl-v0.10.50 +[v0.10.49]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.49 +[v0.10.48]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.47...openssl-v0.10.48 +[v0.10.47]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.46...openssl-v0.10.47 +[v0.10.46]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.45...openssl-v0.10.46 +[v0.10.45]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.44...openssl-v0.10.45 +[v0.10.44]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.43...openssl-v0.10.44 [v0.10.43]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.42...openssl-v0.10.43 [v0.10.42]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.41...openssl-v0.10.42 [v0.10.41]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.40...openssl-v0.10.41 diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 03f621eddd..956d08cf9e 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.10.44" +version = "0.10.55" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" @@ -30,7 +30,7 @@ libc = "0.2" once_cell = "1.5.2" openssl-macros = { version = "0.1.0", path = "../openssl-macros" } -ffi = { package = "openssl-sys", version = "0.9.79", path = "../openssl-sys" } +ffi = { package = "openssl-sys", version = "0.9.89", path = "../openssl-sys" } [dev-dependencies] hex = "0.3" diff --git a/openssl/build.rs b/openssl/build.rs index fc6492292c..0a974b33e6 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -1,4 +1,8 @@ -#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] +#![allow( + clippy::inconsistent_digit_grouping, + clippy::uninlined_format_args, + clippy::unusual_byte_groupings +)] use std::env; @@ -7,13 +11,62 @@ fn main() { println!("cargo:rustc-cfg=libressl"); } - if env::var("CARGO_FEATURE_UNSTABLE_BORINGSSL").is_ok() { + if env::var("DEP_OPENSSL_BORINGSSL").is_ok() { println!("cargo:rustc-cfg=boringssl"); return; } - if let Ok(v) = env::var("DEP_OPENSSL_LIBRESSL_VERSION") { - println!("cargo:rustc-cfg=libressl{}", v); + if let Ok(v) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&v, 16).unwrap(); + + if version >= 0x2_05_00_00_0 { + println!("cargo:rustc-cfg=libressl250"); + } + if version >= 0x2_05_01_00_0 { + println!("cargo:rustc-cfg=libressl251"); + } + if version >= 0x2_06_01_00_0 { + println!("cargo:rustc-cfg=libressl261"); + } + if version >= 0x2_07_00_00_0 { + println!("cargo:rustc-cfg=libressl270"); + } + if version >= 0x2_07_01_00_0 { + println!("cargo:rustc-cfg=libressl271"); + } + if version >= 0x2_07_03_00_0 { + println!("cargo:rustc-cfg=libressl273"); + } + if version >= 0x2_08_00_00_0 { + println!("cargo:rustc-cfg=libressl280"); + } + if version >= 0x2_09_01_00_0 { + println!("cargo:rustc-cfg=libressl291"); + } + if version >= 0x3_01_00_00_0 { + println!("cargo:rustc-cfg=libressl310"); + } + if version >= 0x3_02_01_00_0 { + println!("cargo:rustc-cfg=libressl321"); + } + if version >= 0x3_03_02_00_0 { + println!("cargo:rustc-cfg=libressl332"); + } + if version >= 0x3_04_00_00_0 { + println!("cargo:rustc-cfg=libressl340"); + } + if version >= 0x3_05_00_00_0 { + println!("cargo:rustc-cfg=libressl350"); + } + if version >= 0x3_06_00_00_0 { + println!("cargo:rustc-cfg=libressl360"); + } + if version >= 0x3_06_01_00_0 { + println!("cargo:rustc-cfg=libressl361"); + } + if version >= 0x3_07_00_00_0 { + println!("cargo:rustc-cfg=libressl370"); + } } if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { @@ -46,6 +99,9 @@ fn main() { if version >= 0x3_00_00_00_0 { println!("cargo:rustc-cfg=ossl300"); } + if version >= 0x3_01_00_00_0 { + println!("cargo:rustc-cfg=ossl310"); + } } if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { diff --git a/openssl/examples/mk_certs.rs b/openssl/examples/mk_certs.rs index e944af06bc..48538c7a74 100644 --- a/openssl/examples/mk_certs.rs +++ b/openssl/examples/mk_certs.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + //! A program that generates ca certs, certs verified by the ca, and public //! and private keys. diff --git a/openssl/src/aes.rs b/openssl/src/aes.rs index 440dd05723..cbc4999bb8 100644 --- a/openssl/src/aes.rs +++ b/openssl/src/aes.rs @@ -23,7 +23,7 @@ //! # Examples #![cfg_attr( - not(boringssl), + all(not(boringssl), not(osslconf = "OPENSSL_NO_DEPRECATED_3_0")), doc = r#"\ ## AES IGE ```rust @@ -156,6 +156,7 @@ impl AesKey { /// Panics if `in_` is not the same length as `out`, if that length is not a multiple of 16, or if /// `iv` is not at least 32 bytes. #[cfg(not(boringssl))] +#[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(AES_ige_encrypt)] pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mode) { unsafe { @@ -268,6 +269,7 @@ mod test { // From https://www.mgp25.com/AESIGE/ #[test] #[cfg(not(boringssl))] + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn ige_vector_1() { let raw_key = "000102030405060708090A0B0C0D0E0F"; let raw_iv = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 7f936837db..801310d411 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -27,8 +27,8 @@ use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_long, time_t}; -#[cfg(ossl102)] use std::cmp::Ordering; +use std::convert::TryInto; use std::ffi::CString; use std::fmt; use std::ptr; @@ -39,6 +39,7 @@ use crate::bio::MemBio; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; use crate::nid::Nid; +use crate::stack::Stackable; use crate::string::OpensslString; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -187,7 +188,7 @@ foreign_type_and_impl_send_sync! { /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementation /// used by OpenSSL. /// - /// [ASN_TIME_set]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_set.html + /// [ASN_TIME_set]: https://www.openssl.org/docs/manmaster/crypto/ASN1_TIME_set.html pub struct Asn1Time; /// Reference to an [`Asn1Time`] /// @@ -423,7 +424,7 @@ foreign_type_and_impl_send_sync! { /// structures. This implementation uses [ASN1_STRING-to_UTF8] to preserve /// compatibility with Rust's String. /// - /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_STRING_to_UTF8.html + /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/manmaster/crypto/ASN1_STRING_to_UTF8.html pub struct Asn1String; /// A reference to an [`Asn1String`]. pub struct Asn1StringRef; @@ -492,7 +493,7 @@ foreign_type_and_impl_send_sync! { /// OpenSSL documentation includes [`ASN1_INTEGER_set`]. /// /// [`bn`]: ../bn/index.html - /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html + /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/manmaster/crypto/ASN1_INTEGER_set.html pub struct Asn1Integer; /// A reference to an [`Asn1Integer`]. pub struct Asn1IntegerRef; @@ -504,15 +505,32 @@ impl Asn1Integer { /// Corresponds to [`BN_to_ASN1_INTEGER`]. Also see /// [`BigNumRef::to_asn1_integer`]. /// - /// [`BN_to_ASN1_INTEGER`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_to_ASN1_INTEGER.html + /// [`BN_to_ASN1_INTEGER`]: https://www.openssl.org/docs/manmaster/crypto/BN_to_ASN1_INTEGER.html /// [`BigNumRef::to_asn1_integer`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer pub fn from_bn(bn: &BigNumRef) -> Result { bn.to_asn1_integer() } } +impl Ord for Asn1Integer { + fn cmp(&self, other: &Self) -> Ordering { + Asn1IntegerRef::cmp(self, other) + } +} +impl PartialOrd for Asn1Integer { + fn partial_cmp(&self, other: &Asn1Integer) -> Option { + Some(self.cmp(other)) + } +} +impl Eq for Asn1Integer {} +impl PartialEq for Asn1Integer { + fn eq(&self, other: &Asn1Integer) -> bool { + Asn1IntegerRef::eq(self, other) + } +} + impl Asn1IntegerRef { - #[allow(missing_docs)] + #[allow(missing_docs, clippy::unnecessary_cast)] #[deprecated(since = "0.10.6", note = "use to_bn instead")] pub fn get(&self) -> i64 { unsafe { ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 } @@ -535,6 +553,30 @@ impl Asn1IntegerRef { pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } } + + /// Creates a new Asn1Integer with the same value. + #[corresponds(ASN1_INTEGER_dup)] + pub fn to_owned(&self) -> Result { + unsafe { cvt_p(ffi::ASN1_INTEGER_dup(self.as_ptr())).map(|p| Asn1Integer::from_ptr(p)) } + } +} + +impl Ord for Asn1IntegerRef { + fn cmp(&self, other: &Self) -> Ordering { + let res = unsafe { ffi::ASN1_INTEGER_cmp(self.as_ptr(), other.as_ptr()) }; + res.cmp(&0) + } +} +impl PartialOrd for Asn1IntegerRef { + fn partial_cmp(&self, other: &Asn1IntegerRef) -> Option { + Some(self.cmp(other)) + } +} +impl Eq for Asn1IntegerRef {} +impl PartialEq for Asn1IntegerRef { + fn eq(&self, other: &Asn1IntegerRef) -> bool { + self.cmp(other) == Ordering::Equal + } } foreign_type_and_impl_send_sync! { @@ -570,9 +612,50 @@ impl Asn1BitStringRef { } } +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_OCTET_STRING; + fn drop = ffi::ASN1_OCTET_STRING_free; + /// ASN.1 OCTET STRING type + pub struct Asn1OctetString; + /// A reference to an [`Asn1OctetString`]. + pub struct Asn1OctetStringRef; +} + +impl Asn1OctetString { + /// Creates an Asn1OctetString from bytes + pub fn new_from_bytes(value: &[u8]) -> Result { + ffi::init(); + unsafe { + let s = cvt_p(ffi::ASN1_OCTET_STRING_new())?; + ffi::ASN1_OCTET_STRING_set(s, value.as_ptr(), value.len().try_into().unwrap()); + Ok(Self::from_ptr(s)) + } + } +} + +impl Asn1OctetStringRef { + /// Returns the octet string as an array of bytes. + #[corresponds(ASN1_STRING_get0_data)] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) } + } + + /// Returns the number of bytes in the octet string. + #[corresponds(ASN1_STRING_length)] + pub fn len(&self) -> usize { + unsafe { ffi::ASN1_STRING_length(self.as_ptr().cast()) as usize } + } + + /// Determines if the string is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_OBJECT; fn drop = ffi::ASN1_OBJECT_free; + fn clone = ffi::OBJ_dup; /// Object Identifier /// @@ -586,12 +669,16 @@ foreign_type_and_impl_send_sync! { /// /// [`Nid`]: ../nid/index.html /// [`nid::COMMONNAME`]: ../nid/constant.COMMONNAME.html - /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_obj2nid.html + /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/manmaster/crypto/OBJ_obj2nid.html pub struct Asn1Object; /// A reference to an [`Asn1Object`]. pub struct Asn1ObjectRef; } +impl Stackable for Asn1Object { + type StackType = ffi::stack_st_ASN1_OBJECT; +} + impl Asn1Object { /// Constructs an ASN.1 Object Identifier from a string representation of the OID. #[corresponds(OBJ_txt2obj)] @@ -651,7 +738,7 @@ impl fmt::Debug for Asn1ObjectRef { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::ASN1_STRING_get0_data; } else { #[allow(bad_style)] @@ -661,6 +748,32 @@ cfg_if! { } } +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_ENUMERATED; + fn drop = ffi::ASN1_ENUMERATED_free; + + /// An ASN.1 enumerated. + pub struct Asn1Enumerated; + /// A reference to an [`Asn1Enumerated`]. + pub struct Asn1EnumeratedRef; +} + +impl Asn1EnumeratedRef { + /// Get the value, if it fits in the required bounds. + #[corresponds(ASN1_ENUMERATED_get_int64)] + #[cfg(ossl110)] + pub fn get_i64(&self) -> Result { + let mut crl_reason = 0; + unsafe { + cvt(ffi::ASN1_ENUMERATED_get_int64( + &mut crl_reason, + self.as_ptr(), + ))?; + } + Ok(crl_reason) + } +} + #[cfg(test)] mod tests { use super::*; @@ -744,6 +857,28 @@ mod tests { assert!(c_ref < a_ref); } + #[test] + fn integer_to_owned() { + let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); + let b = a.to_owned().unwrap(); + assert_eq!( + a.to_bn().unwrap().to_dec_str().unwrap().to_string(), + b.to_bn().unwrap().to_dec_str().unwrap().to_string(), + ); + assert_ne!(a.as_ptr(), b.as_ptr()); + } + + #[test] + fn integer_cmp() { + let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); + let b = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); + let c = Asn1Integer::from_bn(&BigNum::from_dec_str("43").unwrap()).unwrap(); + assert!(a == b); + assert!(a != c); + assert!(a < c); + assert!(c > b); + } + #[test] fn object_from_str() { let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap(); @@ -766,4 +901,11 @@ mod tests { &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01], ); } + + #[test] + fn asn1_octet_string() { + let octet_string = Asn1OctetString::new_from_bytes(b"hello world").unwrap(); + assert_eq!(octet_string.as_slice(), b"hello world"); + assert_eq!(octet_string.len(), 11); + } } diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 6a72552adc..0f54935a6b 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -25,7 +25,7 @@ impl<'a> MemBioSlice<'a> { let bio = unsafe { cvt_p(BIO_new_mem_buf( buf.as_ptr() as *const _, - buf.len() as c_int, + buf.len() as crate::SLenType, ))? }; @@ -74,7 +74,7 @@ impl MemBio { } cfg_if! { - if #[cfg(ossl102)] { + if #[cfg(any(ossl102, boringssl))] { use ffi::BIO_new_mem_buf; } else { #[allow(bad_style)] diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index 2619b5ba63..5cfe4b375d 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -91,7 +91,7 @@ foreign_type_and_impl_send_sync! { /// to allocate. BigNumContext and the OpenSSL [`BN_CTX`] structure are used /// internally when passing BigNum values between subroutines. /// - /// [`BN_CTX`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_new.html + /// [`BN_CTX`]: https://www.openssl.org/docs/manmaster/crypto/BN_CTX_new.html pub struct BigNumContext; /// Reference to [`BigNumContext`] /// @@ -134,7 +134,7 @@ foreign_type_and_impl_send_sync! { /// /// [`new`]: struct.BigNum.html#method.new /// [`Dref`]: struct.BigNum.html#deref-methods - /// [`BN_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_new.html + /// [`BN_new`]: https://www.openssl.org/docs/manmaster/crypto/BN_new.html /// /// # Examples /// ``` @@ -217,6 +217,7 @@ impl BigNumRef { } /// The cryptographically weak counterpart to `rand_in_range`. + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_pseudo_rand_range)] pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_pseudo_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) } @@ -336,6 +337,7 @@ impl BigNumRef { /// Returns the number of significant bits in `self`. #[corresponds(BN_num_bits)] + #[allow(clippy::unnecessary_cast)] pub fn num_bits(&self) -> i32 { unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 } } @@ -384,6 +386,7 @@ impl BigNumRef { } /// The cryptographically weak counterpart to `rand`. Not suitable for key generation. + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_pseudo_rand)] #[allow(clippy::useless_conversion)] pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> { @@ -721,6 +724,7 @@ impl BigNumRef { /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_is_prime_ex)] #[allow(clippy::useless_conversion)] pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result { @@ -744,6 +748,7 @@ impl BigNumRef { /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_is_prime_fasttest_ex)] #[allow(clippy::useless_conversion)] pub fn is_prime_fasttest( @@ -809,7 +814,7 @@ impl BigNumRef { /// assert_eq!(&bn_vec, &[0, 0, 0x45, 0x43]); /// ``` #[corresponds(BN_bn2binpad)] - #[cfg(ossl110)] + #[cfg(any(ossl110, libressl340, boringssl))] pub fn to_vec_padded(&self, pad_to: i32) -> Result, ErrorStack> { let mut v = Vec::with_capacity(pad_to as usize); unsafe { @@ -1058,7 +1063,7 @@ impl BigNum { /// /// OpenSSL documentation at [`BN_bin2bn`] /// - /// [`BN_bin2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_bin2bn.html + /// [`BN_bin2bn`]: https://www.openssl.org/docs/manmaster/crypto/BN_bin2bn.html /// /// ``` /// # use openssl::bn::BigNum; @@ -1387,6 +1392,7 @@ mod tests { assert_eq!(a, &(&a << 1) >> 1); } + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[test] fn test_rand_range() { let range = BigNum::from_u32(909_829_283).unwrap(); @@ -1395,6 +1401,7 @@ mod tests { assert!(result >= BigNum::from_u32(0).unwrap() && result < range); } + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[test] fn test_pseudo_rand_range() { let range = BigNum::from_u32(909_829_283).unwrap(); @@ -1403,6 +1410,7 @@ mod tests { assert!(result >= BigNum::from_u32(0).unwrap() && result < range); } + #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[test] fn test_prime_numbers() { let a = BigNum::from_u32(19_029_017).unwrap(); diff --git a/openssl/src/cipher.rs b/openssl/src/cipher.rs index ab5f49d22f..87f7660cde 100644 --- a/openssl/src/cipher.rs +++ b/openssl/src/cipher.rs @@ -324,6 +324,7 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cfb64() as *mut _) } } + #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn rc4() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_rc4() as *mut _) } } @@ -358,12 +359,12 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ecb() as *mut _) } } - #[cfg(not(boringssl))] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] pub fn cast5_cfb64() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cfb64() as *mut _) } } - #[cfg(not(boringssl))] + #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))] pub fn cast5_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ecb() as *mut _) } } diff --git a/openssl/src/cipher_ctx.rs b/openssl/src/cipher_ctx.rs index c0377d969b..216c09e5b0 100644 --- a/openssl/src/cipher_ctx.rs +++ b/openssl/src/cipher_ctx.rs @@ -379,49 +379,6 @@ impl CipherCtxRef { unsafe { ffi::EVP_CIPHER_CTX_num(self.as_ptr()) as usize } } - /// Returns number of bytes cached in partial block update. - #[cfg(ossl110)] - fn used_block_size(&self) -> usize { - self.num() - } - - /// Returns maximum number of bytes that could be cached. - #[cfg(not(ossl110))] - fn used_block_size(&self) -> usize { - self.block_size() - } - - /// Calculate the minimal size of the output buffer given the - /// input buffer size. - /// - /// For streaming ciphers the minimal output size is the same as - /// the input size. For block ciphers the minimal output size - /// additionally depends on the partial blocks that might have - /// been written in previous calls to [`Self::cipher_update`]. - /// - /// This function takes into account the number of partially - /// written blocks for block ciphers for supported targets - /// (OpenSSL >= 1.1). For unsupported targets the number of - /// partially written bytes is assumed to contain one full block - /// (pessimistic case). - /// - /// # Panics - /// - /// Panics if the context has not been initialized with a cipher. - pub fn minimal_output_size(&self, inlen: usize) -> usize { - let block_size = self.block_size(); - if block_size > 1 { - // block cipher - let num = self.used_block_size(); - let total_size = inlen + num; - let num_blocks = total_size / block_size; - num_blocks * block_size - } else { - // streaming cipher - inlen - } - } - /// Sets the length of the IV expected by this context. /// /// Only some ciphers support configurable IV lengths. @@ -429,7 +386,7 @@ impl CipherCtxRef { /// # Panics /// /// Panics if the context has not been initialized with a cipher. - #[corresponds(EVP_CIHPER_CTX_ctrl)] + #[corresponds(EVP_CIPHER_CTX_ctrl)] pub fn set_iv_length(&mut self, len: usize) -> Result<(), ErrorStack> { self.assert_cipher(); @@ -569,7 +526,11 @@ impl CipherCtxRef { output: Option<&mut [u8]>, ) -> Result { if let Some(output) = &output { - let min_output_size = self.minimal_output_size(input.len()); + let mut block_size = self.block_size(); + if block_size == 1 { + block_size = 0; + } + let min_output_size = input.len() + block_size; assert!( output.len() >= min_output_size, "Output buffer size should be at least {} bytes.", @@ -588,16 +549,13 @@ impl CipherCtxRef { /// /// This function is the same as [`Self::cipher_update`] but with the /// output size check removed. It can be used when the exact - /// buffer size control is maintained by the caller and the - /// underlying cryptographic library doesn't expose exact block - /// cache data (e.g. OpenSSL < 1.1, BoringSSL, LibreSSL). + /// buffer size control is maintained by the caller. /// /// SAFETY: The caller is expected to provide `output` buffer /// large enough to contain correct number of bytes. For streaming /// ciphers the output buffer size should be at least as big as /// the input buffer. For block ciphers the size of the output - /// buffer depends on the state of partially updated blocks (see - /// [`Self::minimal_output_size`]). + /// buffer depends on the state of partially updated blocks. #[corresponds(EVP_CipherUpdate)] pub unsafe fn cipher_update_unchecked( &mut self, @@ -633,6 +591,50 @@ impl CipherCtxRef { Ok(len) } + /// Like [`Self::cipher_update`] except that it writes output into the + /// `data` buffer. The `inlen` parameter specifies the number of bytes in + /// `data` that are considered the input. For streaming ciphers, the size of + /// `data` must be at least the input size. Otherwise, it must be at least + /// an additional block size larger. + /// + /// Note: Use [`Self::cipher_update`] with no output argument to write AAD. + /// + /// # Panics + /// + /// This function panics if the input size cannot be represented as `int` or + /// exceeds the buffer size, or if the output buffer does not contain enough + /// additional space. + #[corresponds(EVP_CipherUpdate)] + pub fn cipher_update_inplace( + &mut self, + data: &mut [u8], + inlen: usize, + ) -> Result { + assert!(inlen <= data.len(), "Input size may not exceed buffer size"); + let block_size = self.block_size(); + if block_size != 1 { + assert!( + data.len() >= inlen + block_size, + "Output buffer size must be at least {} bytes.", + inlen + block_size + ); + } + + let inlen = c_int::try_from(inlen).unwrap(); + let mut outlen = 0; + unsafe { + cvt(ffi::EVP_CipherUpdate( + self.as_ptr(), + data.as_mut_ptr(), + &mut outlen, + data.as_ptr(), + inlen, + )) + }?; + + Ok(outlen as usize) + } + /// Finalizes the encryption or decryption process. /// /// Any remaining data will be written to the output buffer. @@ -649,14 +651,34 @@ impl CipherCtxRef { assert!(output.len() >= block_size); } + unsafe { self.cipher_final_unchecked(output) } + } + + /// Finalizes the encryption or decryption process. + /// + /// Any remaining data will be written to the output buffer. + /// + /// Returns the number of bytes written to `output`. + /// + /// This function is the same as [`Self::cipher_final`] but with + /// the output buffer size check removed. + /// + /// SAFETY: The caller is expected to provide `output` buffer + /// large enough to contain correct number of bytes. For streaming + /// ciphers the output buffer can be empty, for block ciphers the + /// output buffer should be at least as big as the block. + #[corresponds(EVP_CipherFinal)] + pub unsafe fn cipher_final_unchecked( + &mut self, + output: &mut [u8], + ) -> Result { let mut outl = 0; - unsafe { - cvt(ffi::EVP_CipherFinal( - self.as_ptr(), - output.as_mut_ptr(), - &mut outl, - ))?; - } + + cvt(ffi::EVP_CipherFinal( + self.as_ptr(), + output.as_mut_ptr(), + &mut outl, + ))?; Ok(outl as usize) } @@ -757,75 +779,6 @@ mod test { aes_128_cbc(cipher); } - #[test] - #[cfg(ossl110)] - fn partial_block_updates() { - test_block_cipher_for_partial_block_updates(Cipher::aes_128_cbc()); - test_block_cipher_for_partial_block_updates(Cipher::aes_256_cbc()); - test_block_cipher_for_partial_block_updates(Cipher::des_ede3_cbc()); - } - - #[cfg(ossl110)] - fn test_block_cipher_for_partial_block_updates(cipher: &'static CipherRef) { - let mut key = vec![0; cipher.key_length()]; - rand_bytes(&mut key).unwrap(); - let mut iv = vec![0; cipher.iv_length()]; - rand_bytes(&mut iv).unwrap(); - - let mut ctx = CipherCtx::new().unwrap(); - - ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) - .unwrap(); - ctx.set_padding(false); - - let block_size = cipher.block_size(); - assert!(block_size > 1, "Need a block cipher, not a stream cipher"); - - // update cipher with non-full block - // expect no output until a block is complete - let outlen = ctx - .cipher_update(&vec![0; block_size - 1], Some(&mut [0; 0])) - .unwrap(); - assert_eq!(0, outlen); - - // update cipher with missing bytes from the previous block - // and one additional block, output should contain two blocks - let mut two_blocks = vec![0; block_size * 2]; - let outlen = ctx - .cipher_update(&vec![0; block_size + 1], Some(&mut two_blocks)) - .unwrap(); - assert_eq!(block_size * 2, outlen); - - ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); - - // try to decrypt - ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) - .unwrap(); - ctx.set_padding(false); - - // update cipher with non-full block - // expect no output until a block is complete - let outlen = ctx - .cipher_update(&two_blocks[0..block_size - 1], Some(&mut [0; 0])) - .unwrap(); - assert_eq!(0, outlen); - - // update cipher with missing bytes from the previous block - // and one additional block, output should contain two blocks - let mut two_blocks_decrypted = vec![0; block_size * 2]; - let outlen = ctx - .cipher_update( - &two_blocks[block_size - 1..], - Some(&mut two_blocks_decrypted), - ) - .unwrap(); - assert_eq!(block_size * 2, outlen); - - ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); - // check if the decrypted blocks are the same as input (all zeros) - assert_eq!(two_blocks_decrypted, vec![0; block_size * 2]); - } - #[test] fn test_stream_ciphers() { test_stream_cipher(Cipher::aes_192_ctr()); @@ -869,6 +822,26 @@ mod test { ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); + // encrypt again, but use in-place encryption this time + // First reset the IV + ctx.encrypt_init(None, None, Some(&iv)).unwrap(); + ctx.set_padding(false); + let mut data_inplace: [u8; 32] = [1; 32]; + let outlen = ctx + .cipher_update_inplace(&mut data_inplace[0..15], 15) + .unwrap(); + assert_eq!(15, outlen); + + let outlen = ctx + .cipher_update_inplace(&mut data_inplace[15..32], 17) + .unwrap(); + assert_eq!(17, outlen); + + ctx.cipher_final(&mut [0u8; 0]).unwrap(); + + // Check that the resulting data is encrypted in the same manner + assert_eq!(data_inplace.as_slice(), output.as_slice()); + // try to decrypt ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) .unwrap(); @@ -891,46 +864,35 @@ mod test { ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); // check if the decrypted blocks are the same as input (all ones) assert_eq!(output_decrypted, vec![1; 32]); - } - #[test] - #[should_panic(expected = "Output buffer size should be at least 16 bytes.")] - #[cfg(ossl110)] - fn full_block_updates_aes_128() { - output_buffer_too_small(Cipher::aes_128_cbc()); - } + // decrypt again, but now the output in-place + ctx.decrypt_init(None, None, Some(&iv)).unwrap(); + ctx.set_padding(false); - #[test] - #[should_panic(expected = "Output buffer size should be at least 16 bytes.")] - #[cfg(ossl110)] - fn full_block_updates_aes_256() { - output_buffer_too_small(Cipher::aes_256_cbc()); - } + let outlen = ctx.cipher_update_inplace(&mut output[0..15], 15).unwrap(); + assert_eq!(15, outlen); - #[test] - #[should_panic(expected = "Output buffer size should be at least 8 bytes.")] - #[cfg(ossl110)] - fn full_block_updates_3des() { - output_buffer_too_small(Cipher::des_ede3_cbc()); + let outlen = ctx.cipher_update_inplace(&mut output[15..], 17).unwrap(); + assert_eq!(17, outlen); + + ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); + assert_eq!(output_decrypted, output); } #[test] - #[should_panic(expected = "Output buffer size should be at least 32 bytes.")] - #[cfg(not(ossl110))] + #[should_panic(expected = "Output buffer size should be at least 33 bytes.")] fn full_block_updates_aes_128() { output_buffer_too_small(Cipher::aes_128_cbc()); } #[test] - #[should_panic(expected = "Output buffer size should be at least 32 bytes.")] - #[cfg(not(ossl110))] + #[should_panic(expected = "Output buffer size should be at least 33 bytes.")] fn full_block_updates_aes_256() { output_buffer_too_small(Cipher::aes_256_cbc()); } #[test] - #[should_panic(expected = "Output buffer size should be at least 16 bytes.")] - #[cfg(not(ossl110))] + #[should_panic(expected = "Output buffer size should be at least 17 bytes.")] fn full_block_updates_3des() { output_buffer_too_small(Cipher::des_ede3_cbc()); } diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 185c4dfa94..6b6aa9fd8c 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -15,7 +15,7 @@ use crate::error::ErrorStack; use crate::pkey::{HasPrivate, PKeyRef}; use crate::stack::StackRef; use crate::symm::Cipher; -use crate::x509::{X509Ref, X509}; +use crate::x509::{store::X509StoreRef, X509Ref, X509}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -227,14 +227,65 @@ impl CmsContentInfo { Ok(CmsContentInfo::from_ptr(cms)) } } + + /// Verify this CmsContentInfo's signature, + /// This will search the 'certs' list for the signing certificate. + /// Additional certificates, needed for building the certificate chain, may be + /// given in 'store' as well as additional CRLs. + /// A detached signature may be passed in `detached_data`. The signed content + /// without signature, will be copied into output_data if it is present. + /// + #[corresponds(CMS_verify)] + pub fn verify( + &mut self, + certs: Option<&StackRef>, + store: Option<&X509StoreRef>, + detached_data: Option<&[u8]>, + output_data: Option<&mut Vec>, + flags: CMSOptions, + ) -> Result<(), ErrorStack> { + unsafe { + let certs_ptr = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); + let store_ptr = store.map_or(ptr::null_mut(), |p| p.as_ptr()); + let detached_data_bio = match detached_data { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, + }; + let detached_data_bio_ptr = detached_data_bio + .as_ref() + .map_or(ptr::null_mut(), |p| p.as_ptr()); + let out_bio = MemBio::new()?; + + cvt(ffi::CMS_verify( + self.as_ptr(), + certs_ptr, + store_ptr, + detached_data_bio_ptr, + out_bio.as_ptr(), + flags.bits(), + ))?; + + if let Some(data) = output_data { + data.clear(); + data.extend_from_slice(out_bio.get_buf()); + }; + + Ok(()) + } + } } #[cfg(test)] mod test { use super::*; + use crate::pkcs12::Pkcs12; + use crate::pkey::PKey; use crate::stack::Stack; - use crate::x509::X509; + use crate::x509::{ + store::{X509Store, X509StoreBuilder}, + X509, + }; #[test] fn cms_encrypt_decrypt() { @@ -249,7 +300,7 @@ mod test { let priv_cert_bytes = include_bytes!("../test/cms.p12"); let priv_cert = Pkcs12::from_der(priv_cert_bytes).expect("failed to load priv cert"); let priv_cert = priv_cert - .parse("mypass") + .parse2("mypass") .expect("failed to parse priv cert"); // encrypt cms message using public key cert @@ -274,13 +325,16 @@ mod test { CmsContentInfo::from_der(&encrypted_der).expect("failed read cms from der"); let decrypt_with_cert_check = decrypt - .decrypt(&priv_cert.pkey, &priv_cert.cert) + .decrypt( + priv_cert.pkey.as_ref().unwrap(), + priv_cert.cert.as_ref().unwrap(), + ) .expect("failed to decrypt cms"); let decrypt_with_cert_check = String::from_utf8(decrypt_with_cert_check) .expect("failed to create string from cms content"); let decrypt_without_cert_check = decrypt - .decrypt_without_cert_check(&priv_cert.pkey) + .decrypt_without_cert_check(priv_cert.pkey.as_ref().unwrap()) .expect("failed to decrypt cms"); let decrypt_without_cert_check = String::from_utf8(decrypt_without_cert_check) .expect("failed to create string from cms content"); @@ -296,13 +350,16 @@ mod test { CmsContentInfo::from_pem(&encrypted_pem).expect("failed read cms from pem"); let decrypt_with_cert_check = decrypt - .decrypt(&priv_cert.pkey, &priv_cert.cert) + .decrypt( + priv_cert.pkey.as_ref().unwrap(), + priv_cert.cert.as_ref().unwrap(), + ) .expect("failed to decrypt cms"); let decrypt_with_cert_check = String::from_utf8(decrypt_with_cert_check) .expect("failed to create string from cms content"); let decrypt_without_cert_check = decrypt - .decrypt_without_cert_check(&priv_cert.pkey) + .decrypt_without_cert_check(priv_cert.pkey.as_ref().unwrap()) .expect("failed to decrypt cms"); let decrypt_without_cert_check = String::from_utf8(decrypt_without_cert_check) .expect("failed to create string from cms content"); @@ -311,4 +368,119 @@ mod test { assert_eq!(input, decrypt_without_cert_check); } } + + fn cms_sign_verify_generic_helper(is_detached: bool) { + // load cert with private key + let cert_bytes = include_bytes!("../test/cert.pem"); + let cert = X509::from_pem(cert_bytes).expect("failed to load cert.pem"); + + let key_bytes = include_bytes!("../test/key.pem"); + let key = PKey::private_key_from_pem(key_bytes).expect("failed to load key.pem"); + + let root_bytes = include_bytes!("../test/root-ca.pem"); + let root = X509::from_pem(root_bytes).expect("failed to load root-ca.pem"); + + // sign cms message using public key cert + let data = b"Hello world!"; + + let (opt, ext_data): (CMSOptions, Option<&[u8]>) = if is_detached { + (CMSOptions::DETACHED | CMSOptions::BINARY, Some(data)) + } else { + (CMSOptions::empty(), None) + }; + + let mut cms = CmsContentInfo::sign(Some(&cert), Some(&key), None, Some(data), opt) + .expect("failed to CMS sign a message"); + + // check CMS signature length + let pem_cms = cms + .to_pem() + .expect("failed to pack CmsContentInfo into PEM"); + assert!(!pem_cms.is_empty()); + + // verify CMS signature + let mut builder = X509StoreBuilder::new().expect("failed to create X509StoreBuilder"); + builder + .add_cert(root) + .expect("failed to add root-ca into X509StoreBuilder"); + let store: X509Store = builder.build(); + let mut out_data: Vec = Vec::new(); + let res = cms.verify( + None, + Some(&store), + ext_data, + Some(&mut out_data), + CMSOptions::empty(), + ); + + // check verification result - valid signature + res.unwrap(); + assert_eq!(data.to_vec(), out_data); + } + + #[test] + fn cms_sign_verify_ok() { + cms_sign_verify_generic_helper(false); + } + + #[test] + fn cms_sign_verify_detached_ok() { + cms_sign_verify_generic_helper(true); + } + + #[test] + fn cms_sign_verify_error() { + #[cfg(ossl300)] + let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); + + // load cert with private key + let priv_cert_bytes = include_bytes!("../test/cms.p12"); + let priv_cert = Pkcs12::from_der(priv_cert_bytes).expect("failed to load priv cert"); + let priv_cert = priv_cert + .parse2("mypass") + .expect("failed to parse priv cert"); + + // sign cms message using public key cert + let data = b"Hello world!"; + let mut cms = CmsContentInfo::sign( + Some(&priv_cert.cert.unwrap()), + Some(&priv_cert.pkey.unwrap()), + None, + Some(data), + CMSOptions::empty(), + ) + .expect("failed to CMS sign a message"); + + // check CMS signature length + let pem_cms = cms + .to_pem() + .expect("failed to pack CmsContentInfo into PEM"); + assert!(!pem_cms.is_empty()); + + let empty_store = X509StoreBuilder::new() + .expect("failed to create X509StoreBuilder") + .build(); + + // verify CMS signature + let res = cms.verify( + None, + Some(&empty_store), + Some(data), + None, + CMSOptions::empty(), + ); + + // check verification result - this is an invalid signature + // defined in openssl crypto/cms/cms.h + const CMS_R_CERTIFICATE_VERIFY_ERROR: i32 = 100; + match res { + Err(es) => { + let error_array = es.errors(); + assert_eq!(1, error_array.len()); + let code = error_array[0].code(); + assert_eq!(ffi::ERR_GET_REASON(code), CMS_R_CERTIFICATE_VERIFY_ERROR); + } + _ => panic!("expected CMS verification error, got Ok()"), + } + } } diff --git a/openssl/src/conf.rs b/openssl/src/conf.rs index 2c54cf28d0..715519c595 100644 --- a/openssl/src/conf.rs +++ b/openssl/src/conf.rs @@ -20,6 +20,7 @@ mod methods { impl ConfMethod { /// Retrieve handle to the default OpenSSL configuration file processing function. #[corresponds(NCONF_default)] + #[allow(clippy::should_implement_trait)] pub fn default() -> ConfMethod { unsafe { ffi::init(); diff --git a/openssl/src/derive.rs b/openssl/src/derive.rs index 87a04a14a3..424c5f92d7 100644 --- a/openssl/src/derive.rs +++ b/openssl/src/derive.rs @@ -56,6 +56,7 @@ use std::ptr; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; /// A type used to derive a shared secret between two keys. pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>); @@ -69,7 +70,7 @@ impl<'a> Deriver<'a> { /// /// This corresponds to [`EVP_PKEY_derive_init`]. /// - /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html pub fn new(key: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, @@ -82,10 +83,7 @@ impl<'a> Deriver<'a> { } /// Sets the peer key used for secret derivation. - /// - /// This corresponds to [`EVP_PKEY_derive_set_peer`]: - /// - /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + #[corresponds(EVP_PKEY_derive_set_peer)] pub fn set_peer(&mut self, key: &'a PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, @@ -93,6 +91,29 @@ impl<'a> Deriver<'a> { unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) } } + /// Sets the peer key used for secret derivation along with optionally validating the peer public key. + /// + /// Requires OpenSSL 3.0.0 or newer. + #[corresponds(EVP_PKEY_derive_set_peer_ex)] + #[cfg(ossl300)] + pub fn set_peer_ex( + &mut self, + key: &'a PKeyRef, + validate_peer: bool, + ) -> Result<(), ErrorStack> + where + T: HasPublic, + { + unsafe { + cvt(ffi::EVP_PKEY_derive_set_peer_ex( + self.0, + key.as_ptr(), + validate_peer as i32, + )) + .map(|_| ()) + } + } + /// Returns the size of the shared secret. /// /// It can be used to size the buffer passed to [`Deriver::derive`]. @@ -100,7 +121,7 @@ impl<'a> Deriver<'a> { /// This corresponds to [`EVP_PKEY_derive`]. /// /// [`Deriver::derive`]: #method.derive - /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html pub fn len(&mut self) -> Result { unsafe { let mut len = 0; @@ -114,7 +135,7 @@ impl<'a> Deriver<'a> { /// /// This corresponds to [`EVP_PKEY_derive`]. /// - /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html pub fn derive(&mut self, buf: &mut [u8]) -> Result { let mut len = buf.len(); unsafe { @@ -179,4 +200,18 @@ mod test { let shared = deriver.derive_to_vec().unwrap(); assert!(!shared.is_empty()); } + + #[test] + #[cfg(ossl300)] + fn test_ec_key_derive_ex() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let ec_key2 = EcKey::generate(&group).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); + let mut deriver = Deriver::new(&pkey).unwrap(); + deriver.set_peer_ex(&pkey2, true).unwrap(); + let shared = deriver.derive_to_vec().unwrap(); + assert!(!shared.is_empty()); + } } diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 12170b994e..7445e3408c 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -7,7 +7,7 @@ use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; -use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private}; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -39,6 +39,16 @@ where params_to_der, ffi::i2d_DHparams } + + /// Validates DH parameters for correctness + #[corresponds(DH_check_key)] + pub fn check_key(&self) -> Result { + unsafe { + let mut codes = 0; + cvt(ffi::DH_check(self.as_ptr(), &mut codes))?; + Ok(codes == 0) + } + } } impl Dh { @@ -66,6 +76,16 @@ impl Dh { } } + /// Sets the public key on the DH object. + pub fn set_public_key(self, pub_key: BigNum) -> Result, ErrorStack> { + unsafe { + let dh_ptr = self.0; + cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), ptr::null_mut()))?; + mem::forget((self, pub_key)); + Ok(Dh::from_ptr(dh_ptr)) + } + } + /// Sets the private key on the DH object and recomputes the public key. pub fn set_private_key(self, priv_key: BigNum) -> Result, ErrorStack> { unsafe { @@ -79,6 +99,16 @@ impl Dh { } } + /// Sets the public and private keys on the DH object. + pub fn set_key(self, pub_key: BigNum, priv_key: BigNum) -> Result, ErrorStack> { + unsafe { + let dh_ptr = self.0; + cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), priv_key.as_ptr()))?; + mem::forget((self, pub_key, priv_key)); + Ok(Dh::from_ptr(dh_ptr)) + } + } + /// Generates DH params based on the given `prime_len` and a fixed `generator` value. #[corresponds(DH_generate_parameters_ex)] pub fn generate_params(prime_len: u32, generator: u32) -> Result, ErrorStack> { @@ -239,7 +269,7 @@ where } cfg_if! { - if #[cfg(any(ossl110, libressl270))] { + if #[cfg(any(ossl110, libressl270, boringssl))] { use ffi::{DH_set0_pqg, DH_get0_pqg, DH_get0_key, DH_set0_key}; } else { #[allow(bad_style)] @@ -367,6 +397,30 @@ mod tests { assert_eq!(key1.private_key(), key2.private_key()); } + #[test] + #[cfg(ossl102)] + fn test_set_keys() { + let dh1 = Dh::get_2048_256().unwrap(); + let key1 = dh1.generate_key().unwrap(); + + let dh2 = Dh::get_2048_256().unwrap(); + let key2 = dh2 + .set_public_key(key1.public_key().to_owned().unwrap()) + .unwrap(); + + assert_eq!(key1.public_key(), key2.public_key()); + + let dh3 = Dh::get_2048_256().unwrap(); + let key3 = dh3 + .set_key( + key1.public_key().to_owned().unwrap(), + key1.private_key().to_owned().unwrap(), + ) + .unwrap(); + assert_eq!(key1.public_key(), key3.public_key()); + assert_eq!(key1.private_key(), key3.private_key()); + } + #[test] fn test_dh_from_pem() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -413,4 +467,14 @@ mod tests { assert_eq!(shared_a, shared_b); } + + #[test] + fn test_dh_check_key() { + let dh1 = Dh::generate_params(512, 2).unwrap(); + let p = BigNum::from_hex_str("04").unwrap(); + let g = BigNum::from_hex_str("02").unwrap(); + let dh2 = Dh::from_pqg(p, None, g).unwrap(); + assert!(dh1.check_key().unwrap()); + assert!(!dh2.check_key().unwrap()); + } } diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 5f59ba8acd..1a63e8ad8f 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -7,6 +7,7 @@ use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; +#[cfg(not(boringssl))] use libc::c_int; use std::fmt; use std::mem; @@ -14,7 +15,7 @@ use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; -use crate::pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; use crate::util::ForeignTypeRefExt; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -37,7 +38,7 @@ generic_foreign_type_and_impl_send_sync! { /// /// OpenSSL documentation at [`DSA_new`] /// - /// [`DSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_new.html + /// [`DSA_new`]: https://www.openssl.org/docs/manmaster/crypto/DSA_new.html /// /// # Examples /// @@ -127,6 +128,13 @@ where ffi::PEM_write_bio_DSAPrivateKey } + to_der! { + /// Serializes the private_key to a DER-encoded `DSAPrivateKey` structure. + #[corresponds(i2d_DSAPrivateKey)] + private_key_to_der, + ffi::i2d_DSAPrivateKey + } + /// Returns a reference to the private key component of `self`. #[corresponds(DSA_get0_key)] pub fn priv_key(&self) -> &BigNumRef { @@ -183,17 +191,21 @@ type BitType = libc::c_uint; #[cfg(not(boringssl))] type BitType = c_int; -impl Dsa { - /// Generate a DSA key pair. - /// - /// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values. - /// These values are used to generate the key pair with [`DSA_generate_key`]. - /// - /// The `bits` parameter corresponds to the length of the prime `p`. - /// - /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_parameters_ex.html - /// [`DSA_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_key.html - pub fn generate(bits: u32) -> Result, ErrorStack> { +impl Dsa { + /// Creates a DSA params based upon the given parameters. + #[corresponds(DSA_set0_pqg)] + pub fn from_pqg(p: BigNum, q: BigNum, g: BigNum) -> Result, ErrorStack> { + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + Ok(dsa) + } + } + + /// Generates DSA params based on the given number of bits. + #[corresponds(DSA_generate_parameters_ex)] + pub fn generate_params(bits: u32) -> Result, ErrorStack> { ffi::init(); unsafe { let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); @@ -206,11 +218,31 @@ impl Dsa { ptr::null_mut(), ptr::null_mut(), ))?; - cvt(ffi::DSA_generate_key(dsa.0))?; Ok(dsa) } } + /// Generates a private key based on the DSA params. + #[corresponds(DSA_generate_key)] + pub fn generate_key(self) -> Result, ErrorStack> { + unsafe { + let dsa_ptr = self.0; + cvt(ffi::DSA_generate_key(dsa_ptr))?; + mem::forget(self); + Ok(Dsa::from_ptr(dsa_ptr)) + } + } +} + +impl Dsa { + /// Generate a DSA key pair. + /// + /// The `bits` parameter corresponds to the length of the prime `p`. + pub fn generate(bits: u32) -> Result, ErrorStack> { + let params = Dsa::generate_params(bits)?; + params.generate_key() + } + /// Create a DSA key pair with the given parameters /// /// `p`, `q` and `g` are the common parameters. @@ -283,7 +315,7 @@ impl fmt::Debug for Dsa { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; } else { #[allow(bad_style)] @@ -462,7 +494,7 @@ impl DsaSigRef { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{DSA_SIG_set0, DSA_SIG_get0}; } else { #[allow(bad_style)] @@ -556,6 +588,24 @@ mod test { assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); } + #[test] + fn test_params() { + let params = Dsa::generate_params(1024).unwrap(); + let p = params.p().to_owned().unwrap(); + let q = params.q().to_owned().unwrap(); + let g = params.g().to_owned().unwrap(); + let key = params.generate_key().unwrap(); + let params2 = Dsa::from_pqg( + key.p().to_owned().unwrap(), + key.q().to_owned().unwrap(), + key.g().to_owned().unwrap(), + ) + .unwrap(); + assert_eq!(p, *params2.p()); + assert_eq!(q, *params2.q()); + assert_eq!(g, *params2.g()); + } + #[test] #[cfg(not(boringssl))] fn test_signature() { diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index 24b3832224..b648aec334 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -57,7 +57,7 @@ impl PointConversionForm { /// Named Curve or Explicit /// /// This type acts as a boolean as to whether the `EcGroup` is named or explicit. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct Asn1Flag(c_int); impl Asn1Flag { @@ -73,7 +73,7 @@ impl Asn1Flag { /// /// OpenSSL documentation at [`EC_GROUP`] /// - /// [`EC_GROUP`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_seed_len.html + /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/crypto/EC_GROUP_get_seed_len.html pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); /// Standard Curves @@ -294,6 +294,12 @@ impl EcGroupRef { } } + /// Gets the flag determining if the group corresponds to a named curve. + #[corresponds(EC_GROUP_get_asn1_flag)] + pub fn asn1_flag(&self) -> Asn1Flag { + unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) } + } + /// Returns the name of the curve, if a name is associated. #[corresponds(EC_GROUP_get_curve_name)] pub fn curve_name(&self) -> Option { @@ -485,7 +491,7 @@ impl EcPointRef { /// Places affine coordinates of a curve over a prime field in the provided /// `x` and `y` `BigNum`s. #[corresponds(EC_POINT_get_affine_coordinates)] - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl350))] pub fn affine_coordinates( &self, group: &EcGroupRef, @@ -1191,7 +1197,7 @@ mod test { assert!(ec_key.check_key().is_ok()); } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl350))] #[test] fn get_affine_coordinates() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); @@ -1265,4 +1271,12 @@ mod test { let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); assert!(!g.is_on_curve(&group2, &mut ctx).unwrap()); } + + #[test] + #[cfg(any(boringssl, ossl111, libressl350))] + fn asn1_flag() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let flag = group.asn1_flag(); + assert_eq!(flag, Asn1Flag::NAMED_CURVE); + } } diff --git a/openssl/src/ecdsa.rs b/openssl/src/ecdsa.rs index 0a960e7b9e..f3b27b3953 100644 --- a/openssl/src/ecdsa.rs +++ b/openssl/src/ecdsa.rs @@ -110,7 +110,7 @@ impl EcdsaSigRef { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; } else { #[allow(bad_style)] diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 3cb10fcca2..d3db0fd414 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -113,7 +113,7 @@ impl<'a> Encrypter<'a> { /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// - /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( @@ -317,7 +317,7 @@ impl<'a> Decrypter<'a> { /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// - /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( diff --git a/openssl/src/error.rs b/openssl/src/error.rs index 58b4d70a38..e097ce6881 100644 --- a/openssl/src/error.rs +++ b/openssl/src/error.rs @@ -198,11 +198,7 @@ impl Error { self.line, self.func.as_ref().map_or(ptr::null(), |s| s.as_ptr()), ); - ffi::ERR_set_error( - ffi::ERR_GET_LIB(self.code), - ffi::ERR_GET_REASON(self.code), - ptr::null(), - ); + ffi::ERR_set_error(self.library_code(), self.reason_code(), ptr::null()); } } @@ -214,9 +210,9 @@ impl Error { let line = self.line.try_into().unwrap(); unsafe { ffi::ERR_put_error( - ffi::ERR_GET_LIB(self.code), + self.library_code(), ffi::ERR_GET_FUNC(self.code), - ffi::ERR_GET_REASON(self.code), + self.reason_code(), self.file.as_ptr(), line, ); @@ -240,6 +236,15 @@ impl Error { } } + /// Returns the raw OpenSSL error constant for the library reporting the + /// error. + // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on + // OpenSSL/LibreSSL they're safe. + #[allow(unused_unsafe)] + pub fn library_code(&self) -> libc::c_int { + unsafe { ffi::ERR_GET_LIB(self.code) } + } + /// Returns the name of the function reporting the error. pub fn function(&self) -> Option> { self.func.as_ref().map(|s| s.as_str()) @@ -257,6 +262,14 @@ impl Error { } } + /// Returns the raw OpenSSL error constant for the reason for the error. + // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on + // OpenSSL/LibreSSL they're safe. + #[allow(unused_unsafe)] + pub fn reason_code(&self) -> libc::c_int { + unsafe { ffi::ERR_GET_REASON(self.code) } + } + /// Returns the name of the source file which encountered the error. pub fn file(&self) -> RetStr<'_> { self.file.as_str() @@ -297,19 +310,22 @@ impl fmt::Debug for Error { } impl fmt::Display for Error { + // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on + // OpenSSL/LibreSSL they're safe. + #[allow(unused_unsafe)] fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "error:{:08X}", self.code())?; match self.library() { Some(l) => write!(fmt, ":{}", l)?, - None => write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))?, + None => write!(fmt, ":lib({})", self.library_code())?, } match self.function() { Some(f) => write!(fmt, ":{}", f)?, - None => write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))?, + None => write!(fmt, ":func({})", unsafe { ffi::ERR_GET_FUNC(self.code()) })?, } match self.reason() { Some(r) => write!(fmt, ":{}", r)?, - None => write!(fmt, ":reason({})", ffi::ERR_GET_REASON(self.code()))?, + None => write!(fmt, ":reason({})", self.reason_code())?, } write!( fmt, @@ -382,3 +398,21 @@ cfg_if! { } } } + +#[cfg(test)] +mod tests { + #[cfg(not(ossl310))] + use crate::nid::Nid; + + #[test] + // Due to a bug in OpenSSL 3.1.0, this test can hang there. Skip for now. + #[cfg(not(ossl310))] + fn test_error_library_code() { + let stack = Nid::create("not-an-oid", "invalid", "invalid").unwrap_err(); + let errors = stack.errors(); + #[cfg(not(boringssl))] + assert_eq!(errors[0].library_code(), ffi::ERR_LIB_ASN1); + #[cfg(boringssl)] + assert_eq!(errors[0].library_code(), ffi::ERR_LIB_OBJ as libc::c_int); + } +} diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 8e27505a02..52d73deed4 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -43,7 +43,7 @@ use crate::nid::Nid; use crate::{cvt, cvt_p}; cfg_if! { - if #[cfg(ossl110)] { + if #[cfg(any(ossl110, boringssl))] { use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; } else { use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; @@ -68,7 +68,7 @@ impl MessageDigest { /// /// This corresponds to [`EVP_get_digestbynid`]. /// - /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html + /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html pub fn from_nid(type_: Nid) -> Option { unsafe { let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); @@ -84,7 +84,7 @@ impl MessageDigest { /// /// This corresponds to [`EVP_get_digestbyname`]. /// - /// [`EVP_get_digestbyname`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html + /// [`EVP_get_digestbyname`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html pub fn from_name(name: &str) -> Option { ffi::init(); let name = CString::new(name).ok()?; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 891651ec53..c2c390cc1b 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,7 +1,7 @@ //! Bindings to OpenSSL //! //! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through -//! 3.x.x and LibreSSL versions 2.5 through 3.4.1 are supported. +//! 3.x.x and LibreSSL versions 2.5 through 3.7.x are supported. //! //! # Building //! @@ -29,7 +29,7 @@ //! //! ```not_rust //! # macOS (Homebrew) -//! $ brew install openssl@1.1 +//! $ brew install openssl@3 //! //! # macOS (MacPorts) //! $ sudo port install openssl @@ -119,6 +119,7 @@ //! ``` #![doc(html_root_url = "https://docs.rs/openssl/0.10")] #![warn(rust_2018_idioms)] +#![allow(clippy::uninlined_format_args)] #[doc(inline)] pub use ffi::init; @@ -164,7 +165,6 @@ pub mod nid; #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_OCSP")))] pub mod ocsp; pub mod pkcs12; -#[cfg(not(boringssl))] pub mod pkcs5; #[cfg(not(boringssl))] pub mod pkcs7; @@ -189,6 +189,11 @@ type LenType = libc::size_t; #[cfg(not(boringssl))] type LenType = libc::c_int; +#[cfg(boringssl)] +type SLenType = libc::ssize_t; +#[cfg(not(boringssl))] +type SLenType = libc::c_int; + #[inline] fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { diff --git a/openssl/src/md_ctx.rs b/openssl/src/md_ctx.rs index c4d3f06b94..156f3c2fc9 100644 --- a/openssl/src/md_ctx.rs +++ b/openssl/src/md_ctx.rs @@ -93,7 +93,7 @@ use std::convert::TryFrom; use std::ptr; cfg_if! { - if #[cfg(ossl110)] { + if #[cfg(any(ossl110, boringssl))] { use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; } else { use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index eadae31653..91fcdeca9d 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -44,20 +44,20 @@ pub struct SignatureAlgorithms { /// The following documentation provides context about `Nid`s and their usage /// in OpenSSL. /// -/// - [Obj_nid2obj](https://www.openssl.org/docs/man1.1.0/crypto/OBJ_create.html) +/// - [Obj_nid2obj](https://www.openssl.org/docs/manmaster/crypto/OBJ_create.html) #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Nid(c_int); #[allow(non_snake_case)] impl Nid { /// Create a `Nid` from an integer representation. - pub fn from_raw(raw: c_int) -> Nid { + pub const fn from_raw(raw: c_int) -> Nid { Nid(raw) } /// Return the integer representation of a `Nid`. #[allow(clippy::trivially_copy_pass_by_ref)] - pub fn as_raw(&self) -> c_int { + pub const fn as_raw(&self) -> c_int { self.0 } @@ -1074,6 +1074,8 @@ impl Nid { pub const AES_128_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_128_cbc_hmac_sha1); pub const AES_192_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_192_cbc_hmac_sha1); pub const AES_256_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_256_cbc_hmac_sha1); + #[cfg(ossl111)] + pub const SM2: Nid = Nid(ffi::NID_sm2); #[cfg(any(ossl111, libressl291))] pub const SM3: Nid = Nid(ffi::NID_sm3); #[cfg(ossl111)] @@ -1165,10 +1167,13 @@ mod test { assert_eq!(nid.short_name().unwrap(), "foo"); assert_eq!(nid.long_name().unwrap(), "foobar"); - let invalid_oid = Nid::create("invalid_oid", "invalid", "invalid"); - assert!( - invalid_oid.is_err(), - "invalid_oid should not return a valid value" - ); + // Due to a bug in OpenSSL 3.1.0, this test crashes on Windows + if !cfg!(ossl310) { + let invalid_oid = Nid::create("invalid_oid", "invalid", "invalid"); + assert!( + invalid_oid.is_err(), + "invalid_oid should not return a valid value" + ); + } } } diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index d4e19dc9f3..d74705eaa8 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -32,30 +32,42 @@ impl Pkcs12Ref { ffi::i2d_PKCS12 } + /// Deprecated. + #[deprecated(note = "Use parse2 instead", since = "0.10.46")] + #[allow(deprecated)] + pub fn parse(&self, pass: &str) -> Result { + let parsed = self.parse2(pass)?; + + Ok(ParsedPkcs12 { + pkey: parsed.pkey.unwrap(), + cert: parsed.cert.unwrap(), + chain: parsed.ca, + }) + } + /// Extracts the contents of the `Pkcs12`. #[corresponds(PKCS12_parse)] - pub fn parse(&self, pass: &str) -> Result { + pub fn parse2(&self, pass: &str) -> Result { unsafe { let pass = CString::new(pass.as_bytes()).unwrap(); let mut pkey = ptr::null_mut(); let mut cert = ptr::null_mut(); - let mut chain = ptr::null_mut(); + let mut ca = ptr::null_mut(); cvt(ffi::PKCS12_parse( self.as_ptr(), pass.as_ptr(), &mut pkey, &mut cert, - &mut chain, + &mut ca, ))?; - let pkey = PKey::from_ptr(pkey); - let cert = X509::from_ptr(cert); - - let chain = Stack::from_ptr_opt(chain); + let pkey = PKey::from_ptr_opt(pkey); + let cert = X509::from_ptr_opt(cert); + let ca = Stack::from_ptr_opt(ca); - Ok(ParsedPkcs12 { pkey, cert, chain }) + Ok(ParsedPkcs12_2 { pkey, cert, ca }) } } } @@ -82,34 +94,78 @@ impl Pkcs12 { ffi::init(); Pkcs12Builder { + name: None, + pkey: None, + cert: None, + ca: None, nid_key: Nid::UNDEF, nid_cert: Nid::UNDEF, iter: ffi::PKCS12_DEFAULT_ITER, mac_iter: ffi::PKCS12_DEFAULT_ITER, #[cfg(not(boringssl))] mac_md: None, - ca: None, } } } +#[deprecated(note = "Use ParsedPkcs12_2 instead", since = "0.10.46")] pub struct ParsedPkcs12 { pub pkey: PKey, pub cert: X509, pub chain: Option>, } +pub struct ParsedPkcs12_2 { + pub pkey: Option>, + pub cert: Option, + pub ca: Option>, +} + pub struct Pkcs12Builder { + // FIXME borrow + name: Option, + pkey: Option>, + cert: Option, + ca: Option>, nid_key: Nid, nid_cert: Nid, iter: c_int, mac_iter: c_int, + // FIXME remove #[cfg(not(boringssl))] mac_md: Option, - ca: Option>, } impl Pkcs12Builder { + /// The `friendlyName` used for the certificate and private key. + pub fn name(&mut self, name: &str) -> &mut Self { + self.name = Some(CString::new(name).unwrap()); + self + } + + /// The private key. + pub fn pkey(&mut self, pkey: &PKeyRef) -> &mut Self + where + T: HasPrivate, + { + let new_pkey = unsafe { PKeyRef::from_ptr(pkey.as_ptr()) }; + self.pkey = Some(new_pkey.to_owned()); + self + } + + /// The certificate. + pub fn cert(&mut self, cert: &X509Ref) -> &mut Self { + self.cert = Some(cert.to_owned()); + self + } + + /// An additional set of certificates to include in the archive beyond the one provided to + /// `build`. + pub fn ca(&mut self, ca: Stack) -> &mut Self { + self.ca = Some(ca); + self + } + /// The encryption algorithm that should be used for the key pub fn key_algorithm(&mut self, nid: Nid) -> &mut Self { self.nid_key = nid; @@ -144,24 +200,13 @@ impl Pkcs12Builder { self } - /// An additional set of certificates to include in the archive beyond the one provided to - /// `build`. - pub fn ca(&mut self, ca: Stack) -> &mut Self { - self.ca = Some(ca); - self - } - - /// Builds the PKCS #12 object - /// - /// # Arguments - /// - /// * `password` - the password used to encrypt the key and certificate - /// * `friendly_name` - user defined name for the certificate - /// * `pkey` - key to store - /// * `cert` - certificate to store - #[corresponds(PKCS12_create)] + /// Deprecated. + #[deprecated( + note = "Use Self::{name, pkey, cert, build2} instead.", + since = "0.10.46" + )] pub fn build( - self, + mut self, password: &str, friendly_name: &str, pkey: &PKeyRef, @@ -170,11 +215,21 @@ impl Pkcs12Builder { where T: HasPrivate, { + self.name(friendly_name) + .pkey(pkey) + .cert(cert) + .build2(password) + } + + /// Builds the PKCS#12 object. + #[corresponds(PKCS12_create)] + pub fn build2(&self, password: &str) -> Result { unsafe { let pass = CString::new(password).unwrap(); - let friendly_name = CString::new(friendly_name).unwrap(); - let pkey = pkey.as_ptr(); - let cert = cert.as_ptr(); + let pass = pass.as_ptr(); + let friendly_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr()); + let pkey = self.pkey.as_ref().map_or(ptr::null(), |p| p.as_ptr()); + let cert = self.cert.as_ref().map_or(ptr::null(), |p| p.as_ptr()); let ca = self .ca .as_ref() @@ -185,14 +240,14 @@ impl Pkcs12Builder { // According to the OpenSSL docs, keytype is a non-standard extension for MSIE, // It's values are KEY_SIG or KEY_EX, see the OpenSSL docs for more information: - // https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html + // https://www.openssl.org/docs/manmaster/crypto/PKCS12_create.html let keytype = 0; let pkcs12 = cvt_p(ffi::PKCS12_create( - pass.as_ptr() as *const _ as *mut _, - friendly_name.as_ptr() as *const _ as *mut _, - pkey, - cert, + pass as *mut _, + friendly_name as *mut _, + pkey as *mut _, + cert as *mut _, ca, nid_key, nid_cert, @@ -213,7 +268,7 @@ impl Pkcs12Builder { cvt(ffi::PKCS12_set_mac( pkcs12.as_ptr(), - pass.as_ptr(), + pass, -1, ptr::null_mut(), 0, @@ -246,14 +301,14 @@ mod test { let der = include_bytes!("../test/identity.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); - let parsed = pkcs12.parse("mypass").unwrap(); + let parsed = pkcs12.parse2("mypass").unwrap(); assert_eq!( - hex::encode(parsed.cert.digest(MessageDigest::sha1()).unwrap()), + hex::encode(parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); - let chain = parsed.chain.unwrap(); + let chain = parsed.ca.unwrap(); assert_eq!(chain.len(), 1); assert_eq!( hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), @@ -268,8 +323,8 @@ mod test { let der = include_bytes!("../test/keystore-empty-chain.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); - let parsed = pkcs12.parse("cassandra").unwrap(); - if let Some(stack) = parsed.chain { + let parsed = pkcs12.parse2("cassandra").unwrap(); + if let Some(stack) = parsed.ca { assert_eq!(stack.len(), 0); } } @@ -302,19 +357,36 @@ mod test { builder.sign(&pkey, MessageDigest::sha256()).unwrap(); let cert = builder.build(); - let pkcs12_builder = Pkcs12::builder(); - let pkcs12 = pkcs12_builder - .build("mypass", subject_name, &pkey, &cert) + let pkcs12 = Pkcs12::builder() + .name(subject_name) + .pkey(&pkey) + .cert(&cert) + .build2("mypass") .unwrap(); let der = pkcs12.to_der().unwrap(); let pkcs12 = Pkcs12::from_der(&der).unwrap(); - let parsed = pkcs12.parse("mypass").unwrap(); + let parsed = pkcs12.parse2("mypass").unwrap(); assert_eq!( - &*parsed.cert.digest(MessageDigest::sha1()).unwrap(), + &*parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap(), &*cert.digest(MessageDigest::sha1()).unwrap() ); - assert!(parsed.pkey.public_eq(&pkey)); + assert!(parsed.pkey.unwrap().public_eq(&pkey)); + } + + #[test] + fn create_only_ca() { + let ca = include_bytes!("../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let mut chain = Stack::new().unwrap(); + chain.push(ca).unwrap(); + + let pkcs12 = Pkcs12::builder().ca(chain).build2("hunter2").unwrap(); + let parsed = pkcs12.parse2("hunter2").unwrap(); + + assert!(parsed.cert.is_none()); + assert!(parsed.pkey.is_none()); + assert_eq!(parsed.ca.unwrap().len(), 1); } } diff --git a/openssl/src/pkcs5.rs b/openssl/src/pkcs5.rs index c15ce47761..cd704e8256 100644 --- a/openssl/src/pkcs5.rs +++ b/openssl/src/pkcs5.rs @@ -1,9 +1,13 @@ +#[cfg(not(boringssl))] use libc::c_int; +use std::convert::TryInto; +#[cfg(not(boringssl))] use std::ptr; use crate::cvt; use crate::error::ErrorStack; use crate::hash::MessageDigest; +#[cfg(not(boringssl))] use crate::symm::Cipher; use openssl_macros::corresponds; @@ -25,6 +29,7 @@ pub struct KeyIvPair { /// `pbkdf2_hmac` or another more modern key derivation algorithm. #[corresponds(EVP_BytesToKey)] #[allow(clippy::useless_conversion)] +#[cfg(not(boringssl))] pub fn bytes_to_key( cipher: Cipher, digest: MessageDigest, @@ -91,19 +96,15 @@ pub fn pbkdf2_hmac( key: &mut [u8], ) -> Result<(), ErrorStack> { unsafe { - assert!(pass.len() <= c_int::max_value() as usize); - assert!(salt.len() <= c_int::max_value() as usize); - assert!(key.len() <= c_int::max_value() as usize); - ffi::init(); cvt(ffi::PKCS5_PBKDF2_HMAC( pass.as_ptr() as *const _, - pass.len() as c_int, + pass.len().try_into().unwrap(), salt.as_ptr(), - salt.len() as c_int, - iter as c_int, + salt.len().try_into().unwrap(), + iter.try_into().unwrap(), hash.as_ptr(), - key.len() as c_int, + key.len().try_into().unwrap(), key.as_mut_ptr(), )) .map(|_| ()) @@ -114,7 +115,8 @@ pub fn pbkdf2_hmac( /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PBE_scrypt)] -#[cfg(any(ossl110))] +#[cfg(any(ossl110, boringssl))] +#[allow(clippy::useless_conversion)] pub fn scrypt( pass: &[u8], salt: &[u8], @@ -134,7 +136,7 @@ pub fn scrypt( n, r, p, - maxmem, + maxmem.try_into().unwrap(), key.as_mut_ptr() as *mut _, key.len(), )) @@ -145,6 +147,7 @@ pub fn scrypt( #[cfg(test)] mod tests { use crate::hash::MessageDigest; + #[cfg(not(boringssl))] use crate::symm::Cipher; // Test vectors from @@ -246,6 +249,7 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn bytes_to_key() { let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8]; @@ -282,7 +286,7 @@ mod tests { } #[test] - #[cfg(any(ossl110))] + #[cfg(any(ossl110, boringssl))] fn scrypt() { let pass = "pleaseletmein"; let salt = "SodiumChloride"; diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 7d438ebadc..453aeed72f 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -47,7 +47,7 @@ use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; use crate::error::ErrorStack; -#[cfg(ossl110)] +#[cfg(any(ossl110, boringssl, libressl370))] use crate::pkey_ctx::PkeyCtx; use crate::rsa::Rsa; use crate::symm::Cipher; @@ -57,7 +57,7 @@ use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long}; use openssl_macros::corresponds; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::ffi::CString; use std::fmt; use std::mem; @@ -85,18 +85,22 @@ impl Id { pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); pub const DH: Id = Id(ffi::EVP_PKEY_DH); pub const EC: Id = Id(ffi::EVP_PKEY_EC); + #[cfg(ossl111)] + pub const SM2: Id = Id(ffi::EVP_PKEY_SM2); - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF); - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519); #[cfg(ossl111)] pub const ED448: Id = Id(ffi::EVP_PKEY_ED448); - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub const X25519: Id = Id(ffi::EVP_PKEY_X25519); #[cfg(ossl111)] pub const X448: Id = Id(ffi::EVP_PKEY_X448); + #[cfg(ossl111)] + pub const POLY1305: Id = Id(ffi::EVP_PKEY_POLY1305); /// Creates a `Id` from an integer representation. pub fn from_raw(value: c_int) -> Id { @@ -229,13 +233,26 @@ where unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } } + ///Returns the number of security bits. + /// + ///Bits of security is defined in NIST SP800-57. + #[corresponds(EVP_PKEY_security_bits)] + #[cfg(any(ossl110, libressl360))] + pub fn security_bits(&self) -> u32 { + unsafe { ffi::EVP_PKEY_security_bits(self.as_ptr()) as u32 } + } + /// Compares the public component of this key with another. #[corresponds(EVP_PKEY_cmp)] pub fn public_eq(&self, other: &PKeyRef) -> bool where U: HasPublic, { - unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } + let res = unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }; + // Clear the stack. OpenSSL will put an error on the stack when the + // keys are different types in some situations. + let _ = ErrorStack::get(); + res } /// Raw byte representation of a public key. @@ -243,7 +260,7 @@ where /// This function only works for algorithms that support raw public keys. /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`]. #[corresponds(EVP_PKEY_get_raw_public_key)] - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn raw_public_key(&self) -> Result, ErrorStack> { unsafe { let mut len = 0; @@ -294,7 +311,7 @@ where /// This function only works for algorithms that support raw private keys. /// Currently this is: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`]. #[corresponds(EVP_PKEY_get_raw_private_key)] - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn raw_private_key(&self) -> Result, ErrorStack> { unsafe { let mut len = 0; @@ -314,12 +331,27 @@ where } } + /// Serializes a private key into an unencrypted DER-formatted PKCS#8 + #[corresponds(i2d_PKCS8PrivateKey_bio)] + pub fn private_key_to_pkcs8(&self) -> Result, ErrorStack> { + unsafe { + let bio = MemBio::new()?; + cvt(ffi::i2d_PKCS8PrivateKey_bio( + bio.as_ptr(), + self.as_ptr(), + ptr::null(), + ptr::null_mut(), + 0, + None, + ptr::null_mut(), + ))?; + + Ok(bio.get_buf().to_owned()) + } + } + /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to /// encrypt the key. - /// - /// # Panics - /// - /// Panics if `passphrase` contains an embedded null. #[corresponds(i2d_PKCS8PrivateKey_bio)] pub fn private_key_to_pkcs8_passphrase( &self, @@ -328,14 +360,12 @@ where ) -> Result, ErrorStack> { unsafe { let bio = MemBio::new()?; - let len = passphrase.len(); - let passphrase = CString::new(passphrase).unwrap(); cvt(ffi::i2d_PKCS8PrivateKey_bio( bio.as_ptr(), self.as_ptr(), cipher.as_ptr(), passphrase.as_ptr() as *const _ as *mut _, - len as ::libc::c_int, + passphrase.len().try_into().unwrap(), None, ptr::null_mut(), ))?; @@ -378,11 +408,7 @@ impl PKey { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_RSA, - rsa.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_RSA(pkey.0, rsa.as_ptr()))?; mem::forget(rsa); Ok(pkey) } @@ -394,11 +420,7 @@ impl PKey { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_DSA, - dsa.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_DSA(pkey.0, dsa.as_ptr()))?; mem::forget(dsa); Ok(pkey) } @@ -406,15 +428,12 @@ impl PKey { /// Creates a new `PKey` containing a Diffie-Hellman key. #[corresponds(EVP_PKEY_assign_DH)] + #[cfg(not(boringssl))] pub fn from_dh(dh: Dh) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_DH, - dh.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_DH(pkey.0, dh.as_ptr()))?; mem::forget(dh); Ok(pkey) } @@ -426,11 +445,7 @@ impl PKey { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_EC, - ec_key.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_EC_KEY(pkey.0, ec_key.as_ptr()))?; mem::forget(ec_key); Ok(pkey) } @@ -475,7 +490,7 @@ impl PKey { ctx.keygen() } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] fn generate_eddsa(id: Id) -> Result, ErrorStack> { let mut ctx = PkeyCtx::new_id(id)?; ctx.keygen_init()?; @@ -505,7 +520,7 @@ impl PKey { /// assert_eq!(secret.len(), 32); /// # Ok(()) } /// ``` - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn generate_x25519() -> Result, ErrorStack> { PKey::generate_eddsa(Id::X25519) } @@ -559,7 +574,7 @@ impl PKey { /// assert_eq!(signature.len(), 64); /// # Ok(()) } /// ``` - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn generate_ed25519() -> Result, ErrorStack> { PKey::generate_eddsa(Id::ED25519) } @@ -709,7 +724,7 @@ impl PKey { /// /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448 #[corresponds(EVP_PKEY_new_raw_private_key)] - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn private_key_from_raw_bytes( bytes: &[u8], key_type: Id, @@ -750,7 +765,7 @@ impl PKey { /// /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448 #[corresponds(EVP_PKEY_new_raw_public_key)] - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn public_key_from_raw_bytes( bytes: &[u8], key_type: Id, @@ -833,6 +848,7 @@ impl TryFrom> for Dsa { } } +#[cfg(not(boringssl))] impl TryFrom> for PKey { type Error = ErrorStack; @@ -857,6 +873,7 @@ mod tests { use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; + use crate::error::Error; use crate::nid::Nid; use crate::rsa::Rsa; use crate::symm::Cipher; @@ -880,7 +897,14 @@ mod tests { #[test] fn test_unencrypted_pkcs8() { let key = include_bytes!("../test/pkcs8-nocrypt.der"); - PKey::private_key_from_pkcs8(key).unwrap(); + let pkey = PKey::private_key_from_pkcs8(key).unwrap(); + let serialized = pkey.private_key_to_pkcs8().unwrap(); + let pkey2 = PKey::private_key_from_pkcs8(&serialized).unwrap(); + + assert_eq!( + pkey2.private_key_to_der().unwrap(), + pkey.private_key_to_der().unwrap() + ); } #[test] @@ -1018,6 +1042,16 @@ mod tests { assert_eq!(ec_key.private_key(), ec_key_.private_key()); } + #[test] + #[cfg(any(ossl110, libressl360))] + fn test_security_bits() { + let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::SECP521R1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let pkey: PKey = ec_key.try_into().unwrap(); + + assert_eq!(pkey.security_bits(), 256); + } + #[test] #[cfg(not(boringssl))] fn test_dh_conversion() { @@ -1039,7 +1073,7 @@ mod tests { assert_eq!(&g, dh_.generator()); } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] fn test_raw_public_key(gen: fn() -> Result, ErrorStack>, key_type: Id) { // Generate a new key let key = gen().unwrap(); @@ -1055,7 +1089,7 @@ mod tests { ); } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] fn test_raw_private_key(gen: fn() -> Result, ErrorStack>, key_type: Id) { // Generate a new key let key = gen().unwrap(); @@ -1066,26 +1100,30 @@ mod tests { // Compare the der encoding of the original and raw / restored public key assert_eq!( - key.private_key_to_der().unwrap(), - from_raw.private_key_to_der().unwrap() + key.private_key_to_pkcs8().unwrap(), + from_raw.private_key_to_pkcs8().unwrap() ); } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] #[test] fn test_raw_public_key_bytes() { test_raw_public_key(PKey::generate_x25519, Id::X25519); test_raw_public_key(PKey::generate_ed25519, Id::ED25519); + #[cfg(all(not(boringssl), not(libressl370)))] test_raw_public_key(PKey::generate_x448, Id::X448); + #[cfg(all(not(boringssl), not(libressl370)))] test_raw_public_key(PKey::generate_ed448, Id::ED448); } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] #[test] fn test_raw_private_key_bytes() { test_raw_private_key(PKey::generate_x25519, Id::X25519); test_raw_private_key(PKey::generate_ed25519, Id::ED25519); + #[cfg(all(not(boringssl), not(libressl370)))] test_raw_private_key(PKey::generate_x448, Id::X448); + #[cfg(all(not(boringssl), not(libressl370)))] test_raw_private_key(PKey::generate_ed448, Id::ED448); } @@ -1119,4 +1157,17 @@ mod tests { let key = PKey::ec_gen("prime256v1").unwrap(); assert!(key.ec_key().is_ok()); } + + #[test] + fn test_public_eq() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey1 = PKey::from_rsa(rsa).unwrap(); + + let group = crate::ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let pkey2 = PKey::from_ec_key(ec_key).unwrap(); + + assert!(!pkey1.public_eq(&pkey2)); + assert!(Error::get().is_none()); + } } diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs index f79372fb11..aba8a66a32 100644 --- a/openssl/src/pkey_ctx.rs +++ b/openssl/src/pkey_ctx.rs @@ -84,8 +84,23 @@ pub struct HkdfMode(c_int); #[cfg(ossl111)] impl HkdfMode { + /// This is the default mode. Calling [`derive`][PkeyCtxRef::derive] on a [`PkeyCtxRef`] set up + /// for HKDF will perform an extract followed by an expand operation in one go. The derived key + /// returned will be the result after the expand operation. The intermediate fixed-length + /// pseudorandom key K is not returned. pub const EXTRACT_THEN_EXPAND: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND); + + /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the extract operation. + /// The value returned will be the intermediate fixed-length pseudorandom key K. + /// + /// The digest, key and salt values must be set before a key is derived or an error occurs. pub const EXTRACT_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY); + + /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the expand operation. + /// The input key should be set to the intermediate fixed-length pseudorandom key K returned + /// from a previous extract operation. + /// + /// The digest, key and info values must be set before a key is derived or an error occurs. pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY); } @@ -470,7 +485,7 @@ impl PkeyCtxRef { /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set_hkdf_md)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { unsafe { @@ -487,6 +502,10 @@ impl PkeyCtxRef { /// /// Defaults to [`HkdfMode::EXTRACT_THEN_EXPAND`]. /// + /// WARNING: Although this API calls it a "mode", HKDF-Extract and HKDF-Expand are distinct + /// operations with distinct inputs and distinct kinds of keys. Callers should not pass input + /// secrets for one operation into the other. + /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(EVP_PKEY_CTX_set_hkdf_mode)] #[cfg(ossl111)] @@ -499,14 +518,22 @@ impl PkeyCtxRef { Ok(()) } - /// Sets the input keying material for HKDF generation. + /// Sets the input material for HKDF generation as the "key". + /// + /// Which input is the key depends on the "mode" (see [`set_hkdf_mode`][Self::set_hkdf_mode]). + /// If [`HkdfMode::EXTRACT_THEN_EXPAND`] or [`HkdfMode::EXTRACT_ONLY`], this function specifies + /// the input keying material (IKM) for HKDF-Extract. If [`HkdfMode::EXPAND_ONLY`], it instead + /// specifies the pseudorandom key (PRK) for HKDF-Expand. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set1_hkdf_key)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { + #[cfg(not(boringssl))] let len = c_int::try_from(key.len()).unwrap(); + #[cfg(boringssl)] + let len = key.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key( @@ -521,12 +548,17 @@ impl PkeyCtxRef { /// Sets the salt value for HKDF generation. /// + /// If performing HKDF-Expand only, this parameter is ignored. + /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set1_hkdf_salt)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> { + #[cfg(not(boringssl))] let len = c_int::try_from(salt.len()).unwrap(); + #[cfg(boringssl)] + let len = salt.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt( @@ -541,12 +573,17 @@ impl PkeyCtxRef { /// Appends info bytes for HKDF generation. /// + /// If performing HKDF-Extract only, this parameter is ignored. + /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_add1_hkdf_info)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> { + #[cfg(not(boringssl))] let len = c_int::try_from(info.len()).unwrap(); + #[cfg(boringssl)] + let len = info.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info( @@ -604,7 +641,7 @@ mod test { #[cfg(not(boringssl))] use crate::cipher::Cipher; use crate::ec::{EcGroup, EcKey}; - #[cfg(any(ossl102, libressl310))] + #[cfg(any(ossl102, libressl310, boringssl))] use crate::md::Md; use crate::nid::Nid; use crate::pkey::PKey; @@ -689,7 +726,7 @@ mod test { } #[test] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] fn hkdf() { let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); ctx.derive_init().unwrap(); diff --git a/openssl/src/provider.rs b/openssl/src/provider.rs index 72d54f41dc..147fadfdbc 100644 --- a/openssl/src/provider.rs +++ b/openssl/src/provider.rs @@ -1,6 +1,6 @@ -use crate::cvt_p; use crate::error::ErrorStack; use crate::lib_ctx::LibCtxRef; +use crate::{cvt, cvt_p}; use foreign_types::{ForeignType, ForeignTypeRef}; use openssl_macros::corresponds; use std::ffi::CString; @@ -58,4 +58,20 @@ impl Provider { Ok(Provider::from_ptr(p)) } } + + /// Specifies the default search path that is to be used for looking for providers in the specified library context. + /// If left unspecified, an environment variable and a fall back default value will be used instead + /// + /// If `ctx` is `None`, the provider will be loaded into the default library context. + #[corresponds(OSSL_PROVIDER_set_default_search_path)] + pub fn set_default_search_path(ctx: Option<&LibCtxRef>, path: &str) -> Result<(), ErrorStack> { + let path = CString::new(path).unwrap(); + unsafe { + cvt(ffi::OSSL_PROVIDER_set_default_search_path( + ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), + path.as_ptr(), + )) + .map(|_| ()) + } + } } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index b5d096744a..f155b12dfe 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -234,6 +234,7 @@ where /// Validates RSA parameters for correctness #[corresponds(RSA_check_key)] + #[allow(clippy::unnecessary_cast)] pub fn check_key(&self) -> Result { unsafe { let result = ffi::RSA_check_key(self.as_ptr()) as i32; @@ -580,7 +581,7 @@ impl fmt::Debug for Rsa { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{ RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors, RSA_set0_crt_params, diff --git a/openssl/src/sha.rs b/openssl/src/sha.rs index dd026677c6..24128904a3 100644 --- a/openssl/src/sha.rs +++ b/openssl/src/sha.rs @@ -57,7 +57,7 @@ pub fn sha1(data: &[u8]) -> [u8; 20] { } /// Computes the SHA224 hash of some data. -#[corresponds(SH224)] +#[corresponds(SHA224)] #[inline] pub fn sha224(data: &[u8]) -> [u8; 28] { unsafe { diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index b675825e2c..a32f5c9144 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -117,10 +117,10 @@ pub struct Signer<'a> { _p: PhantomData<&'a ()>, } -unsafe impl<'a> Sync for Signer<'a> {} -unsafe impl<'a> Send for Signer<'a> {} +unsafe impl Sync for Signer<'_> {} +unsafe impl Send for Signer<'_> {} -impl<'a> Drop for Signer<'a> { +impl Drop for Signer<'_> { fn drop(&mut self) { // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. unsafe { @@ -130,7 +130,7 @@ impl<'a> Drop for Signer<'a> { } #[allow(clippy::len_without_is_empty)] -impl<'a> Signer<'a> { +impl Signer<'_> { /// Creates a new `Signer`. /// /// This cannot be used with Ed25519 or Ed448 keys. Please refer to @@ -139,7 +139,7 @@ impl<'a> Signer<'a> { /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html - pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> + pub fn new<'a, T>(type_: MessageDigest, pkey: &PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { @@ -154,16 +154,16 @@ impl<'a> Signer<'a> { /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html - pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> + pub fn new_without_digest<'a, T>(pkey: &PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { Self::new_intern(None, pkey) } - fn new_intern( + fn new_intern<'a, T>( type_: Option, - pkey: &'a PKeyRef, + pkey: &PKeyRef, ) -> Result, ErrorStack> where T: HasPrivate, @@ -214,7 +214,7 @@ impl<'a> Signer<'a> { /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// - /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( @@ -231,7 +231,7 @@ impl<'a> Signer<'a> { /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. /// - /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( @@ -285,12 +285,12 @@ impl<'a> Signer<'a> { /// /// OpenSSL documentation at [`EVP_DigestSignFinal`]. /// - /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestSignFinal.html pub fn len(&self) -> Result { self.len_intern() } - #[cfg(not(ossl111))] + #[cfg(all(not(ossl111), not(boringssl), not(libressl370)))] fn len_intern(&self) -> Result { unsafe { let mut len = 0; @@ -303,7 +303,7 @@ impl<'a> Signer<'a> { } } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] fn len_intern(&self) -> Result { unsafe { let mut len = 0; @@ -325,7 +325,7 @@ impl<'a> Signer<'a> { /// /// OpenSSL documentation at [`EVP_DigestSignFinal`]. /// - /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestSignFinal.html pub fn sign(&self, buf: &mut [u8]) -> Result { unsafe { let mut len = buf.len(); @@ -360,7 +360,7 @@ impl<'a> Signer<'a> { /// OpenSSL documentation at [`EVP_DigestSign`]. /// /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn sign_oneshot( &mut self, sig_buf: &mut [u8], @@ -382,7 +382,7 @@ impl<'a> Signer<'a> { /// Returns the signature. /// /// This is a simple convenience wrapper over `len` and `sign_oneshot`. - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn sign_oneshot_to_vec(&mut self, data_buf: &[u8]) -> Result, ErrorStack> { let mut sig_buf = vec![0; self.len()?]; let len = self.sign_oneshot(&mut sig_buf, data_buf)?; @@ -507,7 +507,7 @@ impl<'a> Verifier<'a> { /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// - /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( @@ -524,7 +524,7 @@ impl<'a> Verifier<'a> { /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. /// - /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( @@ -596,7 +596,7 @@ impl<'a> Verifier<'a> { /// OpenSSL documentation at [`EVP_DigestVerify`]. /// /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] pub fn verify_oneshot(&mut self, signature: &[u8], buf: &[u8]) -> Result { unsafe { let r = ffi::EVP_DigestVerify( @@ -711,7 +711,7 @@ mod test { #[cfg(not(boringssl))] fn test_hmac(ty: MessageDigest, tests: &[(Vec, Vec, Vec)]) { - for &(ref key, ref data, ref res) in tests.iter() { + for (key, data, res) in tests.iter() { let pkey = PKey::hmac(key).unwrap(); let mut signer = Signer::new(ty, &pkey).unwrap(); signer.update(data).unwrap(); @@ -846,7 +846,7 @@ mod test { } #[test] - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl370))] fn eddsa() { let key = PKey::generate_ed25519().unwrap(); diff --git a/openssl/src/srtp.rs b/openssl/src/srtp.rs index 7ed3135963..595757dc04 100644 --- a/openssl/src/srtp.rs +++ b/openssl/src/srtp.rs @@ -46,10 +46,12 @@ impl SrtpProfileId { SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_32 as c_ulong); pub const SRTP_NULL_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_80 as c_ulong); pub const SRTP_NULL_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_32 as c_ulong); - #[cfg(ossl110)] - pub const SRTP_AEAD_AES_128_GCM: SrtpProfileId = SrtpProfileId(ffi::SRTP_AEAD_AES_128_GCM); - #[cfg(ossl110)] - pub const SRTP_AEAD_AES_256_GCM: SrtpProfileId = SrtpProfileId(ffi::SRTP_AEAD_AES_256_GCM); + #[cfg(any(boringssl, ossl110))] + pub const SRTP_AEAD_AES_128_GCM: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AEAD_AES_128_GCM as c_ulong); + #[cfg(any(boringssl, ossl110))] + pub const SRTP_AEAD_AES_256_GCM: SrtpProfileId = + SrtpProfileId(ffi::SRTP_AEAD_AES_256_GCM as c_ulong); /// Creates a `SrtpProfileId` from an integer representation. pub fn from_raw(value: c_ulong) -> SrtpProfileId { diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs index 45760dc66a..091b1fb771 100644 --- a/openssl/src/ssl/callbacks.rs +++ b/openssl/src/ssl/callbacks.rs @@ -482,7 +482,7 @@ where .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie verify callback missing") as *const F; - let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); + let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len); (*callback)(ssl, slice) as c_int } @@ -654,7 +654,7 @@ where .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext parse callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); - let slice = slice::from_raw_parts(input as *const u8, inlen as usize); + let slice = slice::from_raw_parts(input as *const u8, inlen); let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { Some((chainidx, X509Ref::from_ptr(x))) } else { diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 39f729df90..66d1bd8939 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -11,6 +11,7 @@ use crate::ssl::{ SslOptions, SslRef, SslStream, SslVerifyMode, }; use crate::version; +use std::net::IpAddr; const FFDHE_2048: &str = " -----BEGIN DH PARAMETERS----- @@ -177,9 +178,9 @@ impl ConnectConfiguration { /// Returns an `Ssl` configured to connect to the provided domain. /// - /// The domain is used for SNI and hostname verification if enabled. + /// The domain is used for SNI (if it is not an IP address) and hostname verification if enabled. pub fn into_ssl(mut self, domain: &str) -> Result { - if self.sni { + if self.sni && domain.parse::().is_err() { self.ssl.set_hostname(domain)?; } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 4f349a4e4b..27e817f307 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -72,7 +72,7 @@ use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; use crate::ssl::error::InnerError; -use crate::stack::{Stack, StackRef}; +use crate::stack::{Stack, StackRef, Stackable}; use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, libressl261))] @@ -599,7 +599,7 @@ impl AlpnError { /// Terminate the handshake with a fatal alert. /// /// Requires OpenSSL 1.1.0 or newer. - #[cfg(any(ossl110))] + #[cfg(ossl110)] pub const ALERT_FATAL: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); /// Do not select a protocol, but continue the handshake. @@ -644,6 +644,17 @@ impl SslVersion { /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. #[cfg(any(ossl111, libressl340))] pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION); + + /// DTLSv1.0 + /// + /// DTLS 1.0 corresponds to TLS 1.1. + pub const DTLS1: SslVersion = SslVersion(ffi::DTLS1_VERSION); + + /// DTLSv1.2 + /// + /// DTLS 1.2 corresponds to TLS 1.2 to harmonize versions. There was never a DTLS 1.1. + #[cfg(any(ossl102, libressl332))] + pub const DTLS1_2: SslVersion = SslVersion(ffi::DTLS1_2_VERSION); } cfg_if! { @@ -1047,7 +1058,7 @@ impl SslContextBuilder { /// /// See [`ciphers`] for details on the format. /// - /// [`ciphers`]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html + /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html #[corresponds(SSL_CTX_set_cipher_list)] pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); @@ -1120,7 +1131,7 @@ impl SslContextBuilder { /// Sets the minimum supported protocol version. /// - /// A value of `None` will enable protocol versions down the the lowest version supported by + /// A value of `None` will enable protocol versions down to the lowest version supported by /// OpenSSL. /// /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. @@ -1138,7 +1149,7 @@ impl SslContextBuilder { /// Sets the maximum supported protocol version. /// - /// A value of `None` will enable protocol versions down the the highest version supported by + /// A value of `None` will enable protocol versions up to the highest version supported by /// OpenSSL. /// /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. @@ -1156,7 +1167,7 @@ impl SslContextBuilder { /// Gets the minimum supported protocol version. /// - /// A value of `None` indicates that all versions down the the lowest version supported by + /// A value of `None` indicates that all versions down to the lowest version supported by /// OpenSSL are enabled. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. @@ -1175,7 +1186,7 @@ impl SslContextBuilder { /// Gets the maximum supported protocol version. /// - /// A value of `None` indicates that all versions down the the highest version supported by + /// A value of `None` indicates that all versions up to the highest version supported by /// OpenSSL are enabled. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. @@ -1687,6 +1698,16 @@ impl SslContextBuilder { } } + /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CTX_set_num_tickets)] + #[cfg(ossl111)] + pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.0 @@ -1867,7 +1888,7 @@ impl SslContextRef { /// /// A value of 0 means that the cache size is unbounded. #[corresponds(SSL_CTX_sess_get_cache_size)] - #[allow(clippy::useless_conversion)] + #[allow(clippy::unnecessary_cast)] pub fn session_cache_size(&self) -> i64 { unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()) as i64 } } @@ -1880,6 +1901,16 @@ impl SslContextRef { let mode = unsafe { ffi::SSL_CTX_get_verify_mode(self.as_ptr()) }; SslVerifyMode::from_bits(mode).expect("SSL_CTX_get_verify_mode returned invalid mode") } + + /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_CTX_get_num_tickets)] + #[cfg(ossl111)] + pub fn num_tickets(&self) -> usize { + unsafe { ffi::SSL_CTX_get_num_tickets(self.as_ptr()) } + } } /// Information about the state of a cipher. @@ -1909,6 +1940,10 @@ impl ForeignType for SslCipher { } } +impl Stackable for SslCipher { + type StackType = ffi::stack_st_SSL_CIPHER; +} + impl Deref for SslCipher { type Target = SslCipherRef; @@ -2025,6 +2060,19 @@ impl SslCipherRef { } } +impl fmt::Debug for SslCipherRef { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{}", self.name()) + } +} + +/// A stack of selected ciphers, and a stack of selected signalling cipher suites +#[derive(Debug)] +pub struct CipherLists { + pub suites: Stack, + pub signalling_suites: Stack, +} + foreign_type_and_impl_send_sync! { type CType = ffi::SSL_SESSION; fn drop = ffi::SSL_SESSION_free; @@ -2200,7 +2248,7 @@ impl Ssl { /// /// This corresponds to [`SSL_new`]. /// - /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html + /// [`SSL_new`]: https://www.openssl.org/docs/manmaster/ssl/SSL_new.html #[corresponds(SSL_new)] pub fn new(ctx: &SslContextRef) -> Result { let session_ctx_index = try_get_session_ctx_index()?; @@ -2365,7 +2413,7 @@ impl SslRef { /// /// Requires OpenSSL 1.0.1 or 1.0.2. #[corresponds(SSL_set_tmp_ecdh_callback)] - #[cfg(any(all(ossl101, not(ossl110))))] + #[cfg(all(ossl101, not(ossl110)))] #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where @@ -2507,10 +2555,8 @@ impl SslRef { /// Like [`SslContext::private_key`]. /// - /// This corresponds to `SSL_get_privatekey`. - /// /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key - #[corresponds(SSL_get_certificate)] + #[corresponds(SSL_get_privatekey)] pub fn private_key(&self) -> Option<&PKeyRef> { unsafe { let ptr = ffi::SSL_get_privatekey(self.as_ptr()); @@ -2863,6 +2909,10 @@ impl SslRef { response.len() as c_long, ) as c_int) .map(|_| ()) + .map_err(|e| { + ffi::OPENSSL_free(p); + e + }) } } @@ -3050,6 +3100,41 @@ impl SslRef { } } + /// Decodes a slice of wire-format cipher suite specification bytes. Unsupported cipher suites + /// are ignored. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_bytes_to_cipher_list)] + #[cfg(ossl111)] + pub fn bytes_to_cipher_list( + &self, + bytes: &[u8], + isv2format: bool, + ) -> Result { + unsafe { + let ptr = bytes.as_ptr(); + let len = bytes.len(); + let mut sk = ptr::null_mut(); + let mut scsvs = ptr::null_mut(); + let res = ffi::SSL_bytes_to_cipher_list( + self.as_ptr(), + ptr, + len, + isv2format as c_int, + &mut sk, + &mut scsvs, + ); + if res == 1 { + Ok(CipherLists { + suites: Stack::from_ptr(sk), + signalling_suites: Stack::from_ptr(scsvs), + }) + } else { + Err(ErrorStack::get()) + } + } + } + /// Returns the compression methods field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. @@ -3104,6 +3189,207 @@ impl SslRef { } } } + + #[corresponds(SSL_add0_chain_cert)] + #[cfg(ossl102)] + pub fn add_chain_cert(&mut self, chain: X509) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_add0_chain_cert(self.as_ptr(), chain.as_ptr()) as c_int).map(|_| ())?; + mem::forget(chain); + } + Ok(()) + } + + /// Sets a new default TLS/SSL method for SSL objects + #[cfg(not(boringssl))] + pub fn set_method(&mut self, method: SslMethod) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_ssl_method(self.as_ptr(), method.as_ptr()))?; + }; + Ok(()) + } + + /// Loads the private key from a file. + #[corresponds(SSL_use_Private_Key_file)] + pub fn set_private_key_file>( + &mut self, + path: P, + ssl_file_type: SslFiletype, + ) -> Result<(), ErrorStack> { + let p = path.as_ref().as_os_str().to_str().unwrap(); + let key_file = CString::new(p).unwrap(); + unsafe { + cvt(ffi::SSL_use_PrivateKey_file( + self.as_ptr(), + key_file.as_ptr(), + ssl_file_type.as_raw(), + ))?; + }; + Ok(()) + } + + /// Sets the private key. + #[corresponds(SSL_use_PrivateKey)] + pub fn set_private_key(&mut self, pkey: &PKeyRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), pkey.as_ptr()))?; + }; + Ok(()) + } + + /// Sets the certificate + #[corresponds(SSL_use_certificate)] + pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?; + }; + Ok(()) + } + + /// Loads a certificate chain from a file. + /// + /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf + /// certificate, and the remainder forming the chain of certificates up to and including the + /// trusted root certificate. + #[corresponds(SSL_use_certificate_chain_file)] + #[cfg(any(ossl110, libressl332))] + pub fn set_certificate_chain_file>( + &mut self, + path: P, + ) -> Result<(), ErrorStack> { + let p = path.as_ref().as_os_str().to_str().unwrap(); + let cert_file = CString::new(p).unwrap(); + unsafe { + cvt(ffi::SSL_use_certificate_chain_file( + self.as_ptr(), + cert_file.as_ptr(), + ))?; + }; + Ok(()) + } + + /// Sets ca certificate that client trusted + #[corresponds(SSL_add_client_CA)] + pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_add_client_CA(self.as_ptr(), cacert.as_ptr()))?; + }; + Ok(()) + } + + // Sets the list of CAs sent to the client when requesting a client certificate for the chosen ssl + #[corresponds(SSL_set_client_CA_list)] + pub fn set_client_ca_list(&mut self, list: Stack) { + unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) } + mem::forget(list); + } + + /// Sets the minimum supported protocol version. + /// + /// A value of `None` will enable protocol versions down to the lowest version supported by + /// OpenSSL. + /// + /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_set_min_proto_version)] + #[cfg(any(ossl110, libressl261))] + pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_min_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } + } + + /// Sets the maximum supported protocol version. + /// + /// A value of `None` will enable protocol versions up to the highest version supported by + /// OpenSSL. + /// + /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. + #[corresponds(SSL_set_max_proto_version)] + #[cfg(any(ossl110, libressl261))] + pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_max_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } + } + + /// Sets the list of supported ciphers for the TLSv1.3 protocol. + /// + /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3. + /// + /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of + /// preference. + /// + /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. + #[corresponds(SSL_set_ciphersuites)] + #[cfg(any(ossl111, libressl340))] + pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_set_ciphersuites( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + + /// Sets the list of supported ciphers for protocols before TLSv1.3. + /// + /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3. + /// + /// See [`ciphers`] for details on the format. + /// + /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html + #[corresponds(SSL_set_cipher_list)] + pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_set_cipher_list( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + + /// Set the certificate store used for certificate verification + #[corresponds(SSL_set_cert_store)] + #[cfg(ossl102)] + pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?; + mem::forget(cert_store); + Ok(()) + } + } + + /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_set_num_tickets)] + #[cfg(ossl111)] + pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) } + } + + /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full + /// handshake. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_get_num_tickets)] + #[cfg(ossl111)] + pub fn num_tickets(&self) -> usize { + unsafe { ffi::SSL_get_num_tickets(self.as_ptr()) } + } } /// An SSL stream midway through the handshake process. @@ -3279,7 +3565,7 @@ impl SslStream { ) }; if ret > 0 { - Ok(written as usize) + Ok(written) } else { Err(self.make_error(ret)) } diff --git a/openssl/src/ssl/test/mod.rs b/openssl/src/ssl/test/mod.rs index ab8d79aab4..7707af238f 100644 --- a/openssl/src/ssl/test/mod.rs +++ b/openssl/src/ssl/test/mod.rs @@ -21,10 +21,10 @@ use crate::hash::MessageDigest; use crate::ocsp::{OcspResponse, OcspResponseStatus}; use crate::pkey::PKey; use crate::srtp::SrtpProfileId; -use crate::ssl; use crate::ssl::test::server::Server; #[cfg(any(ossl110, ossl111, libressl261))] use crate::ssl::SslVersion; +use crate::ssl::{self, NameType, SslConnectorBuilder}; #[cfg(ossl111)] use crate::ssl::{ClientHelloResponse, ExtensionContext}; use crate::ssl::{ @@ -84,17 +84,21 @@ fn verify_trusted_with_set_cert() { #[test] fn verify_untrusted_callback_override_ok() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + let server = Server::builder().build(); let mut client = server.client(); client .ctx() .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); assert!(x509.current_cert().is_some()); true }); client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] @@ -113,6 +117,8 @@ fn verify_untrusted_callback_override_bad() { #[test] fn verify_trusted_callback_override_ok() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + let server = Server::builder().build(); let mut client = server.client(); @@ -120,11 +126,13 @@ fn verify_trusted_callback_override_ok() { client .ctx() .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); assert!(x509.current_cert().is_some()); true }); client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] @@ -144,21 +152,27 @@ fn verify_trusted_callback_override_bad() { #[test] fn verify_callback_load_certs() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + let server = Server::builder().build(); let mut client = server.client(); client .ctx() .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); assert!(x509.current_cert().is_some()); true }); client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] fn verify_trusted_get_error_ok() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + let server = Server::builder().build(); let mut client = server.client(); @@ -166,11 +180,13 @@ fn verify_trusted_get_error_ok() { client .ctx() .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); assert_eq!(x509.error(), X509VerifyResult::OK); true }); client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] @@ -451,7 +467,7 @@ fn test_alpn_server_advertise_multiple() { } #[test] -#[cfg(any(ossl110))] +#[cfg(ossl110)] fn test_alpn_server_select_none_fatal() { let mut server = Server::builder(); server.ctx().set_alpn_select_callback(|_, client| { @@ -469,8 +485,11 @@ fn test_alpn_server_select_none_fatal() { #[test] #[cfg(any(ossl102, libressl261))] fn test_alpn_server_select_none() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + let mut server = Server::builder(); server.ctx().set_alpn_select_callback(|_, client| { + CALLED_BACK.store(true, Ordering::SeqCst); ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) }); let server = server.build(); @@ -479,6 +498,7 @@ fn test_alpn_server_select_none() { client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); let s = client.connect(); assert_eq!(None, s.ssl().selected_alpn_protocol()); + assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] @@ -595,7 +615,7 @@ fn refcount_ssl_context() { { let new_ctx_a = SslContext::builder(SslMethod::tls()).unwrap().build(); - let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); + ssl.set_ssl_context(&new_ctx_a).unwrap(); } } @@ -731,7 +751,7 @@ fn connector_no_hostname_still_verifies() { } #[test] -fn connector_no_hostname_can_disable_verify() { +fn connector_can_disable_verify() { let server = Server::builder().build(); let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); @@ -742,10 +762,64 @@ fn connector_no_hostname_can_disable_verify() { let mut s = connector .configure() .unwrap() - .verify_hostname(false) + .connect("fizzbuzz.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_does_use_sni_with_dnsnames() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut builder = Server::builder(); + builder.ctx().set_servername_callback(|ssl, _| { + assert_eq!(ssl.servername(NameType::HOST_NAME), Some("foobar.com")); + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(()) + }); + let server = builder.build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector + .build() + .configure() + .unwrap() .connect("foobar.com", s) .unwrap(); s.read_exact(&mut [0]).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn connector_doesnt_use_sni_with_ips() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut builder = Server::builder(); + builder.ctx().set_servername_callback(|ssl, _| { + assert_eq!(ssl.servername(NameType::HOST_NAME), None); + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(()) + }); + let server = builder.build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + // The server's cert isn't issued for 127.0.0.1 but we don't care for this test. + connector.set_verify(SslVerifyMode::NONE); + + let s = server.connect_tcp(); + let mut s = connector + .build() + .configure() + .unwrap() + .connect("127.0.0.1", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); } fn test_mozilla_server(new: fn(SslMethod) -> Result) { @@ -1384,6 +1458,9 @@ fn client_hello() { assert!(ssl.client_hello_session_id().is_some()); assert!(ssl.client_hello_ciphers().is_some()); assert!(ssl.client_hello_compression_methods().is_some()); + assert!(ssl + .bytes_to_cipher_list(ssl.client_hello_ciphers().unwrap(), ssl.client_hello_isv2()) + .is_ok()); CALLED_BACK.store(true, Ordering::SeqCst); Ok(ClientHelloResponse::SUCCESS) @@ -1413,3 +1490,81 @@ fn session_cache_size() { let ctx = ctx.build(); assert_eq!(ctx.session_cache_size(), 1234); } + +#[test] +#[cfg(ossl102)] +fn add_chain_cert() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let cert = X509::from_pem(CERT).unwrap(); + let mut ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.add_chain_cert(cert).is_ok()); +} +#[test] +#[cfg(ossl111)] +fn set_ssl_certificate_key_related_api() { + let cert_str: &str = include_str!("../../../test/cert.pem"); + let key_str: &str = include_str!("../../../test/key.pem"); + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let cert_x509 = X509::from_pem(CERT).unwrap(); + let mut ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.set_method(SslMethod::tls()).is_ok()); + ssl.set_private_key_file("test/key.pem", SslFiletype::PEM) + .unwrap(); + { + let pkey = String::from_utf8( + ssl.private_key() + .unwrap() + .private_key_to_pem_pkcs8() + .unwrap(), + ) + .unwrap(); + assert!(pkey.lines().eq(key_str.lines())); + } + let pkey = PKey::private_key_from_pem(KEY).unwrap(); + ssl.set_private_key(pkey.as_ref()).unwrap(); + { + let pkey = String::from_utf8( + ssl.private_key() + .unwrap() + .private_key_to_pem_pkcs8() + .unwrap(), + ) + .unwrap(); + assert!(pkey.lines().eq(key_str.lines())); + } + ssl.set_certificate(cert_x509.as_ref()).unwrap(); + let cert = String::from_utf8(ssl.certificate().unwrap().to_pem().unwrap()).unwrap(); + assert!(cert.lines().eq(cert_str.lines())); + ssl.add_client_ca(cert_x509.as_ref()).unwrap(); + ssl.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap(); + ssl.set_max_proto_version(Some(SslVersion::TLS1_3)).unwrap(); + ssl.set_cipher_list("HIGH:!aNULL:!MD5").unwrap(); + ssl.set_ciphersuites("TLS_AES_128_GCM_SHA256").unwrap(); + let x509 = X509::from_pem(ROOT_CERT).unwrap(); + let mut builder = X509StoreBuilder::new().unwrap(); + builder.add_cert(x509).unwrap(); + let store = builder.build(); + ssl.set_verify_cert_store(store).unwrap(); +} + +#[test] +#[cfg(ossl110)] +fn test_ssl_set_cert_chain_file() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_certificate_chain_file("test/cert.pem").unwrap(); +} + +#[test] +#[cfg(ossl111)] +fn set_num_tickets() { + let mut ctx = SslContext::builder(SslMethod::tls_server()).unwrap(); + ctx.set_num_tickets(3).unwrap(); + let ctx = ctx.build(); + assert_eq!(3, ctx.num_tickets()); + + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_num_tickets(5).unwrap(); + let ssl = ssl; + assert_eq!(5, ssl.num_tickets()); +} diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index c75bbc0c4a..c1dbdfee7b 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -68,7 +68,7 @@ pub enum Mode { /// /// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms. /// -/// [`EVP_EncryptInit`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_EncryptInit.html +/// [`EVP_EncryptInit`]: https://www.openssl.org/docs/manmaster/crypto/EVP_EncryptInit.html #[derive(Copy, Clone, PartialEq, Eq)] pub struct Cipher(*const ffi::EVP_CIPHER); @@ -77,7 +77,7 @@ impl Cipher { /// /// This corresponds to [`EVP_get_cipherbynid`] /// - /// [`EVP_get_cipherbynid`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_get_cipherbyname.html + /// [`EVP_get_cipherbynid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_get_cipherbyname.html pub fn from_nid(nid: Nid) -> Option { let ptr = unsafe { ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())) }; if ptr.is_null() { @@ -91,7 +91,7 @@ impl Cipher { /// /// This corresponds to [`EVP_CIPHER_nid`] /// - /// [`EVP_CIPHER_nid`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_CIPHER_nid.html + /// [`EVP_CIPHER_nid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_CIPHER_nid.html pub fn nid(&self) -> Nid { let nid = unsafe { ffi::EVP_CIPHER_nid(self.0) }; Nid::from_raw(nid) @@ -142,7 +142,7 @@ impl Cipher { } /// Requires OpenSSL 1.1.0 or newer. - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_128_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ocb()) } } @@ -187,7 +187,7 @@ impl Cipher { } /// Requires OpenSSL 1.1.0 or newer. - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_192_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_ocb()) } } @@ -237,7 +237,7 @@ impl Cipher { } /// Requires OpenSSL 1.1.0 or newer. - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_256_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ocb()) } } @@ -283,6 +283,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) } } + #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn rc4() -> Cipher { unsafe { Cipher(ffi::EVP_rc4()) } } @@ -401,14 +402,14 @@ impl Cipher { } /// Determines whether the cipher is using OCB mode - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] fn is_ocb(self) -> bool { self == Cipher::aes_128_ocb() || self == Cipher::aes_192_ocb() || self == Cipher::aes_256_ocb() } - #[cfg(not(ossl110))] + #[cfg(any(not(ossl110), osslconf = "OPENSSL_NO_OCB"))] const fn is_ocb(self) -> bool { false } @@ -1421,7 +1422,7 @@ mod tests { } #[test] - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] fn test_aes_128_ocb() { let key = "000102030405060708090a0b0c0d0e0f"; let aad = "0001020304050607"; @@ -1457,7 +1458,7 @@ mod tests { } #[test] - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] fn test_aes_128_ocb_fail() { let key = "000102030405060708090a0b0c0d0e0f"; let aad = "0001020304050607"; @@ -1477,7 +1478,7 @@ mod tests { } #[test] - #[cfg(any(ossl110))] + #[cfg(ossl110)] fn test_chacha20() { let key = "0000000000000000000000000000000000000000000000000000000000000000"; let iv = "00000000000000000000000000000000"; @@ -1492,7 +1493,7 @@ mod tests { } #[test] - #[cfg(any(ossl110))] + #[cfg(ossl110)] fn test_chacha20_poly1305() { let key = "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"; let iv = "070000004041424344454647"; diff --git a/openssl/src/x509/extension.rs b/openssl/src/x509/extension.rs index ebbea1c885..11e0151530 100644 --- a/openssl/src/x509/extension.rs +++ b/openssl/src/x509/extension.rs @@ -18,9 +18,11 @@ //! ``` use std::fmt::Write; +use crate::asn1::Asn1Object; use crate::error::ErrorStack; use crate::nid::Nid; -use crate::x509::{X509Extension, X509v3Context}; +use crate::x509::{GeneralName, Stack, X509Extension, X509v3Context}; +use foreign_types::ForeignType; /// An extension which indicates whether a certificate is a CA certificate. pub struct BasicConstraints { @@ -65,6 +67,9 @@ impl BasicConstraints { } /// Return the `BasicConstraints` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self) -> Result { let mut value = String::new(); if self.critical { @@ -181,6 +186,9 @@ impl KeyUsage { } /// Return the `KeyUsage` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self) -> Result { let mut value = String::new(); let mut first = true; @@ -222,18 +230,7 @@ impl KeyUsage { /// for which the certificate public key can be used for. pub struct ExtendedKeyUsage { critical: bool, - server_auth: bool, - client_auth: bool, - code_signing: bool, - email_protection: bool, - time_stamping: bool, - ms_code_ind: bool, - ms_code_com: bool, - ms_ctl_sign: bool, - ms_sgc: bool, - ms_efs: bool, - ns_sgc: bool, - other: Vec, + items: Vec, } impl Default for ExtendedKeyUsage { @@ -247,18 +244,7 @@ impl ExtendedKeyUsage { pub fn new() -> ExtendedKeyUsage { ExtendedKeyUsage { critical: false, - server_auth: false, - client_auth: false, - code_signing: false, - email_protection: false, - time_stamping: false, - ms_code_ind: false, - ms_code_com: false, - ms_ctl_sign: false, - ms_sgc: false, - ms_efs: false, - ns_sgc: false, - other: vec![], + items: vec![], } } @@ -270,101 +256,74 @@ impl ExtendedKeyUsage { /// Sets the `serverAuth` flag to `true`. pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage { - self.server_auth = true; - self + self.other("serverAuth") } /// Sets the `clientAuth` flag to `true`. pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage { - self.client_auth = true; - self + self.other("clientAuth") } /// Sets the `codeSigning` flag to `true`. pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage { - self.code_signing = true; - self + self.other("codeSigning") } /// Sets the `emailProtection` flag to `true`. pub fn email_protection(&mut self) -> &mut ExtendedKeyUsage { - self.email_protection = true; - self + self.other("emailProtection") } /// Sets the `timeStamping` flag to `true`. pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage { - self.time_stamping = true; - self + self.other("timeStamping") } /// Sets the `msCodeInd` flag to `true`. pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage { - self.ms_code_ind = true; - self + self.other("msCodeInd") } /// Sets the `msCodeCom` flag to `true`. pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage { - self.ms_code_com = true; - self + self.other("msCodeCom") } /// Sets the `msCTLSign` flag to `true`. pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage { - self.ms_ctl_sign = true; - self + self.other("msCTLSign") } /// Sets the `msSGC` flag to `true`. pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage { - self.ms_sgc = true; - self + self.other("msSGC") } /// Sets the `msEFS` flag to `true`. pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage { - self.ms_efs = true; - self + self.other("msEFS") } /// Sets the `nsSGC` flag to `true`. pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage { - self.ns_sgc = true; - self + self.other("nsSGC") } /// Sets a flag not already defined. pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage { - self.other.push(other.to_owned()); + self.items.push(other.to_string()); self } /// Return the `ExtendedKeyUsage` extension as an `X509Extension`. pub fn build(&self) -> Result { - let mut value = String::new(); - let mut first = true; - append(&mut value, &mut first, self.critical, "critical"); - append(&mut value, &mut first, self.server_auth, "serverAuth"); - append(&mut value, &mut first, self.client_auth, "clientAuth"); - append(&mut value, &mut first, self.code_signing, "codeSigning"); - append( - &mut value, - &mut first, - self.email_protection, - "emailProtection", - ); - append(&mut value, &mut first, self.time_stamping, "timeStamping"); - append(&mut value, &mut first, self.ms_code_ind, "msCodeInd"); - append(&mut value, &mut first, self.ms_code_com, "msCodeCom"); - append(&mut value, &mut first, self.ms_ctl_sign, "msCTLSign"); - append(&mut value, &mut first, self.ms_sgc, "msSGC"); - append(&mut value, &mut first, self.ms_efs, "msEFS"); - append(&mut value, &mut first, self.ns_sgc, "nsSGC"); - for other in &self.other { - append(&mut value, &mut first, true, other); + let mut stack = Stack::new()?; + for item in &self.items { + stack.push(Asn1Object::from_str(item)?)?; + } + unsafe { + X509Extension::new_internal(Nid::EXT_KEY_USAGE, self.critical, stack.as_ptr().cast()) } - X509Extension::new_nid(None, None, Nid::EXT_KEY_USAGE, &value) } } @@ -393,6 +352,9 @@ impl SubjectKeyIdentifier { } /// Return a `SubjectKeyIdentifier` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { let mut value = String::new(); let mut first = true; @@ -445,6 +407,9 @@ impl AuthorityKeyIdentifier { } /// Return a `AuthorityKeyIdentifier` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { let mut value = String::new(); let mut first = true; @@ -463,11 +428,20 @@ impl AuthorityKeyIdentifier { } } +enum RustGeneralName { + Dns(String), + Email(String), + Uri(String), + Ip(String), + Rid(String), + OtherName(Asn1Object, Vec), +} + /// An extension that allows additional identities to be bound to the subject /// of the certificate. pub struct SubjectAlternativeName { critical: bool, - names: Vec, + items: Vec, } impl Default for SubjectAlternativeName { @@ -481,7 +455,7 @@ impl SubjectAlternativeName { pub fn new() -> SubjectAlternativeName { SubjectAlternativeName { critical: false, - names: vec![], + items: vec![], } } @@ -493,55 +467,85 @@ impl SubjectAlternativeName { /// Sets the `email` flag. pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName { - self.names.push(format!("email:{}", email)); + self.items.push(RustGeneralName::Email(email.to_string())); self } /// Sets the `uri` flag. pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName { - self.names.push(format!("URI:{}", uri)); + self.items.push(RustGeneralName::Uri(uri.to_string())); self } /// Sets the `dns` flag. pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName { - self.names.push(format!("DNS:{}", dns)); + self.items.push(RustGeneralName::Dns(dns.to_string())); self } /// Sets the `rid` flag. pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName { - self.names.push(format!("RID:{}", rid)); + self.items.push(RustGeneralName::Rid(rid.to_string())); self } /// Sets the `ip` flag. pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName { - self.names.push(format!("IP:{}", ip)); + self.items.push(RustGeneralName::Ip(ip.to_string())); self } /// Sets the `dirName` flag. - pub fn dir_name(&mut self, dir_name: &str) -> &mut SubjectAlternativeName { - self.names.push(format!("dirName:{}", dir_name)); - self + /// + /// Not currently actually supported, always panics. + #[deprecated = "dir_name is deprecated and always panics. Please file a bug if you have a use case for this."] + pub fn dir_name(&mut self, _dir_name: &str) -> &mut SubjectAlternativeName { + unimplemented!( + "This has not yet been adapted for the new internals. File a bug if you need this." + ); + } + + /// Sets the `otherName` flag. + /// + /// Not currently actually supported, always panics. Please use other_name2 + #[deprecated = "other_name is deprecated and always panics. Please use other_name2."] + pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName { + unimplemented!("This has not yet been adapted for the new internals. Use other_name2."); } /// Sets the `otherName` flag. - pub fn other_name(&mut self, other_name: &str) -> &mut SubjectAlternativeName { - self.names.push(format!("otherName:{}", other_name)); + /// + /// `content` must be a valid der encoded ASN1_TYPE + /// + /// If you want to add just a ia5string use `other_name_ia5string` + pub fn other_name2(&mut self, oid: Asn1Object, content: &[u8]) -> &mut SubjectAlternativeName { + self.items + .push(RustGeneralName::OtherName(oid, content.into())); self } /// Return a `SubjectAlternativeName` extension as an `X509Extension`. - pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { - let mut value = String::new(); - let mut first = true; - append(&mut value, &mut first, self.critical, "critical"); - for name in &self.names { - append(&mut value, &mut first, true, name); + pub fn build(&self, _ctx: &X509v3Context<'_>) -> Result { + let mut stack = Stack::new()?; + for item in &self.items { + let gn = match item { + RustGeneralName::Dns(s) => GeneralName::new_dns(s.as_bytes())?, + RustGeneralName::Email(s) => GeneralName::new_email(s.as_bytes())?, + RustGeneralName::Uri(s) => GeneralName::new_uri(s.as_bytes())?, + RustGeneralName::Ip(s) => { + GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)? + } + RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?, + RustGeneralName::OtherName(oid, content) => { + GeneralName::new_other_name(oid.clone(), content)? + } + }; + stack.push(gn)?; + } + + unsafe { + X509Extension::new_internal(Nid::SUBJECT_ALT_NAME, self.critical, stack.as_ptr().cast()) } - X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_ALT_NAME, &value) } } diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index edd54aa840..4325b132e3 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -8,21 +8,24 @@ //! the secure protocol for browsing the web. use cfg_if::cfg_if; -use foreign_types::{ForeignType, ForeignTypeRef}; -use libc::{c_int, c_long, c_uint}; +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; +use libc::{c_int, c_long, c_uint, c_void}; use std::cmp::{self, Ordering}; +use std::convert::{TryFrom, TryInto}; use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt; use std::marker::PhantomData; use std::mem; +use std::net::IpAddr; use std::path::Path; use std::ptr; use std::slice; use std::str; use crate::asn1::{ - Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, Asn1Type, + Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, + Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type, }; use crate::bio::MemBioSlice; use crate::conf::ConfRef; @@ -47,6 +50,16 @@ pub mod store; #[cfg(test)] mod tests; +/// A type of X509 extension. +/// +/// # Safety +/// The value of NID and Output must match those in OpenSSL so that +/// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid. +pub unsafe trait ExtensionType { + const NID: Nid; + type Output: ForeignType; +} + foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE_CTX; fn drop = ffi::X509_STORE_CTX_free; @@ -109,8 +122,8 @@ impl X509StoreContextRef { /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. /// - /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html - /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html + /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_init.html + /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_cleanup.html pub fn init( &mut self, trust: &store::X509StoreRef, @@ -227,6 +240,7 @@ impl X509Builder { /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of /// the X.509 standard should pass `2` to this method. #[corresponds(X509_set_version)] + #[allow(clippy::useless_conversion)] pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) } } @@ -387,7 +401,10 @@ impl X509Ref { /// Returns the hash of the certificates subject #[corresponds(X509_subject_name_hash)] pub fn subject_name_hash(&self) -> u32 { - unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } + #[allow(clippy::unnecessary_cast)] + unsafe { + ffi::X509_subject_name_hash(self.as_ptr()) as u32 + } } /// Returns this certificate's issuer name. @@ -402,7 +419,10 @@ impl X509Ref { /// Returns the hash of the certificates issuer #[corresponds(X509_issuer_name_hash)] pub fn issuer_name_hash(&self) -> u32 { - unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 } + #[allow(clippy::unnecessary_cast)] + unsafe { + ffi::X509_issuer_name_hash(self.as_ptr()) as u32 + } } /// Returns this certificate's subject alternative name entries, if they exist. @@ -419,6 +439,20 @@ impl X509Ref { } } + /// Returns this certificate's CRL distribution points, if they exist. + #[corresponds(X509_get_ext_d2i)] + pub fn crl_distribution_points(&self) -> Option> { + unsafe { + let stack = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_crl_distribution_points, + ptr::null_mut(), + ptr::null_mut(), + ); + Stack::from_ptr_opt(stack as *mut _) + } + } + /// Returns this certificate's issuer alternative name entries, if they exist. #[corresponds(X509_get_ext_d2i)] pub fn issuer_alt_names(&self) -> Option> { @@ -449,6 +483,54 @@ impl X509Ref { } } + /// Retrieves the path length extension from a certificate, if it exists. + #[corresponds(X509_get_pathlen)] + #[cfg(ossl110)] + pub fn pathlen(&self) -> Option { + let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) }; + u32::try_from(v).ok() + } + + /// Returns this certificate's subject key id, if it exists. + #[corresponds(X509_get0_subject_key_id)] + #[cfg(ossl110)] + pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> { + unsafe { + let data = ffi::X509_get0_subject_key_id(self.as_ptr()); + Asn1OctetStringRef::from_const_ptr_opt(data) + } + } + + /// Returns this certificate's authority key id, if it exists. + #[corresponds(X509_get0_authority_key_id)] + #[cfg(ossl110)] + pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> { + unsafe { + let data = ffi::X509_get0_authority_key_id(self.as_ptr()); + Asn1OctetStringRef::from_const_ptr_opt(data) + } + } + + /// Returns this certificate's authority issuer name entries, if they exist. + #[corresponds(X509_get0_authority_issuer)] + #[cfg(ossl111d)] + pub fn authority_issuer(&self) -> Option<&StackRef> { + unsafe { + let stack = ffi::X509_get0_authority_issuer(self.as_ptr()); + StackRef::from_const_ptr_opt(stack) + } + } + + /// Returns this certificate's authority serial number, if it exists. + #[corresponds(X509_get0_authority_serial)] + #[cfg(ossl111d)] + pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> { + unsafe { + let r = ffi::X509_get0_authority_serial(self.as_ptr()); + Asn1IntegerRef::from_const_ptr_opt(r) + } + } + #[corresponds(X509_get_pubkey)] pub fn public_key(&self) -> Result, ErrorStack> { unsafe { @@ -544,6 +626,7 @@ impl X509Ref { /// Note that `0` return value stands for version 1, `1` for version 2 and so on. #[corresponds(X509_get_version)] #[cfg(ossl110)] + #[allow(clippy::unnecessary_cast)] pub fn version(&self) -> i32 { unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } } @@ -803,7 +886,17 @@ impl X509Extension { /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be /// provided. /// + /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL + /// mini-language that can read arbitrary files. + /// /// See the extension module for builder types which will construct certain common extensions. + /// + /// This function is deprecated, `X509Extension::new_from_der` or the + /// types in `x509::extension` should be used in its place. + #[deprecated( + note = "Use x509::extension types or new_from_der instead", + since = "0.10.51" + )] pub fn new( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, @@ -812,14 +905,30 @@ impl X509Extension { ) -> Result { let name = CString::new(name).unwrap(); let value = CString::new(value).unwrap(); + let mut ctx; unsafe { ffi::init(); let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); - let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); + let context_ptr = match context { + Some(c) => c.as_ptr(), + None => { + ctx = mem::zeroed(); + + ffi::X509V3_set_ctx( + &mut ctx, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + &mut ctx + } + }; let name = name.as_ptr() as *mut _; let value = value.as_ptr() as *mut _; - cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension) + cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension) } } @@ -829,7 +938,17 @@ impl X509Extension { /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to /// be provided. /// + /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL + /// mini-language that can read arbitrary files. + /// /// See the extension module for builder types which will construct certain common extensions. + /// + /// This function is deprecated, `X509Extension::new_from_der` or the + /// types in `x509::extension` should be used in its place. + #[deprecated( + note = "Use x509::extension types or new_from_der instead", + since = "0.10.51" + )] pub fn new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, @@ -837,29 +956,92 @@ impl X509Extension { value: &str, ) -> Result { let value = CString::new(value).unwrap(); + let mut ctx; unsafe { ffi::init(); let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); - let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); + let context_ptr = match context { + Some(c) => c.as_ptr(), + None => { + ctx = mem::zeroed(); + + ffi::X509V3_set_ctx( + &mut ctx, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + &mut ctx + } + }; let name = name.as_raw(); let value = value.as_ptr() as *mut _; - cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension) + cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension) + } + } + + /// Constructs a new X509 extension value from its OID, whether it's + /// critical, and its DER contents. + /// + /// The extent structure of the DER value will vary based on the + /// extension type, and can generally be found in the RFC defining the + /// extension. + /// + /// For common extension types, there are Rust APIs provided in + /// `openssl::x509::extensions` which are more ergonomic. + pub fn new_from_der( + oid: &Asn1ObjectRef, + critical: bool, + der_contents: &Asn1OctetStringRef, + ) -> Result { + unsafe { + cvt_p(ffi::X509_EXTENSION_create_by_OBJ( + ptr::null_mut(), + oid.as_ptr(), + critical as _, + der_contents.as_ptr(), + )) + .map(X509Extension) } } + pub(crate) unsafe fn new_internal( + nid: Nid, + critical: bool, + value: *mut c_void, + ) -> Result { + ffi::init(); + cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension) + } + /// Adds an alias for an extension /// /// # Safety /// /// This method modifies global state without locking and therefore is not thread safe #[corresponds(X509V3_EXT_add_alias)] + #[deprecated( + note = "Use x509::extension types or new_from_der and then this is not necessary", + since = "0.10.51" + )] pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> { ffi::init(); cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ()) } } +impl X509ExtensionRef { + to_der! { + /// Serializes the Extension to its standard DER encoding. + #[corresponds(i2d_X509_EXTENSION)] + to_der, + ffi::i2d_X509_EXTENSION + } +} + /// A builder used to construct an `X509Name`. pub struct X509NameBuilder(X509Name); @@ -872,21 +1054,36 @@ impl X509NameBuilder { } } + /// Add a name entry + #[corresponds(X509_NAME_add_entry)] + #[cfg(any(ossl101, libressl350))] + pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_NAME_add_entry( + self.0.as_ptr(), + ne.as_ptr(), + -1, + 0, + )) + .map(|_| ()) + } + } + /// Add a field entry by str. /// /// This corresponds to [`X509_NAME_add_entry_by_txt`]. /// - /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html + /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_txt( self.0.as_ptr(), field.as_ptr() as *mut _, ffi::MBSTRING_UTF8, value.as_ptr(), - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -898,7 +1095,7 @@ impl X509NameBuilder { /// /// This corresponds to [`X509_NAME_add_entry_by_txt`]. /// - /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html + /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html pub fn append_entry_by_text_with_type( &mut self, field: &str, @@ -907,13 +1104,13 @@ impl X509NameBuilder { ) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_txt( self.0.as_ptr(), field.as_ptr() as *mut _, ty.as_raw(), value.as_ptr(), - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -925,16 +1122,16 @@ impl X509NameBuilder { /// /// This corresponds to [`X509_NAME_add_entry_by_NID`]. /// - /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html + /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { unsafe { - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_NID( self.0.as_ptr(), field.as_raw(), ffi::MBSTRING_UTF8, value.as_ptr() as *mut _, - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -946,7 +1143,7 @@ impl X509NameBuilder { /// /// This corresponds to [`X509_NAME_add_entry_by_NID`]. /// - /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html + /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html pub fn append_entry_by_nid_with_type( &mut self, field: Nid, @@ -954,13 +1151,13 @@ impl X509NameBuilder { ty: Asn1Type, ) -> Result<(), ErrorStack> { unsafe { - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_NID( self.0.as_ptr(), field.as_raw(), ty.as_raw(), value.as_ptr() as *mut _, - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -970,7 +1167,10 @@ impl X509NameBuilder { /// Return an `X509Name`. pub fn build(self) -> X509Name { - self.0 + // Round-trip through bytes because OpenSSL is not const correct and + // names in a "modified" state compute various things lazily. This can + // lead to data-races because OpenSSL doesn't have locks or anything. + X509Name::from_der(&self.0.to_der().unwrap()).unwrap() } } @@ -1048,12 +1248,19 @@ impl X509NameRef { Ok(cmp.cmp(&0)) } + /// Copies the name to a new `X509Name`. + #[corresponds(X509_NAME_dup)] + #[cfg(any(boringssl, ossl110, libressl270))] + pub fn to_owned(&self) -> Result { + unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) } + } + to_der! { /// Serializes the certificate into a DER-encoded X509 name structure. /// /// This corresponds to [`i2d_X509_NAME`]. /// - /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509_NAME.html + /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html to_der, ffi::i2d_X509_NAME } @@ -1117,7 +1324,7 @@ impl X509NameEntryRef { /// /// This corresponds to [`X509_NAME_ENTRY_get_data`]. /// - /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html + /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_data.html pub fn data(&self) -> &Asn1StringRef { unsafe { let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); @@ -1130,7 +1337,7 @@ impl X509NameEntryRef { /// /// This corresponds to [`X509_NAME_ENTRY_get_object`]. /// - /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html + /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_object.html pub fn object(&self) -> &Asn1ObjectRef { unsafe { let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); @@ -1153,7 +1360,7 @@ impl X509ReqBuilder { /// /// This corresponds to [`X509_REQ_new`]. /// - ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html + ///[`X509_REQ_new`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_new.html pub fn new() -> Result { unsafe { ffi::init(); @@ -1165,7 +1372,8 @@ impl X509ReqBuilder { /// /// This corresponds to [`X509_REQ_set_version`]. /// - ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html + ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_version.html + #[allow(clippy::useless_conversion)] pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_version( @@ -1180,7 +1388,7 @@ impl X509ReqBuilder { /// /// This corresponds to [`X509_REQ_set_subject_name`]. /// - /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html + /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_subject_name.html pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_subject_name( @@ -1195,7 +1403,7 @@ impl X509ReqBuilder { /// /// This corresponds to [`X509_REQ_set_pubkey`]. /// - /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html + /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_pubkey.html pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, @@ -1245,7 +1453,7 @@ impl X509ReqBuilder { /// /// This corresponds to [`X509_REQ_sign`]. /// - /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html + /// [`X509_REQ_sign`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_sign.html pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate, @@ -1289,7 +1497,7 @@ impl X509Req { /// /// This corresponds to [`PEM_read_bio_X509_REQ`]. /// - /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html + /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_read_bio_X509_REQ.html from_pem, X509Req, ffi::PEM_read_bio_X509_REQ @@ -1300,7 +1508,7 @@ impl X509Req { /// /// This corresponds to [`d2i_X509_REQ`]. /// - /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html + /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/d2i_X509_REQ.html from_der, X509Req, ffi::d2i_X509_REQ @@ -1315,7 +1523,7 @@ impl X509ReqRef { /// /// This corresponds to [`PEM_write_bio_X509_REQ`]. /// - /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html + /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_write_bio_X509_REQ.html to_pem, ffi::PEM_write_bio_X509_REQ } @@ -1325,7 +1533,7 @@ impl X509ReqRef { /// /// This corresponds to [`i2d_X509_REQ`]. /// - /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html + /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_REQ.html to_der, ffi::i2d_X509_REQ } @@ -1341,7 +1549,8 @@ impl X509ReqRef { /// /// This corresponds to [`X509_REQ_get_version`] /// - /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html + /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html + #[allow(clippy::unnecessary_cast)] pub fn version(&self) -> i32 { unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } @@ -1350,7 +1559,7 @@ impl X509ReqRef { /// /// This corresponds to [`X509_REQ_get_subject_name`] /// - /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html + /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_subject_name.html pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = X509_REQ_get_subject_name(self.as_ptr()); @@ -1362,7 +1571,7 @@ impl X509ReqRef { /// /// This corresponds to [`X509_REQ_get_pubkey"] /// - /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html + /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_pubkey.html pub fn public_key(&self) -> Result, ErrorStack> { unsafe { let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; @@ -1376,7 +1585,7 @@ impl X509ReqRef { /// /// This corresponds to [`X509_REQ_verify"]. /// - /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html + /// [`X509_REQ_verify`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_verify.html pub fn verify(&self, key: &PKeyRef) -> Result where T: HasPublic, @@ -1395,6 +1604,319 @@ impl X509ReqRef { } } +/// The reason that a certificate was revoked. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct CrlReason(c_int); + +#[allow(missing_docs)] // no need to document the constants +impl CrlReason { + pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED); + pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE); + pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE); + pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED); + pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED); + pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION); + pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD); + pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL); + pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN); + pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE); + + /// Constructs an `CrlReason` from a raw OpenSSL value. + pub const fn from_raw(value: c_int) -> Self { + CrlReason(value) + } + + /// Returns the raw OpenSSL value represented by this type. + pub const fn as_raw(&self) -> c_int { + self.0 + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_REVOKED; + fn drop = ffi::X509_REVOKED_free; + + /// An `X509` certificate revocation status. + pub struct X509Revoked; + /// Reference to `X509Revoked`. + pub struct X509RevokedRef; +} + +impl Stackable for X509Revoked { + type StackType = ffi::stack_st_X509_REVOKED; +} + +impl X509Revoked { + from_der! { + /// Deserializes a DER-encoded certificate revocation status + #[corresponds(d2i_X509_REVOKED)] + from_der, + X509Revoked, + ffi::d2i_X509_REVOKED + } +} + +impl X509RevokedRef { + to_der! { + /// Serializes the certificate request to a DER-encoded certificate revocation status + #[corresponds(d2i_X509_REVOKED)] + to_der, + ffi::i2d_X509_REVOKED + } + + /// Copies the entry to a new `X509Revoked`. + #[corresponds(X509_NAME_dup)] + #[cfg(any(boringssl, ossl110, libressl270))] + pub fn to_owned(&self) -> Result { + unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) } + } + + /// Get the date that the certificate was revoked + #[corresponds(X509_REVOKED_get0_revocationDate)] + pub fn revocation_date(&self) -> &Asn1TimeRef { + unsafe { + let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _); + assert!(!r.is_null()); + Asn1TimeRef::from_ptr(r as *mut _) + } + } + + /// Get the serial number of the revoked certificate + #[corresponds(X509_REVOKED_get0_serialNumber)] + pub fn serial_number(&self) -> &Asn1IntegerRef { + unsafe { + let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _); + assert!(!r.is_null()); + Asn1IntegerRef::from_ptr(r as *mut _) + } + } + + /// Get the criticality and value of an extension. + /// + /// This returns None if the extension is not present or occurs multiple times. + #[corresponds(X509_REVOKED_get_ext_d2i)] + pub fn extension(&self) -> Result, ErrorStack> { + let mut critical = -1; + let out = unsafe { + // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED. + let ext = ffi::X509_REVOKED_get_ext_d2i( + self.as_ptr(), + T::NID.as_raw(), + &mut critical as *mut _, + ptr::null_mut(), + ); + // SAFETY: Extensions's contract promises that the type returned by + // OpenSSL here is T::Output. + T::Output::from_ptr_opt(ext as *mut _) + }; + match (critical, out) { + (0, Some(out)) => Ok(Some((false, out))), + (1, Some(out)) => Ok(Some((true, out))), + // -1 means the extension wasn't found, -2 means multiple were found. + (-1 | -2, _) => Ok(None), + // A critical value of 0 or 1 suggests success, but a null pointer + // was returned so something went wrong. + (0 | 1, None) => Err(ErrorStack::get()), + (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical), + } + } +} + +/// The CRL entry extension identifying the reason for revocation see [`CrlReason`], +/// this is as defined in RFC 5280 Section 5.3.1. +pub enum ReasonCode {} + +// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC +// and in OpenSSL. +unsafe impl ExtensionType for ReasonCode { + const NID: Nid = Nid::from_raw(ffi::NID_crl_reason); + + type Output = Asn1Enumerated; +} + +/// The CRL entry extension identifying the issuer of a certificate used in +/// indirect CRLs, as defined in RFC 5280 Section 5.3.3. +pub enum CertificateIssuer {} + +// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC +// and in OpenSSL. +unsafe impl ExtensionType for CertificateIssuer { + const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer); + + type Output = Stack; +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_CRL; + fn drop = ffi::X509_CRL_free; + + /// An `X509` certificate revocation list. + pub struct X509Crl; + /// Reference to `X509Crl`. + pub struct X509CrlRef; +} + +/// The status of a certificate in a revoction list +/// +/// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods. +/// +/// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html +pub enum CrlStatus<'a> { + /// The certificate is not present in the list + NotRevoked, + /// The certificate is in the list and is revoked + Revoked(&'a X509RevokedRef), + /// The certificate is in the list, but has the "removeFromCrl" status. + /// + /// This can occur if the certificate was revoked with the "CertificateHold" + /// reason, and has since been unrevoked. + RemoveFromCrl(&'a X509RevokedRef), +} + +impl<'a> CrlStatus<'a> { + // Helper used by the X509_CRL_get0_by_* methods to convert their return + // value to the status enum. + // Safety note: the returned CrlStatus must not outlive the owner of the + // revoked_entry pointer. + unsafe fn from_ffi_status( + status: c_int, + revoked_entry: *mut ffi::X509_REVOKED, + ) -> CrlStatus<'a> { + match status { + 0 => CrlStatus::NotRevoked, + 1 => { + assert!(!revoked_entry.is_null()); + CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry)) + } + 2 => { + assert!(!revoked_entry.is_null()); + CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry)) + } + _ => unreachable!( + "{}", + "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2." + ), + } + } +} + +impl X509Crl { + from_pem! { + /// Deserializes a PEM-encoded Certificate Revocation List + /// + /// The input should have a header of `-----BEGIN X509 CRL-----`. + #[corresponds(PEM_read_bio_X509_CRL)] + from_pem, + X509Crl, + ffi::PEM_read_bio_X509_CRL + } + + from_der! { + /// Deserializes a DER-encoded Certificate Revocation List + #[corresponds(d2i_X509_CRL)] + from_der, + X509Crl, + ffi::d2i_X509_CRL + } +} + +impl X509CrlRef { + to_pem! { + /// Serializes the certificate request to a PEM-encoded Certificate Revocation List. + /// + /// The output will have a header of `-----BEGIN X509 CRL-----`. + #[corresponds(PEM_write_bio_X509_CRL)] + to_pem, + ffi::PEM_write_bio_X509_CRL + } + + to_der! { + /// Serializes the certificate request to a DER-encoded Certificate Revocation List. + #[corresponds(i2d_X509_CRL)] + to_der, + ffi::i2d_X509_CRL + } + + /// Get the stack of revocation entries + pub fn get_revoked(&self) -> Option<&StackRef> { + unsafe { + let revoked = X509_CRL_get_REVOKED(self.as_ptr()); + if revoked.is_null() { + None + } else { + Some(StackRef::from_ptr(revoked)) + } + } + } + + /// Returns the CRL's `lastUpdate` time. + #[corresponds(X509_CRL_get0_lastUpdate)] + pub fn last_update(&self) -> &Asn1TimeRef { + unsafe { + let date = X509_CRL_get0_lastUpdate(self.as_ptr()); + assert!(!date.is_null()); + Asn1TimeRef::from_ptr(date as *mut _) + } + } + + /// Returns the CRL's `nextUpdate` time. + /// + /// If the `nextUpdate` field is missing, returns `None`. + #[corresponds(X509_CRL_get0_nextUpdate)] + pub fn next_update(&self) -> Option<&Asn1TimeRef> { + unsafe { + let date = X509_CRL_get0_nextUpdate(self.as_ptr()); + Asn1TimeRef::from_const_ptr_opt(date) + } + } + + /// Get the revocation status of a certificate by its serial number + #[corresponds(X509_CRL_get0_by_serial)] + pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> { + unsafe { + let mut ret = ptr::null_mut::(); + let status = + ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr()); + CrlStatus::from_ffi_status(status, ret) + } + } + + /// Get the revocation status of a certificate + #[corresponds(X509_CRL_get0_by_cert)] + pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> { + unsafe { + let mut ret = ptr::null_mut::(); + let status = + ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr()); + CrlStatus::from_ffi_status(status, ret) + } + } + + /// Get the issuer name from the revocation list. + #[corresponds(X509_CRL_get_issuer)] + pub fn issuer_name(&self) -> &X509NameRef { + unsafe { + let name = X509_CRL_get_issuer(self.as_ptr()); + assert!(!name.is_null()); + X509NameRef::from_ptr(name) + } + } + + /// Check if the CRL is signed using the given public key. + /// + /// Only the signature is checked: no other checks (such as certificate chain validity) + /// are performed. + /// + /// Returns `true` if verification succeeds. + #[corresponds(X509_CRL_verify)] + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } +} + /// The result of peer certificate verification. #[derive(Copy, Clone, PartialEq, Eq)] pub struct X509VerifyResult(c_int); @@ -1437,7 +1959,7 @@ impl X509VerifyResult { /// /// This corresponds to [`X509_verify_cert_error_string`]. /// - /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html + /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/manmaster/crypto/X509_verify_cert_error_string.html #[allow(clippy::trivially_copy_pass_by_ref)] pub fn error_string(&self) -> &'static str { ffi::init(); @@ -1465,6 +1987,106 @@ foreign_type_and_impl_send_sync! { pub struct GeneralNameRef; } +impl GeneralName { + unsafe fn new( + type_: c_int, + asn1_type: Asn1Type, + value: &[u8], + ) -> Result { + ffi::init(); + let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?); + (*gn.as_ptr()).type_ = type_; + let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?; + ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap()); + + #[cfg(boringssl)] + { + (*gn.as_ptr()).d.ptr = s.cast(); + } + #[cfg(not(boringssl))] + { + (*gn.as_ptr()).d = s.cast(); + } + + Ok(gn) + } + + pub(crate) fn new_email(email: &[u8]) -> Result { + unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) } + } + + pub(crate) fn new_dns(dns: &[u8]) -> Result { + unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) } + } + + pub(crate) fn new_uri(uri: &[u8]) -> Result { + unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) } + } + + pub(crate) fn new_ip(ip: IpAddr) -> Result { + match ip { + IpAddr::V4(addr) => unsafe { + GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets()) + }, + IpAddr::V6(addr) => unsafe { + GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets()) + }, + } + } + + pub(crate) fn new_rid(oid: Asn1Object) -> Result { + unsafe { + ffi::init(); + let gn = cvt_p(ffi::GENERAL_NAME_new())?; + (*gn).type_ = ffi::GEN_RID; + + #[cfg(boringssl)] + { + (*gn).d.registeredID = oid.as_ptr(); + } + #[cfg(not(boringssl))] + { + (*gn).d = oid.as_ptr().cast(); + } + + mem::forget(oid); + + Ok(GeneralName::from_ptr(gn)) + } + } + + pub(crate) fn new_other_name( + oid: Asn1Object, + value: &Vec, + ) -> Result { + unsafe { + ffi::init(); + + let typ = cvt_p(ffi::d2i_ASN1_TYPE( + ptr::null_mut(), + &mut value.as_ptr().cast(), + value.len().try_into().unwrap(), + ))?; + + let gn = cvt_p(ffi::GENERAL_NAME_new())?; + (*gn).type_ = ffi::GEN_OTHERNAME; + + if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername( + gn, + oid.as_ptr().cast(), + typ, + )) { + ffi::GENERAL_NAME_free(gn); + return Err(e); + } + + mem::forget(oid); + + Ok(GeneralName::from_ptr(gn)) + } + } +} + impl GeneralNameRef { fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { unsafe { @@ -1493,6 +2115,22 @@ impl GeneralNameRef { self.ia5_string(ffi::GEN_EMAIL) } + /// Returns the contents of this `GeneralName` if it is a `directoryName`. + pub fn directory_name(&self) -> Option<&X509NameRef> { + unsafe { + if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME { + return None; + } + + #[cfg(boringssl)] + let d = (*self.as_ptr()).d.ptr; + #[cfg(not(boringssl))] + let d = (*self.as_ptr()).d; + + Some(X509NameRef::from_const_ptr(d as *const _)) + } + } + /// Returns the contents of this `GeneralName` if it is a `dNSName`. pub fn dnsname(&self) -> Option<&str> { self.ia5_string(ffi::GEN_DNS) @@ -1531,8 +2169,13 @@ impl fmt::Debug for GeneralNameRef { } else if let Some(uri) = self.uri() { formatter.write_str(uri) } else if let Some(ipaddress) = self.ipaddress() { - let result = String::from_utf8_lossy(ipaddress); - formatter.write_str(&result) + let address = <[u8; 16]>::try_from(ipaddress) + .map(IpAddr::from) + .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from)); + match address { + Ok(a) => fmt::Debug::fmt(&a, formatter), + Err(_) => fmt::Debug::fmt(ipaddress, formatter), + } } else { formatter.write_str("(empty)") } @@ -1543,6 +2186,49 @@ impl Stackable for GeneralName { type StackType = ffi::stack_st_GENERAL_NAME; } +foreign_type_and_impl_send_sync! { + type CType = ffi::DIST_POINT; + fn drop = ffi::DIST_POINT_free; + + /// A `X509` distribution point. + pub struct DistPoint; + /// Reference to `DistPoint`. + pub struct DistPointRef; +} + +impl DistPointRef { + /// Returns the name of this distribution point if it exists + pub fn distpoint(&self) -> Option<&DistPointNameRef> { + unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::DIST_POINT_NAME; + fn drop = ffi::DIST_POINT_NAME_free; + + /// A `X509` distribution point. + pub struct DistPointName; + /// Reference to `DistPointName`. + pub struct DistPointNameRef; +} + +impl DistPointNameRef { + /// Returns the contents of this DistPointName if it is a fullname. + pub fn fullname(&self) -> Option<&StackRef> { + unsafe { + if (*self.as_ptr()).type_ != 0 { + return None; + } + StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname) + } + } +} + +impl Stackable for DistPoint { + type StackType = ffi::stack_st_DIST_POINT; +} + foreign_type_and_impl_send_sync! { type CType = ffi::ACCESS_DESCRIPTION; fn drop = ffi::ACCESS_DESCRIPTION_free; @@ -1722,3 +2408,126 @@ cfg_if! { } } } + +cfg_if! { + if #[cfg(any(ossl110, libressl350, boringssl))] { + use ffi::{ + X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate, + X509_CRL_get_REVOKED, + X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber, + }; + } else { + #[allow(bad_style)] + unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { + (*(*x).crl).lastUpdate + } + #[allow(bad_style)] + unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { + (*(*x).crl).nextUpdate + } + #[allow(bad_style)] + unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME { + (*(*x).crl).issuer + } + #[allow(bad_style)] + unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED { + (*(*x).crl).revoked + } + #[allow(bad_style)] + unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER { + (*x).serialNumber + } + #[allow(bad_style)] + unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME { + (*x).revocationDate + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct X509PurposeId(c_int); + +impl X509PurposeId { + pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT); + pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER); + pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER); + pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN); + pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT); + pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN); + pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY); + pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER); + pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN); + + /// Constructs an `X509PurposeId` from a raw OpenSSL value. + pub fn from_raw(id: c_int) -> Self { + X509PurposeId(id) + } + + /// Returns the raw OpenSSL value represented by this type. + pub fn as_raw(&self) -> c_int { + self.0 + } +} + +/// A reference to an [`X509_PURPOSE`]. +pub struct X509PurposeRef(Opaque); + +/// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL. +impl ForeignTypeRef for X509PurposeRef { + type CType = ffi::X509_PURPOSE; +} + +impl X509PurposeRef { + /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short + /// names include + /// - "sslclient", + /// - "sslserver", + /// - "nssslserver", + /// - "smimesign", + /// - "smimeencrypt", + /// - "crlsign", + /// - "any", + /// - "ocsphelper", + /// - "timestampsign" + /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose. + #[allow(clippy::unnecessary_cast)] + pub fn get_by_sname(sname: &str) -> Result { + unsafe { + let sname = CString::new(sname).unwrap(); + cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?; + } else { + let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?; + } + } + Ok(purpose) + } + } + /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g. + /// `X509PurposeRef::get_by_sname()`. + #[corresponds(X509_PURPOSE_get0)] + pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> { + unsafe { + let ptr = cvt_p(ffi::X509_PURPOSE_get0(idx))?; + Ok(X509PurposeRef::from_ptr(ptr)) + } + } + + /// Get the purpose value from an X509Purpose structure. This value is one of + /// - `X509_PURPOSE_SSL_CLIENT` + /// - `X509_PURPOSE_SSL_SERVER` + /// - `X509_PURPOSE_NS_SSL_SERVER` + /// - `X509_PURPOSE_SMIME_SIGN` + /// - `X509_PURPOSE_SMIME_ENCRYPT` + /// - `X509_PURPOSE_CRL_SIGN` + /// - `X509_PURPOSE_ANY` + /// - `X509_PURPOSE_OCSP_HELPER` + /// - `X509_PURPOSE_TIMESTAMP_SIGN` + pub fn purpose(&self) -> X509PurposeId { + unsafe { + let x509_purpose: *mut ffi::X509_PURPOSE = self.as_ptr(); + X509PurposeId::from_raw((*x509_purpose).purpose) + } + } +} diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index a685fa18e6..a90bf3515f 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -51,7 +51,7 @@ use crate::ssl::SslFiletype; use crate::stack::StackRef; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef}; -use crate::x509::{X509Object, X509}; +use crate::x509::{X509Object, X509PurposeId, X509}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; #[cfg(not(boringssl))] @@ -125,6 +125,13 @@ impl X509StoreBuilderRef { unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) } } + /// Sets the certificate purpose. + /// The purpose value can be obtained by `X509PurposeRef::get_by_sname()` + #[corresponds(X509_STORE_set_purpose)] + pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_STORE_set_purpose(self.as_ptr(), purpose.as_raw())).map(|_| ()) } + } + /// Sets certificate chain validation related parameters. #[corresponds[X509_STORE_set1_param]] #[cfg(any(ossl102, libressl261))] @@ -145,7 +152,7 @@ generic_foreign_type_and_impl_send_sync! { /// Marker type corresponding to the [`X509_LOOKUP_hash_dir`] lookup method. /// -/// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_LOOKUP_hash_dir.html +/// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/manmaster/crypto/X509_LOOKUP_hash_dir.html // FIXME should be an enum pub struct HashDir; @@ -194,8 +201,9 @@ impl X509Lookup { #[cfg(not(boringssl))] impl X509LookupRef { - #[corresponds(X509_load_cert_file)] /// Specifies a file from which certificates will be loaded + #[corresponds(X509_load_cert_file)] + // FIXME should return 'Result>( &mut self, file: P, @@ -211,6 +219,23 @@ impl X509LookupRef { .map(|_| ()) } } + + /// Specifies a file from which certificate revocation lists will be loaded + #[corresponds(X509_load_crl_file)] + pub fn load_crl_file>( + &mut self, + file: P, + file_type: SslFiletype, + ) -> Result { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt(ffi::X509_load_crl_file( + self.as_ptr(), + file.as_ptr(), + file_type.as_raw(), + )) + } + } } generic_foreign_type_and_impl_send_sync! { diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 33d6f4f1e9..da3ce2fed2 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use crate::asn1::Asn1Time; +use crate::asn1::{Asn1Object, Asn1OctetString, Asn1Time}; use crate::bn::{BigNum, MsbOption}; use crate::hash::MessageDigest; use crate::nid::Nid; @@ -18,13 +18,24 @@ use crate::x509::store::X509Lookup; use crate::x509::store::X509StoreBuilder; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::{X509VerifyFlags, X509VerifyParam}; +#[cfg(ossl102)] +use crate::x509::X509PurposeId; +#[cfg(any(ossl102, libressl261))] +use crate::x509::X509PurposeRef; +#[cfg(ossl110)] +use crate::x509::{CrlReason, X509Builder}; +use crate::x509::{ + CrlStatus, X509Crl, X509Extension, X509Name, X509Req, X509StoreContext, X509VerifyResult, X509, +}; + #[cfg(ossl110)] -use crate::x509::X509Builder; -use crate::x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509}; +use foreign_types::ForeignType; use hex::{self, FromHex}; #[cfg(any(ossl102, libressl261))] use libc::time_t; +use super::{CertificateIssuer, ReasonCode}; + fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); PKey::from_rsa(rsa).unwrap() @@ -160,6 +171,70 @@ fn test_subject_alt_name() { assert_eq!(Some("http://www.example.com"), subject_alt_names[4].uri()); } +#[test] +#[cfg(ossl110)] +fn test_retrieve_pathlen() { + let cert = include_bytes!("../../test/root-ca.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert_eq!(cert.pathlen(), None); + + let cert = include_bytes!("../../test/intermediate-ca.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert_eq!(cert.pathlen(), Some(0)); + + let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert_eq!(cert.pathlen(), None); +} + +#[test] +#[cfg(ossl110)] +fn test_subject_key_id() { + let cert = include_bytes!("../../test/certv3.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let subject_key_id = cert.subject_key_id().unwrap(); + assert_eq!( + subject_key_id.as_slice(), + &b"\xB6\x73\x2F\x61\xA5\x4B\xA1\xEF\x48\x2C\x15\xB1\x9F\xF3\xDC\x34\x2F\xBC\xAC\x30"[..] + ); +} + +#[test] +#[cfg(ossl110)] +fn test_authority_key_id() { + let cert = include_bytes!("../../test/certv3.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let authority_key_id = cert.authority_key_id().unwrap(); + assert_eq!( + authority_key_id.as_slice(), + &b"\x6C\xD3\xA5\x03\xAB\x0D\x5F\x2C\xC9\x8D\x8A\x9C\x88\xA7\x88\x77\xB8\x37\xFD\x9A"[..] + ); +} + +#[test] +#[cfg(ossl111d)] +fn test_authority_issuer_and_serial() { + let cert = include_bytes!("../../test/authority_key_identifier.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let authority_issuer = cert.authority_issuer().unwrap(); + assert_eq!(1, authority_issuer.len()); + let dn = authority_issuer[0].directory_name().unwrap(); + let mut o = dn.entries_by_nid(Nid::ORGANIZATIONNAME); + let o = o.next().unwrap().data().as_utf8().unwrap(); + assert_eq!(o.as_bytes(), b"PyCA"); + let mut cn = dn.entries_by_nid(Nid::COMMONNAME); + let cn = cn.next().unwrap().data().as_utf8().unwrap(); + assert_eq!(cn.as_bytes(), b"cryptography.io"); + + let authority_serial = cert.authority_serial().unwrap(); + let serial = authority_serial.to_bn().unwrap(); + let expected = BigNum::from_u32(3).unwrap(); + assert_eq!(serial, expected); +} + #[test] fn test_subject_alt_name_iter() { let cert = include_bytes!("../../test/alt_name_cert.pem"); @@ -281,6 +356,76 @@ fn x509_builder() { assert_eq!(serial, x509.serial_number().to_bn().unwrap()); } +#[test] +// This tests `X509Extension::new`, even though its deprecated. +#[allow(deprecated)] +fn x509_extension_new() { + assert!(X509Extension::new(None, None, "crlDistributionPoints", "section").is_err()); + assert!(X509Extension::new(None, None, "proxyCertInfo", "").is_err()); + assert!(X509Extension::new(None, None, "certificatePolicies", "").is_err()); + assert!(X509Extension::new(None, None, "subjectAltName", "dirName:section").is_err()); +} + +#[test] +fn x509_extension_new_from_der() { + let ext = X509Extension::new_from_der( + &Asn1Object::from_str("2.5.29.19").unwrap(), + true, + &Asn1OctetString::new_from_bytes(b"\x30\x03\x01\x01\xff").unwrap(), + ) + .unwrap(); + assert_eq!( + ext.to_der().unwrap(), + b"0\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff" + ); +} + +#[test] +fn x509_extension_to_der() { + let builder = X509::builder().unwrap(); + + for (ext, expected) in [ + ( + BasicConstraints::new().critical().ca().build().unwrap(), + b"0\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff" as &[u8], + ), + ( + SubjectAlternativeName::new() + .dns("example.com,DNS:example2.com") + .build(&builder.x509v3_context(None, None)) + .unwrap(), + b"0'\x06\x03U\x1d\x11\x04 0\x1e\x82\x1cexample.com,DNS:example2.com", + ), + ( + SubjectAlternativeName::new() + .rid("1.2.3.4") + .uri("https://example.com") + .build(&builder.x509v3_context(None, None)) + .unwrap(), + b"0#\x06\x03U\x1d\x11\x04\x1c0\x1a\x88\x03*\x03\x04\x86\x13https://example.com", + ), + ( + ExtendedKeyUsage::new() + .server_auth() + .other("2.999.1") + .other("clientAuth") + .build() + .unwrap(), + b"0\x22\x06\x03U\x1d%\x04\x1b0\x19\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x03\x887\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x02", + ), + ] { + assert_eq!(&ext.to_der().unwrap(), expected); + } +} + +#[test] +fn eku_invalid_other() { + assert!(ExtendedKeyUsage::new() + .other("1.1.1.1.1,2.2.2.2.2") + .build() + .is_err()); +} + #[test] fn x509_req_builder() { let pkey = pkey(); @@ -438,6 +583,68 @@ fn test_verify_fails_with_crl_flag_set_and_no_crl() { ) } +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_verify_cert_with_purpose() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let chain = Stack::new().unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + let purpose_idx = X509PurposeRef::get_by_sname("sslserver") + .expect("Getting certificate purpose 'sslserver' failed"); + let x509_purposeref = + X509PurposeRef::from_idx(purpose_idx).expect("Getting certificate purpose failed"); + store_bldr + .set_purpose(x509_purposeref.purpose()) + .expect("Setting certificate purpose failed"); + store_bldr.add_cert(ca).unwrap(); + + let store = store_bldr.build(); + + let mut context = X509StoreContext::new().unwrap(); + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_verify_cert_with_wrong_purpose_fails() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let chain = Stack::new().unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + let purpose_idx = X509PurposeRef::get_by_sname("timestampsign") + .expect("Getting certificate purpose 'timestampsign' failed"); + let x509_purpose = + X509PurposeRef::from_idx(purpose_idx).expect("Getting certificate purpose failed"); + store_bldr + .set_purpose(x509_purpose.purpose()) + .expect("Setting certificate purpose failed"); + store_bldr.add_cert(ca).unwrap(); + + let store = store_bldr.build(); + + let expected_error = ffi::X509_V_ERR_INVALID_PURPOSE; + let mut context = X509StoreContext::new().unwrap(); + assert_eq!( + context + .init(&store, &cert, &chain, |c| { + c.verify_cert()?; + Ok(c.error()) + }) + .unwrap() + .as_raw(), + expected_error + ) +} + #[cfg(ossl110)] #[test] fn x509_ref_version() { @@ -465,6 +672,66 @@ fn x509_ref_version_no_version_set() { ); } +#[test] +fn test_load_crl() { + let ca = include_bytes!("../../test/crl-ca.crt"); + let ca = X509::from_pem(ca).unwrap(); + + let crl = include_bytes!("../../test/test.crl"); + let crl = X509Crl::from_der(crl).unwrap(); + assert!(crl.verify(&ca.public_key().unwrap()).unwrap()); + + let cert = include_bytes!("../../test/subca.crt"); + let cert = X509::from_pem(cert).unwrap(); + + let revoked = match crl.get_by_cert(&cert) { + CrlStatus::Revoked(revoked) => revoked, + _ => panic!("cert should be revoked"), + }; + + assert_eq!( + revoked.serial_number().to_bn().unwrap(), + cert.serial_number().to_bn().unwrap(), + "revoked and cert serial numbers should match" + ); +} + +#[test] +fn test_crl_entry_extensions() { + let crl = include_bytes!("../../test/entry_extensions.crl"); + let crl = X509Crl::from_pem(crl).unwrap(); + + let revoked_certs = crl.get_revoked().unwrap(); + let entry = &revoked_certs[0]; + + let (critical, issuer) = entry + .extension::() + .unwrap() + .expect("Certificate issuer extension should be present"); + assert!(critical, "Certificate issuer extension is critical"); + assert_eq!(issuer.len(), 1, "Certificate issuer should have one entry"); + let issuer = issuer[0] + .directory_name() + .expect("Issuer should be a directory name"); + assert_eq!( + format!("{:?}", issuer), + r#"[countryName = "GB", commonName = "Test CA"]"# + ); + + // reason_code can't be inspected without ossl110 + #[allow(unused_variables)] + let (critical, reason_code) = entry + .extension::() + .unwrap() + .expect("Reason code extension should be present"); + assert!(!critical, "Reason code extension is not critical"); + #[cfg(ossl110)] + assert_eq!( + CrlReason::KEY_COMPROMISE, + CrlReason::from_raw(reason_code.get_i64().unwrap() as ffi::c_int) + ); +} + #[test] fn test_save_subject_der() { let cert = include_bytes!("../../test/cert.pem"); @@ -550,6 +817,16 @@ fn test_name_cmp() { assert_eq!(Ordering::Greater, subject.try_cmp(issuer).unwrap()); } +#[test] +#[cfg(any(boringssl, ossl110, libressl270))] +fn test_name_to_owned() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let name = cert.subject_name(); + let copied_name = name.to_owned().unwrap(); + assert_eq!(Ordering::Equal, name.try_cmp(&copied_name).unwrap()); +} + #[test] #[cfg(any(ossl102, libressl261))] fn test_verify_param_set_time_fails_verification() { @@ -634,6 +911,7 @@ fn test_verify_param_set_depth() { #[test] #[cfg(any(ossl102, libressl261))] +#[allow(clippy::bool_to_int_with_if)] fn test_verify_param_set_depth_fails_verification() { let cert = include_bytes!("../../test/leaf.pem"); let cert = X509::from_pem(cert).unwrap(); @@ -692,3 +970,192 @@ fn test_load_cert_file() { .init(&store, &cert, &chain, |c| c.verify_cert()) .unwrap()); } + +#[test] +#[cfg(ossl110)] +fn test_verify_param_auth_level() { + let mut param = X509VerifyParam::new().unwrap(); + let auth_lvl = 2; + let auth_lvl_default = -1; + + assert_eq!(param.auth_level(), auth_lvl_default); + + param.set_auth_level(auth_lvl); + assert_eq!(param.auth_level(), auth_lvl); +} + +#[test] +#[cfg(ossl102)] +fn test_set_purpose() { + let cert = include_bytes!("../../test/leaf.pem"); + let cert = X509::from_pem(cert).unwrap(); + let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem"); + let intermediate_ca = X509::from_pem(intermediate_ca).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let mut chain = Stack::new().unwrap(); + chain.push(intermediate_ca).unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + store_bldr.add_cert(ca).unwrap(); + let mut verify_params = X509VerifyParam::new().unwrap(); + verify_params.set_purpose(X509PurposeId::ANY).unwrap(); + store_bldr.set_param(&verify_params).unwrap(); + let store = store_bldr.build(); + let mut context = X509StoreContext::new().unwrap(); + + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); +} + +#[test] +#[cfg(ossl102)] +fn test_set_purpose_fails_verification() { + let cert = include_bytes!("../../test/leaf.pem"); + let cert = X509::from_pem(cert).unwrap(); + let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem"); + let intermediate_ca = X509::from_pem(intermediate_ca).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let mut chain = Stack::new().unwrap(); + chain.push(intermediate_ca).unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + store_bldr.add_cert(ca).unwrap(); + let mut verify_params = X509VerifyParam::new().unwrap(); + verify_params + .set_purpose(X509PurposeId::TIMESTAMP_SIGN) + .unwrap(); + store_bldr.set_param(&verify_params).unwrap(); + let store = store_bldr.build(); + + let expected_error = ffi::X509_V_ERR_INVALID_PURPOSE; + let mut context = X509StoreContext::new().unwrap(); + assert_eq!( + context + .init(&store, &cert, &chain, |c| { + c.verify_cert()?; + Ok(c.error()) + }) + .unwrap() + .as_raw(), + expected_error + ) +} + +#[test] +#[cfg(any(ossl101, libressl350))] +fn test_add_name_entry() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let inp_name = cert.subject_name().entries().next().unwrap(); + + let mut names = X509Name::builder().unwrap(); + names.append_entry(inp_name).unwrap(); + let names = names.build(); + + let mut entries = names.entries(); + let outp_name = entries.next().unwrap(); + assert_eq!(outp_name.object().nid(), inp_name.object().nid()); + assert_eq!(outp_name.data().as_slice(), inp_name.data().as_slice()); + assert!(entries.next().is_none()); +} + +#[test] +#[cfg(not(boringssl))] +fn test_load_crl_file_fail() { + let mut store_bldr = X509StoreBuilder::new().unwrap(); + let lookup = store_bldr.add_lookup(X509Lookup::file()).unwrap(); + let res = lookup.load_crl_file("test/root-ca.pem", SslFiletype::PEM); + assert!(res.is_err()); +} + +#[cfg(ossl110)] +fn ipaddress_as_subject_alternative_name_is_formatted_in_debug(expected_ip: T) +where + T: Into, +{ + let expected_ip = format!("{:?}", expected_ip.into()); + let mut builder = X509Builder::new().unwrap(); + let san = SubjectAlternativeName::new() + .ip(&expected_ip) + .build(&builder.x509v3_context(None, None)) + .unwrap(); + builder.append_extension(san).unwrap(); + let cert = builder.build(); + let actual_ip = cert + .subject_alt_names() + .into_iter() + .flatten() + .map(|n| format!("{:?}", *n)) + .next() + .unwrap(); + assert_eq!(actual_ip, expected_ip); +} + +#[cfg(ossl110)] +#[test] +fn ipv4_as_subject_alternative_name_is_formatted_in_debug() { + ipaddress_as_subject_alternative_name_is_formatted_in_debug([8u8, 8, 8, 128]); +} + +#[cfg(ossl110)] +#[test] +fn ipv6_as_subject_alternative_name_is_formatted_in_debug() { + ipaddress_as_subject_alternative_name_is_formatted_in_debug([ + 8u8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 128, + ]); +} + +#[cfg(ossl110)] +#[test] +fn other_name_as_subject_alternative_name() { + let oid = Asn1Object::from_str("1.3.6.1.5.5.7.8.11").unwrap(); + // this is the hex representation of "test" encoded as a ia5string + let content = [0x16, 0x04, 0x74, 0x65, 0x73, 0x74]; + + let mut builder = X509Builder::new().unwrap(); + let san = SubjectAlternativeName::new() + .other_name2(oid, &content) + .build(&builder.x509v3_context(None, None)) + .unwrap(); + builder.append_extension(san).unwrap(); + let cert = builder.build(); + let general_name = cert + .subject_alt_names() + .into_iter() + .flatten() + .next() + .unwrap(); + unsafe { + assert_eq!((*general_name.as_ptr()).type_, 0); + } +} + +#[test] +fn test_dist_point() { + let cert = include_bytes!("../../test/certv3.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let dps = cert.crl_distribution_points().unwrap(); + let dp = dps.get(0).unwrap(); + let dp_nm = dp.distpoint().unwrap(); + let dp_gns = dp_nm.fullname().unwrap(); + let dp_gn = dp_gns.get(0).unwrap(); + assert_eq!(dp_gn.uri().unwrap(), "http://example.com/crl.pem"); + + let dp = dps.get(1).unwrap(); + let dp_nm = dp.distpoint().unwrap(); + let dp_gns = dp_nm.fullname().unwrap(); + let dp_gn = dp_gns.get(0).unwrap(); + assert_eq!(dp_gn.uri().unwrap(), "http://example.com/crl2.pem"); + assert!(dps.get(2).is_none()) +} + +#[test] +fn test_dist_point_null() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert!(cert.crl_distribution_points().is_none()); +} diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs index 20dd4bea8d..e8481c551c 100644 --- a/openssl/src/x509/verify.rs +++ b/openssl/src/x509/verify.rs @@ -4,6 +4,8 @@ use libc::{c_int, c_uint, c_ulong, time_t}; use std::net::IpAddr; use crate::error::ErrorStack; +#[cfg(ossl102)] +use crate::x509::X509PurposeId; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -118,9 +120,11 @@ impl X509VerifyParamRef { #[corresponds(X509_VERIFY_PARAM_set1_host)] pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { unsafe { + // len == 0 means "run strlen" :( + let raw_host = if host.is_empty() { "\0" } else { host }; cvt(ffi::X509_VERIFY_PARAM_set1_host( self.as_ptr(), - host.as_ptr() as *const _, + raw_host.as_ptr() as *const _, host.len(), )) .map(|_| ()) @@ -162,4 +166,25 @@ impl X509VerifyParamRef { pub fn set_depth(&mut self, depth: c_int) { unsafe { ffi::X509_VERIFY_PARAM_set_depth(self.as_ptr(), depth) } } + + /// Sets the authentication security level to auth_level + #[corresponds(X509_VERIFY_PARAM_set_auth_level)] + #[cfg(ossl110)] + pub fn set_auth_level(&mut self, lvl: c_int) { + unsafe { ffi::X509_VERIFY_PARAM_set_auth_level(self.as_ptr(), lvl) } + } + + /// Gets the current authentication security level + #[corresponds(X509_VERIFY_PARAM_get_auth_level)] + #[cfg(ossl110)] + pub fn auth_level(&self) -> i32 { + unsafe { ffi::X509_VERIFY_PARAM_get_auth_level(self.as_ptr()) } + } + + /// Sets the verification purpose + #[corresponds(X509_VERIFY_PARAM_set_purpose)] + #[cfg(ossl102)] + pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_VERIFY_PARAM_set_purpose(self.as_ptr(), purpose.0)).map(|_| ()) } + } } diff --git a/openssl/test/authority_key_identifier.pem b/openssl/test/authority_key_identifier.pem new file mode 100644 index 0000000000..cbe9169fc9 --- /dev/null +++ b/openssl/test/authority_key_identifier.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDIjCCAgqgAwIBAgIBAzANBgkqhkiG9w0BAQUFADApMQ0wCwYDVQQKDARQeUNB +MRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcNMTUwNTAzMDk0OTU2WhcNMTYw +NTAyMDk0OTU2WjApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFw +aHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCadi1UZioxdnP +ajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLOhjNLz6PO6KeRbjz9GhTA2hdk +xtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4cMwMe5NGeeg1tfzbJwldIN+cK +vabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr6E9puord3h6Mh8Jfnc3TDAq8 +Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk/XhRzt8Xcfc3yAXIwazvLf8b +YP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+qUYpxA7ZJ/VAGadMulYbXaO8 +Syi39HTpAgMBAAGjVTBTMFEGA1UdIwRKMEiAFDlFPso9Yh3qhkn2WqtAt6RwmPHs +oS2kKzApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW+C +AQMwDQYJKoZIhvcNAQEFBQADggEBAFbZYy6aZJUK/f7nJx2Rs/ht6hMbM32/RoXZ +JGbYapNVqVu/vymcfc/se3FHS5OVmPsnRlo/FIKDn/r5DGl73Sn/FvDJiLJZFucT +msyYuHZ+ZRYWzWmN2fcB3cfxj0s3qps6f5OoCOqoINOSe4HRGlw4X9keZSD+3xAt +vHNwQdlPC7zWbPdrzLT+FqR0e/O81vFJJS6drHJWqPcR3NQVtZw+UF7A/HKwbfeL +Nu2zj6165hzOi9HUxa2/mPr/eLUUV1sTzXp2+TFjt3rVCjW1XnpMLdwNBHzjpyAB +dTOX3iw0+BPy3s2jtnCW1PLpc74kvSTaBwhg74sq39EXfIKax00= +-----END CERTIFICATE----- diff --git a/openssl/test/ca.crt b/openssl/test/ca.crt new file mode 100644 index 0000000000..a0a8ab2390 --- /dev/null +++ b/openssl/test/ca.crt @@ -0,0 +1,88 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 13:ae:da:d8:f4:18:d7:73:b8:bd:35:c9:ce:8e:b3:fc + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=TestCA + Validity + Not Before: Jun 6 19:11:19 2019 GMT + Not After : May 21 19:11:19 2022 GMT + Subject: CN=SubCA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b0:09:fc:54:e7:6a:9f:0c:bd:ad:5a:8d:ef:94: + 4e:11:a6:87:19:4f:bf:a6:e1:62:a5:2d:b7:17:df: + 67:53:70:da:fe:7d:99:17:ee:13:47:0b:40:0b:a2: + 34:32:a9:d3:bf:20:fc:13:77:a1:d5:26:60:1f:f0: + d4:be:dc:76:7c:1e:6c:b4:4c:01:7c:56:cd:5c:53: + ec:81:b3:81:2a:b2:35:26:06:5a:79:e0:b3:9e:e4: + 57:e1:09:de:ad:7f:c8:cd:87:ee:49:93:30:52:58: + b2:bc:0f:c1:b6:10:44:f8:85:d5:5b:0a:9b:28:fe: + f4:f4:4a:16:a6:f7:25:e9:96:47:69:73:5b:33:77: + 92:7d:61:8d:2a:3d:d5:04:89:40:bf:6b:d2:fd:5d: + e2:1a:80:a9:8e:c8:92:f6:e5:4c:00:84:f9:6e:2a: + 93:a3:23:ee:28:23:81:f4:54:f0:18:2c:ee:32:8e: + 38:9c:a0:c8:33:04:b0:fc:4c:43:1a:5c:04:84:9f: + 73:c6:08:c7:1d:64:39:fe:72:19:3b:cc:a5:fd:0b: + 43:25:0d:2b:a9:88:77:9e:62:e6:ac:c2:9a:60:42: + 4f:4a:54:47:bc:a0:29:72:7c:38:52:c9:ea:27:c5: + 3d:d0:81:4a:3e:b8:78:79:4b:89:b8:4e:6d:1b:24: + 15:bd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 CRL Distribution Points: + + Full Name: + URI:http://127.0.0.1:8081/pki/test.crl + + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Key Identifier: + FD:82:45:39:A1:91:41:F2:66:CC:0D:75:D5:0D:40:D5:81:A7:A1:43 + X509v3 Authority Key Identifier: + keyid:C5:CC:F5:A1:8C:D9:E4:A7:BA:EC:21:F5:D1:84:23:EA:0D:C2:C7:30 + DirName:/CN=TestCA + serial:33:E7:04:87:09:32:87:21:D9:CD:7C:AA:4C:5A:BB:2C:6C:7B:54:28 + + X509v3 Key Usage: + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 96:a0:ff:8a:4b:bd:45:96:c9:72:3c:63:e3:48:c4:ab:ef:7e: + db:76:3f:d9:02:9e:69:c8:d9:36:55:e1:f5:9b:c9:69:d8:69: + 02:ac:50:8c:60:94:2c:2e:b9:a8:65:ac:f5:00:b0:8b:96:25: + 0b:8a:ef:94:21:57:e2:04:c2:c3:86:bf:06:4e:91:5c:e6:bc: + 1b:03:31:8b:64:ea:c5:79:c3:5c:94:e5:aa:67:7e:74:12:07: + 14:fd:cd:32:02:26:26:c9:0a:ed:d4:da:ee:2a:84:e3:f1:60: + b3:09:77:27:a1:3c:ac:ec:61:18:30:b5:6d:1f:16:0a:24:1a: + cf:1c:1b:60:a5:60:e5:2c:8b:cf:37:83:0c:15:e7:79:30:3f: + ee:50:45:7c:4b:c6:2c:cd:2c:81:0a:98:f1:65:44:7a:ca:2a: + 20:1a:de:19:d9:4b:ca:a1:e2:a4:b5:14:47:bf:b4:68:15:03: + c0:55:e5:f4:47:0e:55:9f:fe:85:d8:2c:7d:d0:1a:96:11:b9: + 68:b7:74:1e:61:94:c1:ae:87:52:2d:c6:26:ba:51:ed:f1:91: + c0:e6:4c:f8:ad:02:23:75:51:fc:f8:69:05:ec:cf:31:50:5a: + 41:78:eb:3d:27:4d:9b:68:ef:ba:0e:ba:3a:7d:60:00:9d:53: + a5:08:3d:c6 +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIQE67a2PQY13O4vTXJzo6z/DANBgkqhkiG9w0BAQsFADAR +MQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTkwNjA2MTkxMTE5WhcNMjIwNTIxMTkxMTE5 +WjAQMQ4wDAYDVQQDDAVTdWJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALAJ/FTnap8Mva1aje+UThGmhxlPv6bhYqUttxffZ1Nw2v59mRfuE0cLQAui +NDKp078g/BN3odUmYB/w1L7cdnwebLRMAXxWzVxT7IGzgSqyNSYGWnngs57kV+EJ +3q1/yM2H7kmTMFJYsrwPwbYQRPiF1VsKmyj+9PRKFqb3JemWR2lzWzN3kn1hjSo9 +1QSJQL9r0v1d4hqAqY7IkvblTACE+W4qk6Mj7igjgfRU8Bgs7jKOOJygyDMEsPxM +QxpcBISfc8YIxx1kOf5yGTvMpf0LQyUNK6mId55i5qzCmmBCT0pUR7ygKXJ8OFLJ +6ifFPdCBSj64eHlLibhObRskFb0CAwEAAaOBwDCBvTAzBgNVHR8ELDAqMCigJqAk +hiJodHRwOi8vMTI3LjAuMC4xOjgwODEvcGtpL3Rlc3QuY3JsMAwGA1UdEwQFMAMB +Af8wHQYDVR0OBBYEFP2CRTmhkUHyZswNddUNQNWBp6FDMEwGA1UdIwRFMEOAFMXM +9aGM2eSnuuwh9dGEI+oNwscwoRWkEzARMQ8wDQYDVQQDDAZUZXN0Q0GCFDPnBIcJ +Moch2c18qkxauyxse1QoMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +lqD/iku9RZbJcjxj40jEq+9+23Y/2QKeacjZNlXh9ZvJadhpAqxQjGCULC65qGWs +9QCwi5YlC4rvlCFX4gTCw4a/Bk6RXOa8GwMxi2TqxXnDXJTlqmd+dBIHFP3NMgIm +JskK7dTa7iqE4/Fgswl3J6E8rOxhGDC1bR8WCiQazxwbYKVg5SyLzzeDDBXneTA/ +7lBFfEvGLM0sgQqY8WVEesoqIBreGdlLyqHipLUUR7+0aBUDwFXl9EcOVZ/+hdgs +fdAalhG5aLd0HmGUwa6HUi3GJrpR7fGRwOZM+K0CI3VR/PhpBezPMVBaQXjrPSdN +m2jvug66On1gAJ1TpQg9xg== +-----END CERTIFICATE----- diff --git a/openssl/test/certv3.pem b/openssl/test/certv3.pem new file mode 100644 index 0000000000..819409164d --- /dev/null +++ b/openssl/test/certv3.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDwTCCAqmgAwIBAgIUDeCGNunyJfBd3U/qUtmCcvbMyZwwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzAxMjMxMzMzNTJaFw0zMzAx +MjAxMzMzNTJaMFoxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmZvb2Jh +ci5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo9CWMRLMXo1CF +/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 +kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS +wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM +jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT +Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt +OzboKgs1AgMBAAGjgZMwgZAwTgYDVR0fBEcwRTAgoB6gHIYaaHR0cDovL2V4YW1w +bGUuY29tL2NybC5wZW0wIaAfoB2GG2h0dHA6Ly9leGFtcGxlLmNvbS9jcmwyLnBl +bTAdBgNVHQ4EFgQUtnMvYaVLoe9ILBWxn/PcNC+8rDAwHwYDVR0jBBgwFoAUbNOl +A6sNXyzJjYqciKeId7g3/ZowDQYJKoZIhvcNAQELBQADggEBAJZyk6Eo4p3JIyOt +7t6ET3K18BKvlRilze+zrGkaQYvKRsP6YzbZWgcIq59hy5VeFCX5O2WP91CPG3MU +I9eRiih66/ry3G4I8QEdpRKnn0N5unbGjb5qPT5wXrhU4IO+vn3sGZGM4uIM1/3K +N/bOh9CTsu9YqrdHSGeDyNzCy/XZ/j5bP4aNm31ZDNCZDFsbjr3/yTLcpHPL0UP3 +mCX8D16BDu1Nep+wK9VRuOEw6Z9tlT/VjTImzoOUoJO/o2UHfSHahX+n2aC5OpI6 +BdhaFBuJ1vn+yTWf3zIjhWUdp9TlzgRyFiyetP2FcKwremVVGdDq/Y6dfXaq8CA1 +6Fr9KTY= +-----END CERTIFICATE----- diff --git a/openssl/test/certv3_extfile b/openssl/test/certv3_extfile new file mode 100644 index 0000000000..1b3df49482 --- /dev/null +++ b/openssl/test/certv3_extfile @@ -0,0 +1 @@ +crlDistributionPoints=URI:http://example.com/crl.pem,URI:http://example.com/crl2.pem diff --git a/openssl/test/crl-ca.crt b/openssl/test/crl-ca.crt new file mode 100644 index 0000000000..a4a9075af4 --- /dev/null +++ b/openssl/test/crl-ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPDCCAiSgAwIBAgIUM+cEhwkyhyHZzXyqTFq7LGx7VCgwDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGVGVzdENBMB4XDTE5MDYwNjE5MTA1NVoXDTI5MDYwMzE5 +MTA1NVowETEPMA0GA1UEAwwGVGVzdENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAtNcFPtD1MHcolhgTHIAx/b9OyawCbVzvgasv8R9+94ZMhoGc/tNc +dVg271pCSmj+zYAFYsIwjxW+iq2e5A/fiBc6uqtNfEbU7+77QzxFG5wIbXtmmqEb +dVbqBT28NeKTR6X+EHlNgbw90CHy7byA7LMewxbTt2q1eY1RnB0ji8zdGZmIUPeC +WxzkxXEd0fg+KwBFN3YHV9CJX2KJ10qv7DvbKHeIVBU7osm6tzvNglNnnT90GFSY +zc59b+zS00axcY3Kn08Vt+1qWB9Sl8tixCTGqR538y/ambDr3NCWsiQYWys9KE1L +g0nEaIjb84R7b+qNmPtOezd9tanx7j9UzQIDAQABo4GLMIGIMB0GA1UdDgQWBBTF +zPWhjNnkp7rsIfXRhCPqDcLHMDBMBgNVHSMERTBDgBTFzPWhjNnkp7rsIfXRhCPq +DcLHMKEVpBMwETEPMA0GA1UEAwwGVGVzdENBghQz5wSHCTKHIdnNfKpMWrssbHtU +KDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +gdyQq6F8DO5rn7rZSLehTFx6tbtfncC/BOXZEGLZO0ciTrQ9Q8xHwRhz0W09QE1A +/GsBzb++PuvAl9i82WvunyPB5KZh+GPiaaqf466MdQrXj+IyqxeC9Lg9wEUjwRgp +ANVd3moKap5IZ9WDvhyEng2Oy8/btP2iqVEmd58rGAodd671eOPD8QkIxSquiIwy +Cu5s3IBZ0BOuSG9fWoyPTGMKAhzQPFiXGvWOabCkMz3TsPYVY5ENpq2K8cWn2D/r +TD1yPPdINg6HrALGD3S0sD+k588oS7U5oj1L8V4KJQTLSbh6/XcBpasa5Jdv7ZZe +lVgt69Gsn5Cf2BkbwhbF2Q== +-----END CERTIFICATE----- diff --git a/openssl/test/entry_extensions.crl b/openssl/test/entry_extensions.crl new file mode 100644 index 0000000000..9654171cf1 --- /dev/null +++ b/openssl/test/entry_extensions.crl @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBXDCCAQICAQEwCgYIKoZIzj0EAwIwETEPMA0GA1UEAwwGQ1JMIENBFw0yMzAz +MjgwOTQ5MThaFw0yMzA0MDQwOTUwMDdaMIGAMH4CFE+Y95/1pOqa6c9fUEJ8c04k +xu2PFw0yMzAzMjgwOTQ3MzNaMFcwLwYDVR0dAQH/BCUwI6QhMB8xCzAJBgNVBAYT +AkdCMRAwDgYDVQQDDAdUZXN0IENBMAoGA1UdFQQDCgEBMBgGA1UdGAQRGA8yMDIz +MDMyODA5NDQ0MFqgPTA7MB8GA1UdIwQYMBaAFNX1GZ0RWuC+4gz1wuy5H32T2W+R +MAoGA1UdFAQDAgEUMAwGA1UdHAQFMAOEAf8wCgYIKoZIzj0EAwIDSAAwRQIgbl7x +W+WVAb+zlvKcJLmHVuC+gbqR4jqwGIHHgQl2J8kCIQCo/sAF5sDqy/cL+fbzBeUe +YoY2h6lIkj9ENwU8ZCt03w== +-----END X509 CRL----- diff --git a/openssl/test/subca.crt b/openssl/test/subca.crt new file mode 100644 index 0000000000..a0a8ab2390 --- /dev/null +++ b/openssl/test/subca.crt @@ -0,0 +1,88 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 13:ae:da:d8:f4:18:d7:73:b8:bd:35:c9:ce:8e:b3:fc + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=TestCA + Validity + Not Before: Jun 6 19:11:19 2019 GMT + Not After : May 21 19:11:19 2022 GMT + Subject: CN=SubCA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b0:09:fc:54:e7:6a:9f:0c:bd:ad:5a:8d:ef:94: + 4e:11:a6:87:19:4f:bf:a6:e1:62:a5:2d:b7:17:df: + 67:53:70:da:fe:7d:99:17:ee:13:47:0b:40:0b:a2: + 34:32:a9:d3:bf:20:fc:13:77:a1:d5:26:60:1f:f0: + d4:be:dc:76:7c:1e:6c:b4:4c:01:7c:56:cd:5c:53: + ec:81:b3:81:2a:b2:35:26:06:5a:79:e0:b3:9e:e4: + 57:e1:09:de:ad:7f:c8:cd:87:ee:49:93:30:52:58: + b2:bc:0f:c1:b6:10:44:f8:85:d5:5b:0a:9b:28:fe: + f4:f4:4a:16:a6:f7:25:e9:96:47:69:73:5b:33:77: + 92:7d:61:8d:2a:3d:d5:04:89:40:bf:6b:d2:fd:5d: + e2:1a:80:a9:8e:c8:92:f6:e5:4c:00:84:f9:6e:2a: + 93:a3:23:ee:28:23:81:f4:54:f0:18:2c:ee:32:8e: + 38:9c:a0:c8:33:04:b0:fc:4c:43:1a:5c:04:84:9f: + 73:c6:08:c7:1d:64:39:fe:72:19:3b:cc:a5:fd:0b: + 43:25:0d:2b:a9:88:77:9e:62:e6:ac:c2:9a:60:42: + 4f:4a:54:47:bc:a0:29:72:7c:38:52:c9:ea:27:c5: + 3d:d0:81:4a:3e:b8:78:79:4b:89:b8:4e:6d:1b:24: + 15:bd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 CRL Distribution Points: + + Full Name: + URI:http://127.0.0.1:8081/pki/test.crl + + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Key Identifier: + FD:82:45:39:A1:91:41:F2:66:CC:0D:75:D5:0D:40:D5:81:A7:A1:43 + X509v3 Authority Key Identifier: + keyid:C5:CC:F5:A1:8C:D9:E4:A7:BA:EC:21:F5:D1:84:23:EA:0D:C2:C7:30 + DirName:/CN=TestCA + serial:33:E7:04:87:09:32:87:21:D9:CD:7C:AA:4C:5A:BB:2C:6C:7B:54:28 + + X509v3 Key Usage: + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 96:a0:ff:8a:4b:bd:45:96:c9:72:3c:63:e3:48:c4:ab:ef:7e: + db:76:3f:d9:02:9e:69:c8:d9:36:55:e1:f5:9b:c9:69:d8:69: + 02:ac:50:8c:60:94:2c:2e:b9:a8:65:ac:f5:00:b0:8b:96:25: + 0b:8a:ef:94:21:57:e2:04:c2:c3:86:bf:06:4e:91:5c:e6:bc: + 1b:03:31:8b:64:ea:c5:79:c3:5c:94:e5:aa:67:7e:74:12:07: + 14:fd:cd:32:02:26:26:c9:0a:ed:d4:da:ee:2a:84:e3:f1:60: + b3:09:77:27:a1:3c:ac:ec:61:18:30:b5:6d:1f:16:0a:24:1a: + cf:1c:1b:60:a5:60:e5:2c:8b:cf:37:83:0c:15:e7:79:30:3f: + ee:50:45:7c:4b:c6:2c:cd:2c:81:0a:98:f1:65:44:7a:ca:2a: + 20:1a:de:19:d9:4b:ca:a1:e2:a4:b5:14:47:bf:b4:68:15:03: + c0:55:e5:f4:47:0e:55:9f:fe:85:d8:2c:7d:d0:1a:96:11:b9: + 68:b7:74:1e:61:94:c1:ae:87:52:2d:c6:26:ba:51:ed:f1:91: + c0:e6:4c:f8:ad:02:23:75:51:fc:f8:69:05:ec:cf:31:50:5a: + 41:78:eb:3d:27:4d:9b:68:ef:ba:0e:ba:3a:7d:60:00:9d:53: + a5:08:3d:c6 +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIQE67a2PQY13O4vTXJzo6z/DANBgkqhkiG9w0BAQsFADAR +MQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTkwNjA2MTkxMTE5WhcNMjIwNTIxMTkxMTE5 +WjAQMQ4wDAYDVQQDDAVTdWJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALAJ/FTnap8Mva1aje+UThGmhxlPv6bhYqUttxffZ1Nw2v59mRfuE0cLQAui +NDKp078g/BN3odUmYB/w1L7cdnwebLRMAXxWzVxT7IGzgSqyNSYGWnngs57kV+EJ +3q1/yM2H7kmTMFJYsrwPwbYQRPiF1VsKmyj+9PRKFqb3JemWR2lzWzN3kn1hjSo9 +1QSJQL9r0v1d4hqAqY7IkvblTACE+W4qk6Mj7igjgfRU8Bgs7jKOOJygyDMEsPxM +QxpcBISfc8YIxx1kOf5yGTvMpf0LQyUNK6mId55i5qzCmmBCT0pUR7ygKXJ8OFLJ +6ifFPdCBSj64eHlLibhObRskFb0CAwEAAaOBwDCBvTAzBgNVHR8ELDAqMCigJqAk +hiJodHRwOi8vMTI3LjAuMC4xOjgwODEvcGtpL3Rlc3QuY3JsMAwGA1UdEwQFMAMB +Af8wHQYDVR0OBBYEFP2CRTmhkUHyZswNddUNQNWBp6FDMEwGA1UdIwRFMEOAFMXM +9aGM2eSnuuwh9dGEI+oNwscwoRWkEzARMQ8wDQYDVQQDDAZUZXN0Q0GCFDPnBIcJ +Moch2c18qkxauyxse1QoMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA +lqD/iku9RZbJcjxj40jEq+9+23Y/2QKeacjZNlXh9ZvJadhpAqxQjGCULC65qGWs +9QCwi5YlC4rvlCFX4gTCw4a/Bk6RXOa8GwMxi2TqxXnDXJTlqmd+dBIHFP3NMgIm +JskK7dTa7iqE4/Fgswl3J6E8rOxhGDC1bR8WCiQazxwbYKVg5SyLzzeDDBXneTA/ +7lBFfEvGLM0sgQqY8WVEesoqIBreGdlLyqHipLUUR7+0aBUDwFXl9EcOVZ/+hdgs +fdAalhG5aLd0HmGUwa6HUi3GJrpR7fGRwOZM+K0CI3VR/PhpBezPMVBaQXjrPSdN +m2jvug66On1gAJ1TpQg9xg== +-----END CERTIFICATE----- diff --git a/openssl/test/test.crl b/openssl/test/test.crl new file mode 100644 index 0000000000..aead062c4d Binary files /dev/null and b/openssl/test/test.crl differ diff --git a/systest/build.rs b/systest/build.rs index e54438114b..6d3ac3a3d3 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + use std::env; #[allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] @@ -54,6 +56,7 @@ fn main() { .header("openssl/bio.h") .header("openssl/x509v3.h") .header("openssl/safestack.h") + .header("openssl/cmac.h") .header("openssl/hmac.h") .header("openssl/obj_mac.h") .header("openssl/ssl.h") @@ -108,7 +111,11 @@ fn main() { || s.starts_with("CRYPTO_EX_") }); cfg.skip_struct(|s| { - s == "ProbeResult" || s == "X509_OBJECT_data" // inline union + s == "ProbeResult" || + s == "X509_OBJECT_data" || // inline union + s == "DIST_POINT_NAME_st_anon_union" || // inline union + s == "PKCS7_data" || + s == "ASN1_TYPE_value" }); cfg.skip_fn(move |s| { s == "CRYPTO_memcmp" || // uses volatile @@ -128,7 +135,10 @@ fn main() { cfg.skip_field_type(|s, field| { (s == "EVP_PKEY" && field == "pkey") || // union (s == "GENERAL_NAME" && field == "d") || // union - (s == "X509_OBJECT" && field == "data") // union + (s == "DIST_POINT_NAME" && field == "name") || // union + (s == "X509_OBJECT" && field == "data") || // union + (s == "PKCS7" && field == "d") || // union + (s == "ASN1_TYPE" && field == "value") // union }); cfg.skip_signededness(|s| { s.ends_with("_cb")