From 4cb7e260a85b7157f14790444f49fcceca085447 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Thu, 25 Sep 2025 09:51:52 +0100 Subject: [PATCH] Clean-up legacy FIPS options Per BoringSSL's FIPS policy, its `main` branch is the "update branch" for FedRAMP compliance's purposes. This means that we can stop using a specific BoringSSL branch when enabling FIPS, as well as a number of hacks that allowed us to build more recent BoringSSL versions with an older pre-compiled FIPS modules. This also required slightly updating the main BoringSSL submodule, as the previous version had an issue when building with the FIPS option enabled. This is turn required some changes to the PQ patch as well as some APIs that don't seem to be exposed publicly, as well as changing some paths in the other patches. In order to allow a smooth upgrade of internal projects, the `fips-compat` feature is reduced in scope and renamed to `legacy-compat-deprecated` so that we can incrementally upgrade internal BoringSSL forks. In practice this shouldn't really be something anyone else would need, since in order to work it requires a specific mix of BoringSSL version and backported patches. --- .github/workflows/ci.yml | 16 +- .gitmodules | 3 - boring-sys/Cargo.toml | 41 +- boring-sys/build/config.rs | 24 +- boring-sys/build/main.rs | 120 +- boring-sys/deps/boringssl | 2 +- boring-sys/deps/boringssl-fips | 1 - boring-sys/patches/boring-pq.patch | 3178 ++++++++--------- boring-sys/patches/rpk.patch | 102 +- boring-sys/patches/underscore-wildcards.patch | 45 +- boring/Cargo.toml | 24 +- boring/src/bio.rs | 4 +- boring/src/fips.rs | 12 +- boring/src/lib.rs | 1 - boring/src/ssl/mod.rs | 115 +- boring/src/ssl/test/mod.rs | 4 - boring/src/x509/mod.rs | 4 +- boring/src/x509/tests/trusted_first.rs | 4 +- hyper-boring/Cargo.toml | 15 +- tokio-boring/Cargo.toml | 13 - 20 files changed, 1572 insertions(+), 2156 deletions(-) delete mode 160000 boring-sys/deps/boringssl-fips diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 110d8ba7..8ee8b46c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -202,6 +202,10 @@ jobs: run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} shell: bash - run: rustup target add ${{ matrix.target }} + - name: Install golang + uses: actions/setup-go@v5 + with: + go-version: '>=1.22.0' - name: Install target-specific APT dependencies if: "matrix.apt_packages != ''" run: sudo apt update && sudo apt install -y ${{ matrix.apt_packages }} @@ -255,18 +259,10 @@ jobs: - name: Install Rust (rustup) run: rustup update stable --no-self-update && rustup default stable shell: bash - - name: Install Clang-12 - uses: KyleMayes/install-llvm-action@v1 - with: - version: "12.0.0" - directory: ${{ runner.temp }}/llvm - name: Install golang uses: actions/setup-go@v5 with: go-version: '>=1.22.0' - - name: Add clang++-12 link - working-directory: ${{ runner.temp }}/llvm/bin - run: ln -s clang clang++-12 - name: Run tests run: cargo test --features fips - name: Test boring-sys cargo publish (FIPS) @@ -296,6 +292,10 @@ jobs: - name: Install Rust (rustup) run: rustup update stable --no-self-update && rustup default stable && rustup target add ${{ matrix.target }} shell: bash + - name: Install golang + uses: actions/setup-go@v5 + with: + go-version: '>=1.22.0' - name: Install ${{ matrix.target }} toolchain run: brew tap messense/macos-cross-toolchains && brew install ${{ matrix.target }} - name: Set BORING_BSSL_SYSROOT diff --git a/.gitmodules b/.gitmodules index 93bfb089..c1e5a527 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,3 @@ path = boring-sys/deps/boringssl url = https://github.com/google/boringssl.git ignore = dirty -[submodule "boring-sys/deps/boringssl-fips"] - path = boring-sys/deps/boringssl-fips - url = https://github.com/google/boringssl.git diff --git a/boring-sys/Cargo.toml b/boring-sys/Cargo.toml index 166d62f5..86ff731c 100644 --- a/boring-sys/Cargo.toml +++ b/boring-sys/Cargo.toml @@ -19,35 +19,22 @@ include = [ "/*.toml", "/LICENSE-MIT", "/cmake/*.cmake", - # boringssl (non-FIPS) - "/deps/boringssl/src/util/32-bit-toolchain.cmake", "/deps/boringssl/**/*.[chS]", "/deps/boringssl/**/*.asm", - "/deps/boringssl/sources.json", - "/deps/boringssl/src/crypto/obj/obj_mac.num", - "/deps/boringssl/src/crypto/obj/objects.txt", + "/deps/boringssl/**/*.pl", + "/deps/boringssl/**/*.go", + "/deps/boringssl/**/*.cmake", + "/deps/boringssl/**/go.mod", + "/deps/boringssl/**/go.sum", + "/deps/boringssl/crypto/obj/obj_mac.num", + "/deps/boringssl/crypto/obj/objects.txt", + "/deps/boringssl/crypto/err/*.errordata", "/deps/boringssl/**/*.bzl", - "/deps/boringssl/src/**/*.cc", + "/deps/boringssl/**/*.cc", "/deps/boringssl/**/CMakeLists.txt", "/deps/boringssl/**/sources.cmake", + "/deps/boringssl/**/util/go_tests.txt", "/deps/boringssl/LICENSE", - # boringssl (FIPS) - "/deps/boringssl-fips/src/util/32-bit-toolchain.cmake", - "/deps/boringssl-fips/**/*.[chS]", - "/deps/boringssl-fips/**/*.asm", - "/deps/boringssl-fips/**/*.pl", - "/deps/boringssl-fips/**/*.go", - "/deps/boringssl-fips/**/go.mod", - "/deps/boringssl-fips/**/go.sum", - "/deps/boringssl-fips/sources.json", - "/deps/boringssl-fips/crypto/obj/obj_mac.num", - "/deps/boringssl-fips/crypto/obj/objects.txt", - "/deps/boringssl-fips/crypto/err/*.errordata", - "/deps/boringssl-fips/**/*.bzl", - "/deps/boringssl-fips/**/*.cc", - "/deps/boringssl-fips/**/CMakeLists.txt", - "/deps/boringssl-fips/**/sources.cmake", - "/deps/boringssl-fips/LICENSE", "/build/*", "/src", "/patches", @@ -66,14 +53,6 @@ rustdoc-args = ["--cfg", "docsrs"] # for instructions and more details on the boringssl FIPS flag. fips = [] -# Use a precompiled FIPS-validated version of BoringSSL. Meant to be used with -# FIPS-20230428 or newer. Users must set `BORING_BSSL_FIPS_PATH` to use this -# feature, or else the build will fail. -fips-precompiled = [] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = [] - # Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250) rpk = [] diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index 5d93eda4..f586b968 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -16,8 +16,6 @@ pub(crate) struct Config { pub(crate) struct Features { pub(crate) fips: bool, - pub(crate) fips_precompiled: bool, - pub(crate) fips_link_precompiled: bool, pub(crate) pq_experimental: bool, pub(crate) rpk: bool, pub(crate) underscore_wildcards: bool, @@ -27,7 +25,6 @@ pub(crate) struct Env { pub(crate) path: Option, pub(crate) include_path: Option, pub(crate) source_path: Option, - pub(crate) precompiled_bcm_o: Option, pub(crate) assume_patched: bool, pub(crate) sysroot: Option, pub(crate) compiler_external_toolchain: Option, @@ -81,10 +78,6 @@ impl Config { panic!("`fips` and `rpk` features are mutually exclusive"); } - if self.features.fips_precompiled && self.features.rpk { - panic!("`fips-precompiled` and `rpk` features are mutually exclusive"); - } - let is_precompiled_native_lib = self.env.path.is_some(); let is_external_native_lib_source = !is_precompiled_native_lib && self.env.source_path.is_none(); @@ -107,32 +100,18 @@ impl Config { "cargo:warning=precompiled BoringSSL was provided, so patches will be ignored" ); } - - // todo(rmehra): should this even be a restriction? why not let people link a custom bcm.o? - // precompiled boringssl will include libcrypto.a - if is_precompiled_native_lib && self.features.fips_link_precompiled { - panic!("precompiled BoringSSL was provided, so FIPS configuration can't be applied"); - } - - if !is_precompiled_native_lib && self.features.fips_precompiled { - panic!("`fips-precompiled` feature requires `BORING_BSSL_FIPS_PATH` to be set"); - } } } impl Features { fn from_env() -> Self { let fips = env::var_os("CARGO_FEATURE_FIPS").is_some(); - let fips_precompiled = env::var_os("CARGO_FEATURE_FIPS_PRECOMPILED").is_some(); - let fips_link_precompiled = env::var_os("CARGO_FEATURE_FIPS_LINK_PRECOMPILED").is_some(); let pq_experimental = env::var_os("CARGO_FEATURE_PQ_EXPERIMENTAL").is_some(); let rpk = env::var_os("CARGO_FEATURE_RPK").is_some(); let underscore_wildcards = env::var_os("CARGO_FEATURE_UNDERSCORE_WILDCARDS").is_some(); Self { fips, - fips_precompiled, - fips_link_precompiled, pq_experimental, rpk, underscore_wildcards, @@ -140,7 +119,7 @@ impl Features { } pub(crate) fn is_fips_like(&self) -> bool { - self.fips || self.fips_precompiled || self.fips_link_precompiled + self.fips } } @@ -175,7 +154,6 @@ impl Env { path: boringssl_var("BORING_BSSL_PATH").map(PathBuf::from), include_path: boringssl_var("BORING_BSSL_INCLUDE_PATH").map(PathBuf::from), source_path: boringssl_var("BORING_BSSL_SOURCE_PATH").map(PathBuf::from), - precompiled_bcm_o: boringssl_var("BORING_BSSL_PRECOMPILED_BCM_O").map(PathBuf::from), assume_patched: boringssl_var("BORING_BSSL_ASSUME_PATCHED") .is_some_and(|v| !v.is_empty()), sysroot: boringssl_var("BORING_BSSL_SYSROOT").map(PathBuf::from), diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index be9a3fa1..c95f1cd4 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -50,6 +50,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[ &[ ("CMAKE_OSX_ARCHITECTURES", "arm64"), ("CMAKE_OSX_SYSROOT", "iphoneos"), + ("CMAKE_MACOSX_BUNDLE", "OFF"), ], ), ( @@ -57,6 +58,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[ &[ ("CMAKE_OSX_ARCHITECTURES", "arm64"), ("CMAKE_OSX_SYSROOT", "iphonesimulator"), + ("CMAKE_MACOSX_BUNDLE", "OFF"), ], ), ( @@ -64,6 +66,7 @@ const CMAKE_PARAMS_APPLE: &[(&str, &[(&str, &str)])] = &[ &[ ("CMAKE_OSX_ARCHITECTURES", "x86_64"), ("CMAKE_OSX_SYSROOT", "iphonesimulator"), + ("CMAKE_MACOSX_BUNDLE", "OFF"), ], ), // macOS @@ -114,11 +117,7 @@ fn get_boringssl_source_path(config: &Config) -> &PathBuf { static SOURCE_PATH: OnceLock = OnceLock::new(); SOURCE_PATH.get_or_init(|| { - let submodule_dir = if config.features.fips { - "boringssl-fips" - } else { - "boringssl" - }; + let submodule_dir = "boringssl"; let src_path = config.out_dir.join(submodule_dir); @@ -304,7 +303,7 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { config .manifest_dir .join(src_path) - .join("src/util/32-bit-toolchain.cmake") + .join("util/32-bit-toolchain.cmake") .as_os_str(), ); } @@ -340,55 +339,6 @@ fn get_boringssl_cmake_config(config: &Config) -> cmake::Config { boringssl_cmake } -/// Verify that the toolchains match -/// See "Installation Instructions" under section 12.1. -// TODO: maybe this should also verify the Go and Ninja versions? But those haven't been an issue in practice ... -fn verify_fips_clang_version() -> (&'static str, &'static str) { - fn version(tool: &str) -> Option { - let output = match Command::new(tool).arg("--version").output() { - Ok(o) => o, - Err(e) => { - println!("cargo:warning=missing {tool}, trying other compilers: {e}"); - // NOTE: hard-codes that the loop below checks the version - return None; - } - }; - if !output.status.success() { - return Some(String::new()); - } - let output = std::str::from_utf8(&output.stdout).expect("invalid utf8 output"); - Some(output.lines().next().expect("empty output").to_string()) - } - - const REQUIRED_CLANG_VERSION: &str = "12.0.0"; - for (cc, cxx) in [ - ("clang-12", "clang++-12"), - ("clang", "clang++"), - ("cc", "c++"), - ] { - let (Some(cc_version), Some(cxx_version)) = (version(cc), version(cxx)) else { - continue; - }; - - if cc_version.contains(REQUIRED_CLANG_VERSION) { - assert!( - cxx_version.contains(REQUIRED_CLANG_VERSION), - "mismatched versions of cc and c++" - ); - return (cc, cxx); - } else if cc == "cc" { - panic!( - "unsupported clang version \"{cc_version}\": FIPS requires clang {REQUIRED_CLANG_VERSION}" - ); - } else if !cc_version.is_empty() { - println!( - "cargo:warning=FIPS requires clang version {REQUIRED_CLANG_VERSION}, skipping incompatible version \"{cc_version}\"" - ); - } - } - unreachable!() -} - fn pick_best_android_ndk_toolchain(toolchains_dir: &Path) -> std::io::Result { let toolchains = std::fs::read_dir(toolchains_dir)?.collect::, _>>()?; // First look for one of the toolchains that Google has documented. @@ -591,66 +541,17 @@ fn built_boring_source_path(config: &Config) -> &PathBuf { } if config.features.fips { - let (clang, clangxx) = verify_fips_clang_version(); - cfg.define("CMAKE_C_COMPILER", clang) - .define("CMAKE_CXX_COMPILER", clangxx) - .define("CMAKE_ASM_COMPILER", clang) + cfg.define("CMAKE_C_COMPILER", "clang") + .define("CMAKE_CXX_COMPILER", "clang++") + .define("CMAKE_ASM_COMPILER", "clang") .define("FIPS", "1"); } - if config.features.fips_link_precompiled { - cfg.define("FIPS", "1"); - } - cfg.build_target("ssl").build(); cfg.build_target("crypto").build() }) } -fn link_in_precompiled_bcm_o(config: &Config) { - println!("cargo:warning=linking in precompiled `bcm.o` module"); - - let bssl_dir = built_boring_source_path(config); - let bcm_o_src_path = config.env.precompiled_bcm_o.as_ref() - .expect("`fips-link-precompiled` requires `BORING_BSSL_FIPS_PRECOMPILED_BCM_O` env variable to be specified"); - - let libcrypto_path = bssl_dir - .join("build/crypto/libcrypto.a") - .canonicalize() - .unwrap(); - - let bcm_o_dst_path = bssl_dir.join("build/bcm-fips.o"); - - fs::copy(bcm_o_src_path, &bcm_o_dst_path).unwrap(); - - // check that fips module is named as expected - let out = run_command( - Command::new("ar") - .arg("t") - .arg(&libcrypto_path) - .arg("bcm.o"), - ) - .unwrap(); - - assert_eq!( - String::from_utf8(out.stdout).unwrap().trim(), - "bcm.o", - "failed to verify FIPS module name" - ); - - // insert fips bcm.o before bcm.o into libcrypto.a, - // so for all duplicate symbols the older fips bcm.o is used - // (this causes the need for extra linker flags to deal with duplicate symbols) - // (as long as the newer module does not define new symbols, one may also remove it, - // but once there are new symbols it would cause missing symbols at linking stage) - run_command( - Command::new("ar") - .args(["rb", "bcm.o"]) - .args([&libcrypto_path, &bcm_o_dst_path]), - ) - .unwrap(); -} - fn get_cpp_runtime_lib(config: &Config) -> Option { if let Some(ref cpp_lib) = config.env.cpp_runtime_lib { return cpp_lib.clone().into_string().ok(); @@ -709,10 +610,6 @@ fn emit_link_directives(config: &Config) { ); } - if config.features.fips_link_precompiled { - link_in_precompiled_bcm_o(config); - } - if let Some(cpp_lib) = get_cpp_runtime_lib(config) { println!("cargo:rustc-link-lib={cpp_lib}"); } @@ -785,7 +682,6 @@ fn generate_bindings(config: &Config) { "des.h", "dtls1.h", "hkdf.h", - #[cfg(not(feature = "fips"))] "hpke.h", "hmac.h", "hrss.h", diff --git a/boring-sys/deps/boringssl b/boring-sys/deps/boringssl index 44b3df6f..478b28ab 160000 --- a/boring-sys/deps/boringssl +++ b/boring-sys/deps/boringssl @@ -1 +1 @@ -Subproject commit 44b3df6f03d85c901767250329c571db405122d5 +Subproject commit 478b28ab12f2001a03261624261fd041f5439706 diff --git a/boring-sys/deps/boringssl-fips b/boring-sys/deps/boringssl-fips deleted file mode 160000 index 853ca1ea..00000000 --- a/boring-sys/deps/boringssl-fips +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 853ca1ea1168dff08011e5d42d94609cc0ca2e27 diff --git a/boring-sys/patches/boring-pq.patch b/boring-sys/patches/boring-pq.patch index 38488004..fb5df8b9 100644 --- a/boring-sys/patches/boring-pq.patch +++ b/boring-sys/patches/boring-pq.patch @@ -66,141 +66,26 @@ Cf RTG-2076 RTG-2051 RTG-2508 RTG-2707 RTG-2607 RTG-3239 delete mode 100644 src/crypto/kyber/kyber_test.cc delete mode 100644 src/crypto/kyber/kyber_tests.txt -diff --git a/BUILD.generated.bzl b/BUILD.generated.bzl -index 738e1055f..9466757a2 100644 ---- a/BUILD.generated.bzl -+++ b/BUILD.generated.bzl -@@ -253,7 +253,6 @@ crypto_internal_headers = [ - "src/crypto/fipsmodule/tls/internal.h", - "src/crypto/hrss/internal.h", - "src/crypto/internal.h", -- "src/crypto/kyber/internal.h", - "src/crypto/lhash/internal.h", - "src/crypto/obj/obj_dat.h", - "src/crypto/pkcs7/internal.h", -@@ -382,8 +381,8 @@ crypto_sources = [ - "src/crypto/fipsmodule/fips_shared_support.c", - "src/crypto/hpke/hpke.c", - "src/crypto/hrss/hrss.c", -- "src/crypto/kyber/keccak.c", -- "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/kyber512.c", -+ "src/crypto/kyber/kyber768.c", - "src/crypto/lhash/lhash.c", - "src/crypto/mem.c", - "src/crypto/obj/obj.c", -diff --git a/BUILD.generated_tests.bzl b/BUILD.generated_tests.bzl -index 92dec1e01..8f70dedc0 100644 ---- a/BUILD.generated_tests.bzl -+++ b/BUILD.generated_tests.bzl -@@ -40,7 +40,6 @@ test_support_sources = [ - "src/crypto/fipsmodule/tls/internal.h", - "src/crypto/hrss/internal.h", - "src/crypto/internal.h", -- "src/crypto/kyber/internal.h", - "src/crypto/lhash/internal.h", - "src/crypto/obj/obj_dat.h", - "src/crypto/pkcs7/internal.h", -@@ -124,7 +123,6 @@ crypto_test_sources = [ - "src/crypto/hpke/hpke_test.cc", - "src/crypto/hrss/hrss_test.cc", - "src/crypto/impl_dispatch_test.cc", -- "src/crypto/kyber/kyber_test.cc", - "src/crypto/lhash/lhash_test.cc", - "src/crypto/obj/obj_test.cc", - "src/crypto/pem/pem_test.cc", -@@ -218,8 +216,6 @@ crypto_test_data = [ - "src/crypto/fipsmodule/rand/ctrdrbg_vectors.txt", - "src/crypto/hmac_extra/hmac_tests.txt", - "src/crypto/hpke/hpke_test_vectors.txt", -- "src/crypto/kyber/keccak_tests.txt", -- "src/crypto/kyber/kyber_tests.txt", - "src/crypto/pkcs8/test/empty_password.p12", - "src/crypto/pkcs8/test/no_encryption.p12", - "src/crypto/pkcs8/test/nss.p12", -diff --git a/CMakeLists.txt b/CMakeLists.txt -index faed2befa..931c0e3a8 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -375,8 +375,8 @@ add_library( - src/crypto/fipsmodule/fips_shared_support.c - src/crypto/hpke/hpke.c - src/crypto/hrss/hrss.c -- src/crypto/kyber/keccak.c -- src/crypto/kyber/kyber.c -+ src/crypto/kyber/kyber512.c -+ src/crypto/kyber/kyber768.c - src/crypto/lhash/lhash.c - src/crypto/mem.c - src/crypto/obj/obj.c -diff --git a/sources.json b/sources.json -index 4c0048e1d..f6ea5c40f 100644 ---- a/sources.json -+++ b/sources.json -@@ -111,8 +111,8 @@ - "src/crypto/fipsmodule/fips_shared_support.c", - "src/crypto/hpke/hpke.c", - "src/crypto/hrss/hrss.c", -- "src/crypto/kyber/keccak.c", -- "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/kyber512.c", -+ "src/crypto/kyber/kyber768.c", - "src/crypto/lhash/lhash.c", - "src/crypto/mem.c", - "src/crypto/obj/obj.c", -@@ -549,7 +549,6 @@ - "src/crypto/hpke/hpke_test.cc", - "src/crypto/hrss/hrss_test.cc", - "src/crypto/impl_dispatch_test.cc", -- "src/crypto/kyber/kyber_test.cc", - "src/crypto/lhash/lhash_test.cc", - "src/crypto/obj/obj_test.cc", - "src/crypto/pem/pem_test.cc", -@@ -634,8 +633,6 @@ - "src/crypto/fipsmodule/rand/ctrdrbg_vectors.txt", - "src/crypto/hmac_extra/hmac_tests.txt", - "src/crypto/hpke/hpke_test_vectors.txt", -- "src/crypto/kyber/keccak_tests.txt", -- "src/crypto/kyber/kyber_tests.txt", - "src/crypto/pkcs8/test/empty_password.p12", - "src/crypto/pkcs8/test/no_encryption.p12", - "src/crypto/pkcs8/test/nss.p12", -@@ -1060,4 +1057,4 @@ - "urandom_test": [ - "src/crypto/fipsmodule/rand/urandom_test.cc" - ] --} -\ No newline at end of file -+} -diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt -index cdb5ddca1..2052fa791 100644 ---- a/src/crypto/CMakeLists.txt -+++ b/src/crypto/CMakeLists.txt -@@ -170,8 +170,8 @@ add_library( - ex_data.c +diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt +index a594b9e9d..ed468237f 100644 +--- a/crypto/CMakeLists.txt ++++ b/crypto/CMakeLists.txt +@@ -176,7 +176,8 @@ add_library( hpke/hpke.c hrss/hrss.c -- kyber/keccak.c + keccak/keccak.c - kyber/kyber.c + kyber/kyber512.c + kyber/kyber768.c lhash/lhash.c mem.c obj/obj.c -@@ -400,7 +400,6 @@ add_executable( - hmac_extra/hmac_test.cc - hrss/hrss_test.cc - impl_dispatch_test.cc -- kyber/kyber_test.cc - lhash/lhash_test.cc - obj/obj_test.cc - pem/pem_test.cc -diff --git a/src/crypto/kyber/internal.h b/src/crypto/kyber/internal.h +diff --git a/crypto/kyber/internal.h b/crypto/kyber/internal.h deleted file mode 100644 -index b3bfa86b8..000000000 ---- a/src/crypto/kyber/internal.h +index b11211726..000000000 +--- a/crypto/kyber/internal.h +++ /dev/null -@@ -1,91 +0,0 @@ +@@ -1,60 +0,0 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -235,37 +120,6 @@ index b3bfa86b8..000000000 -// necessary to generate a key. -#define KYBER_GENERATE_KEY_ENTROPY 64 - --struct BORINGSSL_keccak_st { -- uint64_t state[25]; -- size_t rate_bytes; -- size_t offset; --}; -- --enum boringssl_keccak_config_t { -- boringssl_sha3_256, -- boringssl_sha3_512, -- boringssl_shake128, -- boringssl_shake256, --}; -- --// BORINGSSL_keccak hashes |in_len| bytes from |in| and writes |out_len| bytes --// of output to |out|. If the |config| specifies a fixed-output function, like --// SHA3-256, then |out_len| must be the correct length for that function. --OPENSSL_EXPORT void BORINGSSL_keccak(uint8_t *out, size_t out_len, -- const uint8_t *in, size_t in_len, -- enum boringssl_keccak_config_t config); -- --// BORINGSSL_keccak_init absorbs |in_len| bytes from |in| and sets up |ctx| for --// squeezing. The |config| must specify a SHAKE variant, otherwise callers --// should use |BORINGSSL_keccak|. --OPENSSL_EXPORT void BORINGSSL_keccak_init( -- struct BORINGSSL_keccak_st *ctx, const uint8_t *in, size_t in_len, -- enum boringssl_keccak_config_t config); -- --// BORINGSSL_keccak_squeeze writes |out_len| bytes to |out| from |ctx|. --OPENSSL_EXPORT void BORINGSSL_keccak_squeeze(struct BORINGSSL_keccak_st *ctx, -- uint8_t *out, size_t out_len); -- -// KYBER_generate_key_external_entropy is a deterministic function to create a -// pair of Kyber768 keys, using the supplied entropy. The entropy needs to be -// uniformly random generated. This function is should only be used for tests, @@ -292,221 +146,11 @@ index b3bfa86b8..000000000 -#endif - -#endif // OPENSSL_HEADER_CRYPTO_KYBER_INTERNAL_H -diff --git a/src/crypto/kyber/keccak.c b/src/crypto/kyber/keccak.c -deleted file mode 100644 -index f1c012d11..000000000 ---- a/src/crypto/kyber/keccak.c -+++ /dev/null -@@ -1,204 +0,0 @@ --/* Copyright (c) 2023, Google Inc. -- * -- * Permission to use, copy, modify, and/or distribute this software for any -- * purpose with or without fee is hereby granted, provided that the above -- * copyright notice and this permission notice appear in all copies. -- * -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -- --#include -- --#include --#include -- --#include "../internal.h" --#include "./internal.h" -- -- --// keccak_f implements the Keccak-1600 permutation as described at --// https://keccak.team/keccak_specs_summary.html. Each lane is represented as a --// 64-bit value and the 5×5 lanes are stored as an array in row-major order. --static void keccak_f(uint64_t state[25]) { -- static const int kNumRounds = 24; -- for (int round = 0; round < kNumRounds; round++) { -- // θ step -- uint64_t c[5]; -- for (int x = 0; x < 5; x++) { -- c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ -- state[x + 20]; -- } -- -- for (int x = 0; x < 5; x++) { -- const uint64_t d = c[(x + 4) % 5] ^ CRYPTO_rotl_u64(c[(x + 1) % 5], 1); -- for (int y = 0; y < 5; y++) { -- state[y * 5 + x] ^= d; -- } -- } -- -- // ρ and π steps. -- // -- // These steps involve a mapping of the state matrix. Each input point, -- // (x,y), is rotated and written to the point (y, 2x + 3y). In the Keccak -- // pseudo-code a separate array is used because an in-place operation would -- // overwrite some values that are subsequently needed. However, the mapping -- // forms a trail through 24 of the 25 values so we can do it in place with -- // only a single temporary variable. -- // -- // Start with (1, 0). The value here will be mapped and end up at (0, 2). -- // That value will end up at (2, 1), then (1, 2), and so on. After 24 -- // steps, 24 of the 25 values have been hit (as this mapping is injective) -- // and the sequence will repeat. All that remains is to handle the element -- // at (0, 0), but the rotation for that element is zero, and it goes to (0, -- // 0), so we can ignore it. -- static const uint8_t kIndexes[24] = {10, 7, 11, 17, 18, 3, 5, 16, -- 8, 21, 24, 4, 15, 23, 19, 13, -- 12, 2, 20, 14, 22, 9, 6, 1}; -- static const uint8_t kRotations[24] = {1, 3, 6, 10, 15, 21, 28, 36, -- 45, 55, 2, 14, 27, 41, 56, 8, -- 25, 43, 62, 18, 39, 61, 20, 44}; -- uint64_t prev_value = state[1]; -- for (int i = 0; i < 24; i++) { -- const uint64_t value = CRYPTO_rotl_u64(prev_value, kRotations[i]); -- const size_t index = kIndexes[i]; -- prev_value = state[index]; -- state[index] = value; -- } -- -- // χ step -- for (int y = 0; y < 5; y++) { -- const int row_index = 5 * y; -- const uint64_t orig_x0 = state[row_index]; -- const uint64_t orig_x1 = state[row_index + 1]; -- state[row_index] ^= ~orig_x1 & state[row_index + 2]; -- state[row_index + 1] ^= ~state[row_index + 2] & state[row_index + 3]; -- state[row_index + 2] ^= ~state[row_index + 3] & state[row_index + 4]; -- state[row_index + 3] ^= ~state[row_index + 4] & orig_x0; -- state[row_index + 4] ^= ~orig_x0 & orig_x1; -- } -- -- // ι step -- // -- // From https://keccak.team/files/Keccak-reference-3.0.pdf, section -- // 1.2, the round constants are based on the output of a LFSR. Thus, as -- // suggested in the appendix of of -- // https://keccak.team/keccak_specs_summary.html, the values are -- // simply encoded here. -- static const uint64_t kRoundConstants[24] = { -- 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, -- 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, -- 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, -- 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, -- 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, -- 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, -- 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, -- 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, -- }; -- -- state[0] ^= kRoundConstants[round]; -- } --} -- --static void keccak_init(struct BORINGSSL_keccak_st *ctx, -- size_t *out_required_out_len, const uint8_t *in, -- size_t in_len, enum boringssl_keccak_config_t config) { -- size_t capacity_bytes; -- uint8_t terminator; -- switch (config) { -- case boringssl_sha3_256: -- capacity_bytes = 512 / 8; -- *out_required_out_len = 32; -- terminator = 0x06; -- break; -- case boringssl_sha3_512: -- capacity_bytes = 1024 / 8; -- *out_required_out_len = 64; -- terminator = 0x06; -- break; -- case boringssl_shake128: -- capacity_bytes = 256 / 8; -- *out_required_out_len = 0; -- terminator = 0x1f; -- break; -- case boringssl_shake256: -- capacity_bytes = 512 / 8; -- *out_required_out_len = 0; -- terminator = 0x1f; -- break; -- default: -- abort(); -- } -- -- OPENSSL_memset(ctx, 0, sizeof(*ctx)); -- ctx->rate_bytes = 200 - capacity_bytes; -- assert(ctx->rate_bytes % 8 == 0); -- const size_t rate_words = ctx->rate_bytes / 8; -- -- while (in_len >= ctx->rate_bytes) { -- for (size_t i = 0; i < rate_words; i++) { -- ctx->state[i] ^= CRYPTO_load_u64_le(in + 8 * i); -- } -- keccak_f(ctx->state); -- in += ctx->rate_bytes; -- in_len -= ctx->rate_bytes; -- } -- -- // XOR the final block. Accessing |ctx->state| as a |uint8_t*| is allowed by -- // strict aliasing because we require |uint8_t| to be a character type. -- uint8_t *state_bytes = (uint8_t *)ctx->state; -- assert(in_len < ctx->rate_bytes); -- for (size_t i = 0; i < in_len; i++) { -- state_bytes[i] ^= in[i]; -- } -- state_bytes[in_len] ^= terminator; -- state_bytes[ctx->rate_bytes - 1] ^= 0x80; -- keccak_f(ctx->state); --} -- --void BORINGSSL_keccak(uint8_t *out, size_t out_len, const uint8_t *in, -- size_t in_len, enum boringssl_keccak_config_t config) { -- struct BORINGSSL_keccak_st ctx; -- size_t required_out_len; -- keccak_init(&ctx, &required_out_len, in, in_len, config); -- if (required_out_len != 0 && out_len != required_out_len) { -- abort(); -- } -- BORINGSSL_keccak_squeeze(&ctx, out, out_len); --} -- --void BORINGSSL_keccak_init(struct BORINGSSL_keccak_st *ctx, const uint8_t *in, -- size_t in_len, -- enum boringssl_keccak_config_t config) { -- size_t required_out_len; -- keccak_init(ctx, &required_out_len, in, in_len, config); -- if (required_out_len != 0) { -- abort(); -- } --} -- --void BORINGSSL_keccak_squeeze(struct BORINGSSL_keccak_st *ctx, uint8_t *out, -- size_t out_len) { -- // Accessing |ctx->state| as a |uint8_t*| is allowed by strict aliasing -- // because we require |uint8_t| to be a character type. -- const uint8_t *state_bytes = (const uint8_t *)ctx->state; -- while (out_len) { -- size_t remaining = ctx->rate_bytes - ctx->offset; -- size_t todo = out_len; -- if (todo > remaining) { -- todo = remaining; -- } -- OPENSSL_memcpy(out, &state_bytes[ctx->offset], todo); -- out += todo; -- out_len -= todo; -- ctx->offset += todo; -- if (ctx->offset == ctx->rate_bytes) { -- keccak_f(ctx->state); -- ctx->offset = 0; -- } -- } --} -diff --git a/src/crypto/kyber/kyber.c b/src/crypto/kyber/kyber.c -index 776c085f9..ccb5b3d9b 100644 ---- a/src/crypto/kyber/kyber.c -+++ b/src/crypto/kyber/kyber.c -@@ -1,833 +1,2426 @@ +diff --git a/crypto/kyber/kyber.c b/crypto/kyber/kyber.c +index d3ea02090..ccb5b3d9b 100644 +--- a/crypto/kyber/kyber.c ++++ b/crypto/kyber/kyber.c +@@ -1,835 +1,2426 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -547,17 +191,17 @@ index 776c085f9..ccb5b3d9b 100644 +// implementation or https://github.com/cloudflare/circl/tree/main/pke/kyber +// +// - Option to keep A stored in private key. - --#include ++ +#ifndef KYBER_K +#error "Don't compile this file direcly" +#endif --#include --#include -+#include + #include +#include +-#include +-#include +- -#include -#include +#include @@ -565,9 +209,29 @@ index 776c085f9..ccb5b3d9b 100644 +#include #include "../internal.h" +-#include "../keccak/internal.h" -#include "./internal.h" -- -- ++ ++#if (KYBER_K == 2) ++#define KYBER_NAMESPACE(s) KYBER512_##s ++#elif (KYBER_K == 3) ++#define KYBER_NAMESPACE(s) KYBER768_##s ++#elif (KYBER_K == 4) ++#define KYBER_NAMESPACE(s) KYBER1024_##s ++#else ++#error "KYBER_K must be in {2,3,4}" ++#endif ++ ++#define public_key KYBER_NAMESPACE(public_key) ++#define private_key KYBER_NAMESPACE(private_key) ++ ++#define generate_key KYBER_NAMESPACE(generate_key) ++#define encap KYBER_NAMESPACE(encap) ++#define decap KYBER_NAMESPACE(decap) ++#define marshal_public_key KYBER_NAMESPACE(marshal_public_key) ++#define parse_public_key KYBER_NAMESPACE(parse_public_key) + + -// See -// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf - @@ -602,9 +266,10 @@ index 776c085f9..ccb5b3d9b 100644 -} matrix; - -// This bit of Python will be referenced in some of the following comments: --// + // -// p = 3329 --// ++// params.h + // -// def bitreverse(i): -// ret = 0 -// for n in range(7): @@ -613,7 +278,9 @@ index 776c085f9..ccb5b3d9b 100644 -// ret |= bit -// i >>= 1 -// return ret -- ++#define KYBER_N 256 ++#define KYBER_Q 3329 + -// kNTTRoots = [pow(17, bitreverse(i), p) for i in range(128)] -static const uint16_t kNTTRoots[128] = { - 1, 1729, 2580, 3289, 2642, 630, 1897, 848, 1062, 1919, 193, 797, @@ -627,110 +294,6 @@ index 776c085f9..ccb5b3d9b 100644 - 1584, 2298, 2037, 3220, 375, 2549, 2090, 1645, 1063, 319, 2773, 757, - 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, - 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154, --}; - --// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)] --static const uint16_t kInverseNTTRoots[128] = { -- 1, 1600, 40, 749, 2481, 1432, 2699, 687, 1583, 2760, 69, 543, -- 2532, 3136, 1410, 2267, 2508, 1355, 450, 936, 447, 2794, 1235, 1903, -- 1996, 1089, 3273, 283, 1853, 1990, 882, 3033, 2419, 2102, 219, 855, -- 2681, 1848, 712, 682, 927, 1795, 461, 1891, 2877, 2522, 1894, 1010, -- 1414, 2009, 3296, 464, 2697, 816, 1352, 2679, 1274, 1052, 1025, 2132, -- 1573, 76, 2998, 3040, 1175, 2444, 394, 1219, 2300, 1455, 2117, 1607, -- 2443, 554, 1179, 2186, 2303, 2926, 2237, 525, 735, 863, 2768, 1230, -- 2572, 556, 3010, 2266, 1684, 1239, 780, 2954, 109, 1292, 1031, 1745, -- 2688, 3061, 992, 2596, 941, 892, 1021, 2390, 642, 1868, 2377, 1482, -- 1540, 540, 1678, 1626, 279, 314, 1173, 2573, 3096, 48, 667, 1920, -- 2229, 1041, 2606, 1692, 680, 2746, 568, 3312, --}; -+#if (KYBER_K == 2) -+#define KYBER_NAMESPACE(s) KYBER512_##s -+#elif (KYBER_K == 3) -+#define KYBER_NAMESPACE(s) KYBER768_##s -+#elif (KYBER_K == 4) -+#define KYBER_NAMESPACE(s) KYBER1024_##s -+#else -+#error "KYBER_K must be in {2,3,4}" -+#endif - --// kModRoots = [pow(17, 2*bitreverse(i) + 1, p) for i in range(128)] --static const uint16_t kModRoots[128] = { -- 17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, -- 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, -- 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, -- 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, -- 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, -- 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, -- 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, -- 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, -- 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, -- 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, -- 2110, 1219, 2935, 394, 885, 2444, 2154, 1175, --}; -+#define public_key KYBER_NAMESPACE(public_key) -+#define private_key KYBER_NAMESPACE(private_key) - --// reduce_once reduces 0 <= x < 2*kPrime, mod kPrime. --static uint16_t reduce_once(uint16_t x) { -- assert(x < 2 * kPrime); -- const uint16_t subtracted = x - kPrime; -- uint16_t mask = 0u - (subtracted >> 15); -- // On Aarch64, omitting a |value_barrier_u16| results in a 2x speedup of Kyber -- // overall and Clang still produces constant-time code using `csel`. On other -- // platforms & compilers on godbolt that we care about, this code also -- // produces constant-time output. -- return (mask & x) | (~mask & subtracted); --} -- --// constant time reduce x mod kPrime using Barrett reduction. x must be less --// than kPrime + 2×kPrime². --static uint16_t reduce(uint32_t x) { -- assert(x < kPrime + 2u * kPrime * kPrime); -- uint64_t product = (uint64_t)x * kBarrettMultiplier; -- uint32_t quotient = product >> kBarrettShift; -- uint32_t remainder = x - quotient * kPrime; -- return reduce_once(remainder); --} -- --static void scalar_zero(scalar *out) { OPENSSL_memset(out, 0, sizeof(*out)); } -- --static void vector_zero(vector *out) { OPENSSL_memset(out, 0, sizeof(*out)); } -- --// In place number theoretic transform of a given scalar. --// Note that Kyber's kPrime 3329 does not have a 512th root of unity, so this --// transform leaves off the last iteration of the usual FFT code, with the 128 --// relevant roots of unity being stored in |kNTTRoots|. This means the output --// should be seen as 128 elements in GF(3329^2), with the coefficients of the --// elements being consecutive entries in |s->c|. --static void scalar_ntt(scalar *s) { -- int offset = DEGREE; -- // `int` is used here because using `size_t` throughout caused a ~5% slowdown -- // with Clang 14 on Aarch64. -- for (int step = 1; step < DEGREE / 2; step <<= 1) { -- offset >>= 1; -- int k = 0; -- for (int i = 0; i < step; i++) { -- const uint32_t step_root = kNTTRoots[i + step]; -- for (int j = k; j < k + offset; j++) { -- uint16_t odd = reduce(step_root * s->c[j + offset]); -- uint16_t even = s->c[j]; -- s->c[j] = reduce_once(odd + even); -- s->c[j + offset] = reduce_once(even - odd + kPrime); -- } -- k += 2 * offset; -+#define generate_key KYBER_NAMESPACE(generate_key) -+#define encap KYBER_NAMESPACE(encap) -+#define decap KYBER_NAMESPACE(decap) -+#define marshal_public_key KYBER_NAMESPACE(marshal_public_key) -+#define parse_public_key KYBER_NAMESPACE(parse_public_key) -+ -+ -+// -+// params.h -+// -+#define KYBER_N 256 -+#define KYBER_Q 3329 -+ +#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */ +#define KYBER_SSBYTES 32 /* size in bytes of shared key */ + @@ -1112,9 +675,9 @@ index 776c085f9..ccb5b3d9b 100644 + a = (d >> (6*j+0)) & 0x7; + b = (d >> (6*j+3)) & 0x7; + r->coeffs[4*i+j] = a - b; - } - } - } ++ } ++ } ++} +#endif + +static void poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1*KYBER_N/4]) @@ -1127,10 +690,7 @@ index 776c085f9..ccb5b3d9b 100644 +#error "This implementation requires eta1 in {2,3}" +#endif +} - --static void vector_ntt(vector *a) { -- for (int i = 0; i < RANK; i++) { -- scalar_ntt(&a->v[i]); ++ +static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]) +{ +#if KYBER_ETA2 == 2 @@ -1157,8 +717,21 @@ index 776c085f9..ccb5b3d9b 100644 + 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, + 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, + 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127 -+}; -+ + }; + +-// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)] +-static const uint16_t kInverseNTTRoots[128] = { +- 1, 1600, 40, 749, 2481, 1432, 2699, 687, 1583, 2760, 69, 543, +- 2532, 3136, 1410, 2267, 2508, 1355, 450, 936, 447, 2794, 1235, 1903, +- 1996, 1089, 3273, 283, 1853, 1990, 882, 3033, 2419, 2102, 219, 855, +- 2681, 1848, 712, 682, 927, 1795, 461, 1891, 2877, 2522, 1894, 1010, +- 1414, 2009, 3296, 464, 2697, 816, 1352, 2679, 1274, 1052, 1025, 2132, +- 1573, 76, 2998, 3040, 1175, 2444, 394, 1219, 2300, 1455, 2117, 1607, +- 2443, 554, 1179, 2186, 2303, 2926, 2237, 525, 735, 863, 2768, 1230, +- 2572, 556, 3010, 2266, 1684, 1239, 780, 2954, 109, 1292, 1031, 1745, +- 2688, 3061, 992, 2596, 941, 892, 1021, 2390, 642, 1868, 2377, 1482, +- 1540, 540, 1678, 1626, 279, 314, 1173, 2573, 3096, 48, 667, 1920, +- 2229, 1041, 2606, 1692, 680, 2746, 568, 3312, +void init_ntt() { + unsigned int i; + int16_t tmp[128]; @@ -1173,8 +746,8 @@ index 776c085f9..ccb5b3d9b 100644 + zetas[i] -= KYBER_Q; + if(zetas[i] < -KYBER_Q/2) + zetas[i] += KYBER_Q; - } - } ++ } ++} +*/ + +static const int16_t zetas[128] = { @@ -1194,8 +767,21 @@ index 776c085f9..ccb5b3d9b 100644 + -1215, -136, 1218, -1335, -874, 220, -1187, -1659, + -1185, -1530, -1278, 794, -1510, -854, -870, 478, + -108, -308, 996, 991, 958, -1460, 1522, 1628 -+}; -+ + }; + +-// kModRoots = [pow(17, 2*bitreverse(i) + 1, p) for i in range(128)] +-static const uint16_t kModRoots[128] = { +- 17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, +- 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, +- 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, +- 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, +- 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, +- 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, +- 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, +- 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, +- 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, +- 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, +- 2110, 1219, 2935, 394, 885, 2444, 2154, 1175, +/************************************************* +* Name: fqmul +* @@ -1209,26 +795,7 @@ index 776c085f9..ccb5b3d9b 100644 +static int16_t fqmul(int16_t a, int16_t b) { + return montgomery_reduce((int32_t)a*b); +} - --// In place inverse number theoretic transform of a given scalar, with pairs of --// entries of s->v being interpreted as elements of GF(3329^2). Just as with the --// number theoretic transform, this leaves off the first step of the normal iFFT --// to account for the fact that 3329 does not have a 512th root of unity, using --// the precomputed 128 roots of unity stored in |kInverseNTTRoots|. --static void scalar_inverse_ntt(scalar *s) { -- int step = DEGREE / 2; -- // `int` is used here because using `size_t` throughout caused a ~5% slowdown -- // with Clang 14 on Aarch64. -- for (int offset = 2; offset < DEGREE; offset <<= 1) { -- step >>= 1; -- int k = 0; -- for (int i = 0; i < step; i++) { -- uint32_t step_root = kInverseNTTRoots[i + step]; -- for (int j = k; j < k + offset; j++) { -- uint16_t odd = s->c[j + offset]; -- uint16_t even = s->c[j]; -- s->c[j] = reduce_once(odd + even); -- s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); ++ +/************************************************* +* Name: ntt +* @@ -1249,18 +816,11 @@ index 776c085f9..ccb5b3d9b 100644 + t = fqmul(zeta, r[j + len]); + r[j + len] = r[j] - t; + r[j] = r[j] + t; - } -- k += 2 * offset; - } - } -- for (int i = 0; i < DEGREE; i++) { -- s->c[i] = reduce(s->c[i] * kInverseDegree); -- } - } - --static void vector_inverse_ntt(vector *a) { -- for (int i = 0; i < RANK; i++) { -- scalar_inverse_ntt(&a->v[i]); ++ } ++ } ++ } ++} ++ +/************************************************* +* Name: invntt_tomont +* @@ -1286,7 +846,7 @@ index 776c085f9..ccb5b3d9b 100644 + r[j + len] = fqmul(zeta, r[j + len]); + } + } - } ++ } + + for(j = 0; j < 256; j++) + r[j] = fqmul(r[j], f); @@ -1310,11 +870,8 @@ index 776c085f9..ccb5b3d9b 100644 + r[0] += fqmul(a[0], b[0]); + r[1] = fqmul(a[0], b[1]); + r[1] += fqmul(a[1], b[0]); - } - --static void scalar_add(scalar *lhs, const scalar *rhs) { -- for (int i = 0; i < DEGREE; i++) { -- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); ++} ++ +// +// poly.c +// @@ -1353,7 +910,7 @@ index 776c085f9..ccb5b3d9b 100644 + r[2] = t[4] | (t[5] << 4); + r[3] = t[6] | (t[7] << 4); + r += 4; - } ++ } +#elif (KYBER_POLYCOMPRESSEDBYTES == 160) + for(i=0;ic[i] = reduce_once(lhs->c[i] - rhs->c[i] + kPrime); ++} ++ +/************************************************* +* Name: poly_decompress +* @@ -1418,29 +972,12 @@ index 776c085f9..ccb5b3d9b 100644 + + for(j=0;j<8;j++) + r->coeffs[8*i+j] = ((uint32_t)(t[j] & 31)*KYBER_Q + 16) >> 5; - } ++ } +#else +#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}" +#endif - } - --// Multiplying two scalars in the number theoretically transformed state. Since --// 3329 does not have a 512th root of unity, this means we have to interpret --// the 2*ith and (2*i+1)th entries of the scalar as elements of GF(3329)[X]/(X^2 --// - 17^(2*bitreverse(i)+1)) The value of 17^(2*bitreverse(i)+1) mod 3329 is --// stored in the precomputed |kModRoots| table. Note that our Barrett transform --// only allows us to multipy two reduced numbers together, so we need some --// intermediate reduction steps, even if an uint64_t could hold 3 multiplied --// numbers. --static void scalar_mult(scalar *out, const scalar *lhs, const scalar *rhs) { -- for (int i = 0; i < DEGREE / 2; i++) { -- uint32_t real_real = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i]; -- uint32_t img_img = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i + 1]; -- uint32_t real_img = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i + 1]; -- uint32_t img_real = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i]; -- out->c[2 * i] = -- reduce(real_real + (uint32_t)reduce(img_img) * kModRoots[i]); -- out->c[2 * i + 1] = reduce(img_real + real_img); ++} ++ +/************************************************* +* Name: poly_tobytes +* @@ -1464,12 +1001,9 @@ index 776c085f9..ccb5b3d9b 100644 + r[3*i+0] = (t0 >> 0); + r[3*i+1] = (t0 >> 8) | (t1 << 4); + r[3*i+2] = (t1 >> 4); - } - } - --static void vector_add(vector *lhs, const vector *rhs) { -- for (int i = 0; i < RANK; i++) { -- scalar_add(&lhs->v[i], &rhs->v[i]); ++ } ++} ++ +/************************************************* +* Name: poly_frombytes +* @@ -1486,16 +1020,9 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;icoeffs[2*i] = ((a[3*i+0] >> 0) | ((uint16_t)a[3*i+1] << 8)) & 0xFFF; + r->coeffs[2*i+1] = ((a[3*i+1] >> 4) | ((uint16_t)a[3*i+2] << 4)) & 0xFFF; - } - } - --static void matrix_mult(vector *out, const matrix *m, const vector *a) { -- vector_zero(out); -- for (int i = 0; i < RANK; i++) { -- for (int j = 0; j < RANK; j++) { -- scalar product; -- scalar_mult(&product, &m->v[i][j], &a->v[j]); -- scalar_add(&out->v[i], &product); ++ } ++} ++ +/************************************************* +* Name: poly_frommsg +* @@ -1517,18 +1044,10 @@ index 776c085f9..ccb5b3d9b 100644 + for(j=0;j<8;j++) { + mask = -(int16_t)value_barrier_u32((msg[i] >> j)&1); + r->coeffs[8*i+j] = mask & ((KYBER_Q+1)/2); - } - } - } - --static void matrix_mult_transpose(vector *out, const matrix *m, -- const vector *a) { -- vector_zero(out); -- for (int i = 0; i < RANK; i++) { -- for (int j = 0; j < RANK; j++) { -- scalar product; -- scalar_mult(&product, &m->v[j][i], &a->v[j]); -- scalar_add(&out->v[i], &product); ++ } ++ } ++} ++ +/************************************************* +* Name: poly_tomsg +* @@ -1552,18 +1071,10 @@ index 776c085f9..ccb5b3d9b 100644 + t >>= 28; + t &= 1; + msg[i] |= t << j; - } - } - } - --static void scalar_inner_product(scalar *out, const vector *lhs, -- const vector *rhs) { -- scalar_zero(out); -- for (int i = 0; i < RANK; i++) { -- scalar product; -- scalar_mult(&product, &lhs->v[i], &rhs->v[i]); -- scalar_add(out, &product); -- } ++ } ++ } ++} ++ +/************************************************* +* Name: poly_getnoise_eta1 +* @@ -1581,32 +1092,8 @@ index 776c085f9..ccb5b3d9b 100644 + uint8_t buf[KYBER_ETA1*KYBER_N/4]; + prf(buf, sizeof(buf), seed, nonce); + poly_cbd_eta1(r, buf); - } - --// Algorithm 1 of the Kyber spec. Rejection samples a Keccak stream to get --// uniformly distributed elements. This is used for matrix expansion and only --// operates on public inputs. --static void scalar_from_keccak_vartime(scalar *out, -- struct BORINGSSL_keccak_st *keccak_ctx) { -- assert(keccak_ctx->offset == 0); -- assert(keccak_ctx->rate_bytes == 168); -- static_assert(168 % 3 == 0, "block and coefficient boundaries do not align"); -- -- int done = 0; -- while (done < DEGREE) { -- uint8_t block[168]; -- BORINGSSL_keccak_squeeze(keccak_ctx, block, sizeof(block)); -- for (size_t i = 0; i < sizeof(block) && done < DEGREE; i += 3) { -- uint16_t d1 = block[i] + 256 * (block[i + 1] % 16); -- uint16_t d2 = block[i + 1] / 16 + 16 * block[i + 2]; -- if (d1 < kPrime) { -- out->c[done++] = d1; -- } -- if (d2 < kPrime && done < DEGREE) { -- out->c[done++] = d2; -- } -- } -- } ++} ++ +/************************************************* +* Name: poly_getnoise_eta2 +* @@ -1624,34 +1111,8 @@ index 776c085f9..ccb5b3d9b 100644 + uint8_t buf[KYBER_ETA2*KYBER_N/4]; + prf(buf, sizeof(buf), seed, nonce); + poly_cbd_eta2(r, buf); - } - --// Algorithm 2 of the Kyber spec, with eta fixed to two and the PRF call --// included. Creates binominally distributed elements by sampling 2*|eta| bits, --// and setting the coefficient to the count of the first bits minus the count of --// the second bits, resulting in a centered binomial distribution. Since eta is --// two this gives -2/2 with a probability of 1/16, -1/1 with probability 1/4, --// and 0 with probability 3/8. --static void scalar_centered_binomial_distribution_eta_2_with_prf( -- scalar *out, const uint8_t input[33]) { -- uint8_t entropy[128]; -- static_assert(sizeof(entropy) == 2 * /*kEta=*/2 * DEGREE / 8, ""); -- BORINGSSL_keccak(entropy, sizeof(entropy), input, 33, boringssl_shake256); -- -- for (int i = 0; i < DEGREE; i += 2) { -- uint8_t byte = entropy[i / 2]; -- -- uint16_t value = kPrime; -- value += (byte & 1) + ((byte >> 1) & 1); -- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); -- out->c[i] = reduce_once(value); -- -- byte >>= 4; -- value = kPrime; -- value += (byte & 1) + ((byte >> 1) & 1); -- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); -- out->c[i + 1] = reduce_once(value); -- } ++} ++ + +/************************************************* +* Name: poly_ntt @@ -1666,19 +1127,8 @@ index 776c085f9..ccb5b3d9b 100644 +{ + ntt(r->coeffs); + poly_reduce(r); - } - --// Generates a secret vector by using --// |scalar_centered_binomial_distribution_eta_2_with_prf|, using the given seed --// appending and incrementing |counter| for entry of the vector. --static void vector_generate_secret_eta_2(vector *out, uint8_t *counter, -- const uint8_t seed[32]) { -- uint8_t input[33]; -- OPENSSL_memcpy(input, seed, 32); -- for (int i = 0; i < RANK; i++) { -- input[32] = (*counter)++; -- scalar_centered_binomial_distribution_eta_2_with_prf(&out->v[i], input); -- } ++} ++ +/************************************************* +* Name: poly_invntt_tomont +* @@ -1691,21 +1141,8 @@ index 776c085f9..ccb5b3d9b 100644 +static void poly_invntt_tomont(poly *r) +{ + invntt(r->coeffs); - } - --// Expands the matrix of a seed for key generation and for encaps-CPA. --static void matrix_expand(matrix *out, const uint8_t rho[32]) { -- uint8_t input[34]; -- OPENSSL_memcpy(input, rho, 32); -- for (int i = 0; i < RANK; i++) { -- for (int j = 0; j < RANK; j++) { -- input[32] = i; -- input[33] = j; -- struct BORINGSSL_keccak_st keccak_ctx; -- BORINGSSL_keccak_init(&keccak_ctx, input, sizeof(input), -- boringssl_shake128); -- scalar_from_keccak_vartime(&out->v[i][j], &keccak_ctx); -- } ++} ++ +/************************************************* +* Name: poly_basemul_montgomery +* @@ -1721,35 +1158,9 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;icoeffs[4*i], &a->coeffs[4*i], &b->coeffs[4*i], zetas[64+i]); + basemul(&r->coeffs[4*i+2], &a->coeffs[4*i+2], &b->coeffs[4*i+2], -zetas[64+i]); - } - } - --static const uint8_t kMasks[8] = {0x01, 0x03, 0x07, 0x0f, -- 0x1f, 0x3f, 0x7f, 0xff}; -- --static void scalar_encode(uint8_t *out, const scalar *s, int bits) { -- assert(bits <= (int)sizeof(*s->c) * 8 && bits != 1); -- -- uint8_t out_byte = 0; -- int out_byte_bits = 0; -- -- for (int i = 0; i < DEGREE; i++) { -- uint16_t element = s->c[i]; -- int element_bits_done = 0; -- -- while (element_bits_done < bits) { -- int chunk_bits = bits - element_bits_done; -- int out_bits_remaining = 8 - out_byte_bits; -- if (chunk_bits >= out_bits_remaining) { -- chunk_bits = out_bits_remaining; -- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; -- *out = out_byte; -- out++; -- out_byte_bits = 0; -- out_byte = 0; -- } else { -- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; -- out_byte_bits += chunk_bits; ++ } ++} ++ +/************************************************* +* Name: poly_tomont +* @@ -1844,10 +1255,8 @@ index 776c085f9..ccb5b3d9b 100644 + d0 *= 645084; + d0 >>= 31; + t[k] = d0 & 0x7ff; - } - -- element_bits_done += chunk_bits; -- element >>= chunk_bits; ++ } ++ + r[ 0] = (t[0] >> 0); + r[ 1] = (t[0] >> 8) | (t[1] << 3); + r[ 2] = (t[1] >> 5) | (t[2] << 6); @@ -1860,8 +1269,8 @@ index 776c085f9..ccb5b3d9b 100644 + r[ 9] = (t[6] >> 6) | (t[7] << 5); + r[10] = (t[7] >> 3); + r += 11; - } - } ++ } ++ } +#elif (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 320)) + uint16_t t[4]; + for(i=0;i>= 32; + t[k] = d0 & 0x3ff; + } - -- if (out_byte_bits > 0) { -- *out = out_byte; ++ + r[0] = (t[0] >> 0); + r[1] = (t[0] >> 8) | (t[1] << 2); + r[2] = (t[1] >> 6) | (t[2] << 4); @@ -1886,18 +1293,12 @@ index 776c085f9..ccb5b3d9b 100644 + r[4] = (t[3] >> 2); + r += 5; + } - } ++ } +#else +#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}" +#endif - } - --// scalar_encode_1 is |scalar_encode| specialised for |bits| == 1. --static void scalar_encode_1(uint8_t out[32], const scalar *s) { -- for (int i = 0; i < DEGREE; i += 8) { -- uint8_t out_byte = 0; -- for (int j = 0; j < 8; j++) { -- out_byte |= (s->c[i + j] & 1) << j; ++} ++ +/************************************************* +* Name: polyvec_decompress +* @@ -1942,22 +1343,13 @@ index 776c085f9..ccb5b3d9b 100644 + + for(k=0;k<4;k++) + r->vec[i].coeffs[4*j+k] = ((uint32_t)(t[k] & 0x3FF)*KYBER_Q + 512) >> 10; - } -- *out = out_byte; -- out++; - } ++ } ++ } +#else +#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}" +#endif - } - --// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 --// (DEGREE) is divisible by 8, the individual vector entries will always fill a --// whole number of bytes, so we do not need to worry about bit packing here. --static void vector_encode(uint8_t *out, const vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); -- } ++} ++ +/************************************************* +* Name: polyvec_tobytes +* @@ -1972,13 +1364,8 @@ index 776c085f9..ccb5b3d9b 100644 + unsigned int i; + for(i=0;ivec[i]); - } - --// scalar_decode parses |DEGREE * bits| bits from |in| into |DEGREE| values in --// |out|. It returns one on success and zero if any parsed value is >= --// |kPrime|. --static int scalar_decode(scalar *out, const uint8_t *in, int bits) { -- assert(bits <= (int)sizeof(*out->c) * 8 && bits != 1); ++} ++ +/************************************************* +* Name: polyvec_frombytes +* @@ -1995,9 +1382,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i], a+i*KYBER_POLYBYTES); +} - -- uint8_t in_byte = 0; -- int in_byte_bits_left = 0; ++ +/************************************************* +* Name: polyvec_ntt +* @@ -2011,10 +1396,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i]); +} - -- for (int i = 0; i < DEGREE; i++) { -- uint16_t element = 0; -- int element_bits_done = 0; ++ +/************************************************* +* Name: polyvec_invntt_tomont +* @@ -2029,13 +1411,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i]); +} - -- while (element_bits_done < bits) { -- if (in_byte_bits_left == 0) { -- in_byte = *in; -- in++; -- in_byte_bits_left = 8; -- } ++ +/************************************************* +* Name: polyvec_basemul_acc_montgomery +* @@ -2056,17 +1432,10 @@ index 776c085f9..ccb5b3d9b 100644 + poly_basemul_montgomery(&t, &a->vec[i], &b->vec[i]); + poly_add(r, r, &t); + } - -- int chunk_bits = bits - element_bits_done; -- if (chunk_bits > in_byte_bits_left) { -- chunk_bits = in_byte_bits_left; -- } ++ + poly_reduce(r); +} - -- element |= (in_byte & kMasks[chunk_bits - 1]) << element_bits_done; -- in_byte_bits_left -= chunk_bits; -- in_byte >>= chunk_bits; ++ +/************************************************* +* Name: polyvec_reduce +* @@ -2082,9 +1451,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i]); +} - -- element_bits_done += chunk_bits; -- } ++ +/************************************************* +* Name: polyvec_add +* @@ -2100,12 +1467,7 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ivec[i], &a->vec[i], &b->vec[i]); +} - -- if (element >= kPrime) { -- return 0; -- } -- out->c[i] = element; -- } ++ +// +// indcpa.c +// @@ -2154,21 +1516,12 @@ index 776c085f9..ccb5b3d9b 100644 + + if(verify(repacked, packedpk, KYBER_POLYVECBYTES) != 0) + return 0; - ++ + for(i=0;ic[i + j] = in_byte & 1; -- in_byte >>= 1; -- } ++ return 1; ++} ++ +/************************************************* +* Name: pack_sk +* @@ -2259,17 +1612,11 @@ index 776c085f9..ccb5b3d9b 100644 + r[ctr++] = val0; + if(ctr < len && val1 < KYBER_Q) + r[ctr++] = val1; - } ++ } + + return ctr; - } - --// Decodes 32*|RANK|*|bits| bytes from |in| into |out|. It returns one on --// success or zero if any parsed value is >= |kPrime|. --static int vector_decode(vector *out, const uint8_t *in, int bits) { -- for (int i = 0; i < RANK; i++) { -- if (!scalar_decode(&out->v[i], in + i * bits * DEGREE / 8, bits)) { -- return 0; ++} ++ +#define gen_a(A,B) gen_matrix(A,B,0) +#define gen_at(A,B) gen_matrix(A,B,1) + @@ -2313,52 +1660,10 @@ index 776c085f9..ccb5b3d9b 100644 + buflen = off + XOF_BLOCKBYTES; + ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, buflen); + } - } - } -- return 1; - } - --// Compresses (lossily) an input |x| mod 3329 into |bits| many bits by grouping --// numbers close to each other together. The formula used is --// round(2^|bits|/kPrime*x) mod 2^|bits|. --// Uses Barrett reduction to achieve constant time. Since we need both the --// remainder (for rounding) and the quotient (as the result), we cannot use --// |reduce| here, but need to do the Barrett reduction directly. --static uint16_t compress(uint16_t x, int bits) { -- uint32_t product = (uint32_t)x << bits; -- uint32_t quotient = ((uint64_t)product * kBarrettMultiplier) >> kBarrettShift; -- uint32_t remainder = product - quotient * kPrime; -- -- // Adjust the quotient to round correctly: -- // 0 <= remainder <= kHalfPrime round to 0 -- // kHalfPrime < remainder <= kPrime + kHalfPrime round to 1 -- // kPrime + kHalfPrime < remainder < 2 * kPrime round to 2 -- assert(remainder < 2u * kPrime); -- quotient += 1 & constant_time_lt_w(kHalfPrime, remainder); -- quotient += 1 & constant_time_lt_w(kPrime + kHalfPrime, remainder); -- return quotient & ((1 << bits) - 1); --} -- --// Decompresses |x| by using an equi-distant representative. The formula is --// round(kPrime/2^|bits|*x). Note that 2^|bits| being the divisor allows us to --// implement this logic using only bit operations. --static uint16_t decompress(uint16_t x, int bits) { -- uint32_t product = (uint32_t)x * kPrime; -- uint32_t power = 1 << bits; -- // This is |product| % power, since |power| is a power of 2. -- uint32_t remainder = product & (power - 1); -- // This is |product| / power, since |power| is a power of 2. -- uint32_t lower = product >> bits; -- // The rounding logic works since the first half of numbers mod |power| have a -- // 0 as first bit, and the second half has a 1 as first bit, since |power| is -- // a power of 2. As a 12 bit number, |remainder| is always positive, so we -- // will shift in 0s for a right shift. -- return lower + (remainder >> (bits - 1)); --} -- --static void scalar_compress(scalar *s, int bits) { -- for (int i = 0; i < DEGREE; i++) { -- s->c[i] = compress(s->c[i], bits); ++ } ++ } ++} ++ +/************************************************* +* Name: indcpa_keypair +* @@ -2398,19 +1703,15 @@ index 776c085f9..ccb5b3d9b 100644 + for(i=0;ic[i] = decompress(s->c[i], bits); -- } ++} ++ +/************************************************* +* Name: indcpa_enc +* @@ -2469,12 +1770,8 @@ index 776c085f9..ccb5b3d9b 100644 + + pack_ciphertext(c, &b, &v); + return 1; - } - --static void vector_compress(vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_compress(&a->v[i], bits); -- } ++} ++ +/************************************************* +* Name: indcpa_dec +* @@ -2506,12 +1803,8 @@ index 776c085f9..ccb5b3d9b 100644 + poly_reduce(&mp); + + poly_tomsg(m, &mp); - } - --static void vector_decompress(vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_decompress(&a->v[i], bits); -- } ++} ++ +// +// fips202.c +// @@ -2541,13 +1834,8 @@ index 776c085f9..ccb5b3d9b 100644 + r |= (uint64_t)x[i] << 8*i; + + return r; - } - --struct public_key { -- vector t; -- uint8_t rho[32]; -- uint8_t public_key_hash[32]; -- matrix m; ++} ++ +/************************************************* +* Name: store64 +* @@ -2591,13 +1879,16 @@ index 776c085f9..ccb5b3d9b 100644 + (uint64_t)0x8000000080008008ULL }; --static struct public_key *public_key_from_external( -- const struct KYBER_public_key *external) { -- static_assert(sizeof(struct KYBER_public_key) >= sizeof(struct public_key), -- "Kyber public key is too small"); -- static_assert(alignof(struct KYBER_public_key) >= alignof(struct public_key), -- "Kyber public key align incorrect"); -- return (struct public_key *)external; +-// reduce_once reduces 0 <= x < 2*kPrime, mod kPrime. +-static uint16_t reduce_once(uint16_t x) { +- assert(x < 2 * kPrime); +- const uint16_t subtracted = x - kPrime; +- uint16_t mask = 0u - (subtracted >> 15); +- // On Aarch64, omitting a |value_barrier_u16| results in a 2x speedup of Kyber +- // overall and Clang still produces constant-time code using `csel`. On other +- // platforms & compilers on godbolt that we care about, this code also +- // produces constant-time output. +- return (mask & x) | (~mask & subtracted); +/************************************************* +* Name: KeccakF1600_StatePermute +* @@ -2869,36 +2160,17 @@ index 776c085f9..ccb5b3d9b 100644 + state[24] = Asu; } --struct private_key { -- struct public_key pub; -- vector s; -- uint8_t fo_failure_secret[32]; --}; +-// constant time reduce x mod kPrime using Barrett reduction. x must be less +-// than kPrime + 2×kPrime². +-static uint16_t reduce(uint32_t x) { +- assert(x < kPrime + 2u * kPrime * kPrime); +- uint64_t product = (uint64_t)x * kBarrettMultiplier; +- uint32_t quotient = (uint32_t)(product >> kBarrettShift); +- uint32_t remainder = x - quotient * kPrime; +- return reduce_once(remainder); +-} --static struct private_key *private_key_from_external( -- const struct KYBER_private_key *external) { -- static_assert(sizeof(struct KYBER_private_key) >= sizeof(struct private_key), -- "Kyber private key too small"); -- static_assert( -- alignof(struct KYBER_private_key) >= alignof(struct private_key), -- "Kyber private key align incorrect"); -- return (struct private_key *)external; --} -- --// Calls |KYBER_generate_key_external_entropy| with random bytes from --// |RAND_bytes|. --void KYBER_generate_key(uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], -- struct KYBER_private_key *out_private_key) { -- uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]; -- RAND_bytes(entropy, sizeof(entropy)); -- KYBER_generate_key_external_entropy(out_encoded_public_key, out_private_key, -- entropy); --} -- --static int kyber_marshal_public_key(CBB *out, const struct public_key *pub) { -- uint8_t *vector_output; -- if (!CBB_add_space(out, &vector_output, kEncodedVectorSize)) { -- return 0; +-static void scalar_zero(scalar *out) { OPENSSL_memset(out, 0, sizeof(*out)); } +/************************************************* +* Name: keccak_squeeze +* @@ -2921,20 +2193,41 @@ index 776c085f9..ccb5b3d9b 100644 + unsigned int r) +{ + unsigned int i; -+ + +-static void vector_zero(vector *out) { OPENSSL_memset(out, 0, sizeof(*out)); } +- +-// In place number theoretic transform of a given scalar. +-// Note that Kyber's kPrime 3329 does not have a 512th root of unity, so this +-// transform leaves off the last iteration of the usual FFT code, with the 128 +-// relevant roots of unity being stored in |kNTTRoots|. This means the output +-// should be seen as 128 elements in GF(3329^2), with the coefficients of the +-// elements being consecutive entries in |s->c|. +-static void scalar_ntt(scalar *s) { +- int offset = DEGREE; +- // `int` is used here because using `size_t` throughout caused a ~5% slowdown +- // with Clang 14 on Aarch64. +- for (int step = 1; step < DEGREE / 2; step <<= 1) { +- offset >>= 1; +- int k = 0; +- for (int i = 0; i < step; i++) { +- const uint32_t step_root = kNTTRoots[i + step]; +- for (int j = k; j < k + offset; j++) { +- uint16_t odd = reduce(step_root * s->c[j + offset]); +- uint16_t even = s->c[j]; +- s->c[j] = reduce_once(odd + even); +- s->c[j + offset] = reduce_once(even - odd + kPrime); +- } +- k += 2 * offset; + while(outlen) { + if(pos == r) { + KeccakF1600_StatePermute(s); + pos = 0; -+ } + } + for(i=pos;i < r && i < pos+outlen; i++) + *out++ = s[i/8] >> 8*(i%8); + outlen -= i-pos; + pos = i; - } -- vector_encode(vector_output, &pub->t, kLog2Prime); -- if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { -- return 0; ++ } + + return pos; +} @@ -2966,8 +2259,7 @@ index 776c085f9..ccb5b3d9b 100644 + inlen -= r-pos; + KeccakF1600_StatePermute(s); + pos = 0; - } -- return 1; ++ } + + for(i=pos;ipub.rho, hashed, sizeof(priv->pub.rho)); -- matrix_expand(&priv->pub.m, rho); -- uint8_t counter = 0; -- vector_generate_secret_eta_2(&priv->s, &counter, sigma); -- vector_ntt(&priv->s); -- vector error; -- vector_generate_secret_eta_2(&error, &counter, sigma); -- vector_ntt(&error); -- matrix_mult_transpose(&priv->pub.t, &priv->pub.m, &priv->s); -- vector_add(&priv->pub.t, &error); -- -- CBB cbb; -- CBB_init_fixed(&cbb, out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES); -- if (!kyber_marshal_public_key(&cbb, &priv->pub)) { -- abort(); ++} ++ + +/************************************************* +* Name: keccak_absorb_once @@ -3048,8 +2313,824 @@ index 776c085f9..ccb5b3d9b 100644 + in += r; + inlen -= r; + KeccakF1600_StatePermute(s); ++ } ++ ++ for(i=0;iv[i]); +- } ++ ++/************************************************* ++* Name: shake128_absorb_once ++* ++* Description: Initialize, absorb into and finalize SHAKE128 XOF; non-incremental. ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state ++* - const uint8_t *in: pointer to input to be absorbed into s ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) ++{ ++ keccak_absorb_once(state->s, SHAKE128_RATE, in, inlen, 0x1F); ++ state->pos = SHAKE128_RATE; + } + +-// In place inverse number theoretic transform of a given scalar, with pairs of +-// entries of s->v being interpreted as elements of GF(3329^2). Just as with the +-// number theoretic transform, this leaves off the first step of the normal iFFT +-// to account for the fact that 3329 does not have a 512th root of unity, using +-// the precomputed 128 roots of unity stored in |kInverseNTTRoots|. +-static void scalar_inverse_ntt(scalar *s) { +- int step = DEGREE / 2; +- // `int` is used here because using `size_t` throughout caused a ~5% slowdown +- // with Clang 14 on Aarch64. +- for (int offset = 2; offset < DEGREE; offset <<= 1) { +- step >>= 1; +- int k = 0; +- for (int i = 0; i < step; i++) { +- uint32_t step_root = kInverseNTTRoots[i + step]; +- for (int j = k; j < k + offset; j++) { +- uint16_t odd = s->c[j + offset]; +- uint16_t even = s->c[j]; +- s->c[j] = reduce_once(odd + even); +- s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); +- } +- k += 2 * offset; +- } +- } +- for (int i = 0; i < DEGREE; i++) { +- s->c[i] = reduce(s->c[i] * kInverseDegree); +- } ++/************************************************* ++* Name: shake128_squeezeblocks ++* ++* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of ++* SHAKE128_RATE bytes each. Can be called multiple times ++* to keep squeezing. Assumes new block has not yet been ++* started (state->pos = SHAKE128_RATE). ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t nblocks: number of blocks to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) ++{ ++ keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); + } + +-static void vector_inverse_ntt(vector *a) { +- for (int i = 0; i < RANK; i++) { +- scalar_inverse_ntt(&a->v[i]); +- } ++/************************************************* ++* Name: shake256_squeeze ++* ++* Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many ++* bytes. Can be called multiple times to keep squeezing. ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t outlen : number of bytes to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) ++{ ++ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); + } + +-static void scalar_add(scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE; i++) { +- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); +- } ++/************************************************* ++* Name: shake256_absorb_once ++* ++* Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental. ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state ++* - const uint8_t *in: pointer to input to be absorbed into s ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) ++{ ++ keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); ++ state->pos = SHAKE256_RATE; + } + +-static void scalar_sub(scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE; i++) { +- lhs->c[i] = reduce_once(lhs->c[i] - rhs->c[i] + kPrime); +- } ++/************************************************* ++* Name: shake256_squeezeblocks ++* ++* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of ++* SHAKE256_RATE bytes each. Can be called multiple times ++* to keep squeezing. Assumes next block has not yet been ++* started (state->pos = SHAKE256_RATE). ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t nblocks: number of blocks to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) ++{ ++ keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); + } + +-// Multiplying two scalars in the number theoretically transformed state. Since +-// 3329 does not have a 512th root of unity, this means we have to interpret +-// the 2*ith and (2*i+1)th entries of the scalar as elements of GF(3329)[X]/(X^2 +-// - 17^(2*bitreverse(i)+1)) The value of 17^(2*bitreverse(i)+1) mod 3329 is +-// stored in the precomputed |kModRoots| table. Note that our Barrett transform +-// only allows us to multipy two reduced numbers together, so we need some +-// intermediate reduction steps, even if an uint64_t could hold 3 multiplied +-// numbers. +-static void scalar_mult(scalar *out, const scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE / 2; i++) { +- uint32_t real_real = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i]; +- uint32_t img_img = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i + 1]; +- uint32_t real_img = (uint32_t)lhs->c[2 * i] * rhs->c[2 * i + 1]; +- uint32_t img_real = (uint32_t)lhs->c[2 * i + 1] * rhs->c[2 * i]; +- out->c[2 * i] = +- reduce(real_real + (uint32_t)reduce(img_img) * kModRoots[i]); +- out->c[2 * i + 1] = reduce(img_real + real_img); +- } ++/************************************************* ++* Name: shake256_absorb ++* ++* Description: Absorb step of the SHAKE256 XOF; incremental. ++* ++* Arguments: - keccak_state *state: pointer to (initialized) output Keccak state ++* - const uint8_t *in: pointer to input to be absorbed into s ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen) ++{ ++ state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); + } + +-static void vector_add(vector *lhs, const vector *rhs) { +- for (int i = 0; i < RANK; i++) { +- scalar_add(&lhs->v[i], &rhs->v[i]); +- } ++/************************************************* ++* Name: shake256_finalize ++* ++* Description: Finalize absorb step of the SHAKE256 XOF. ++* ++* Arguments: - keccak_state *state: pointer to Keccak state ++**************************************************/ ++static void shake256_finalize(keccak_state *state) ++{ ++ keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); ++ state->pos = SHAKE256_RATE; + } + +-static void matrix_mult(vector *out, const matrix *m, const vector *a) { +- vector_zero(out); +- for (int i = 0; i < RANK; i++) { +- for (int j = 0; j < RANK; j++) { +- scalar product; +- scalar_mult(&product, &m->v[i][j], &a->v[j]); +- scalar_add(&out->v[i], &product); +- } +- } ++/************************************************* ++* Name: keccak_init ++* ++* Description: Initializes the Keccak state. ++* ++* Arguments: - uint64_t *s: pointer to Keccak state ++**************************************************/ ++static void keccak_init(uint64_t s[25]) ++{ ++ unsigned int i; ++ for(i=0;i<25;i++) ++ s[i] = 0; + } + +-static void matrix_mult_transpose(vector *out, const matrix *m, +- const vector *a) { +- vector_zero(out); +- for (int i = 0; i < RANK; i++) { +- for (int j = 0; j < RANK; j++) { +- scalar product; +- scalar_mult(&product, &m->v[j][i], &a->v[j]); +- scalar_add(&out->v[i], &product); +- } +- } ++/************************************************* ++* Name: shake256_init ++* ++* Description: Initilizes Keccak state for use as SHAKE256 XOF ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state ++**************************************************/ ++static void shake256_init(keccak_state *state) ++{ ++ keccak_init(state->s); ++ state->pos = 0; + } + +-static void scalar_inner_product(scalar *out, const vector *lhs, +- const vector *rhs) { +- scalar_zero(out); +- for (int i = 0; i < RANK; i++) { +- scalar product; +- scalar_mult(&product, &lhs->v[i], &rhs->v[i]); +- scalar_add(out, &product); +- } ++ ++/************************************************* ++* Name: shake256 ++* ++* Description: SHAKE256 XOF with non-incremental API ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: requested output length in bytes ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) ++{ ++ size_t nblocks; ++ keccak_state state; ++ ++ shake256_absorb_once(&state, in, inlen); ++ nblocks = outlen/SHAKE256_RATE; ++ shake256_squeezeblocks(out, nblocks, &state); ++ outlen -= nblocks*SHAKE256_RATE; ++ out += nblocks*SHAKE256_RATE; ++ shake256_squeeze(out, outlen, &state); + } + +-// Algorithm 1 of the Kyber spec. Rejection samples a Keccak stream to get +-// uniformly distributed elements. This is used for matrix expansion and only +-// operates on public inputs. +-static void scalar_from_keccak_vartime(scalar *out, +- struct BORINGSSL_keccak_st *keccak_ctx) { +- assert(keccak_ctx->squeeze_offset == 0); +- assert(keccak_ctx->rate_bytes == 168); +- static_assert(168 % 3 == 0, "block and coefficient boundaries do not align"); ++/************************************************* ++* Name: sha3_256 ++* ++* Description: SHA3-256 with non-incremental API ++* ++* Arguments: - uint8_t *h: pointer to output (32 bytes) ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen) ++{ ++ unsigned int i; ++ uint64_t s[25]; + +- int done = 0; +- while (done < DEGREE) { +- uint8_t block[168]; +- BORINGSSL_keccak_squeeze(keccak_ctx, block, sizeof(block)); +- for (size_t i = 0; i < sizeof(block) && done < DEGREE; i += 3) { +- uint16_t d1 = block[i] + 256 * (block[i + 1] % 16); +- uint16_t d2 = block[i + 1] / 16 + 16 * block[i + 2]; +- if (d1 < kPrime) { +- out->c[done++] = d1; +- } +- if (d2 < kPrime && done < DEGREE) { +- out->c[done++] = d2; +- } +- } +- } ++ keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); ++ KeccakF1600_StatePermute(s); ++ for(i=0;i<4;i++) ++ store64(h+8*i,s[i]); + } + +-// Algorithm 2 of the Kyber spec, with eta fixed to two and the PRF call +-// included. Creates binominally distributed elements by sampling 2*|eta| bits, +-// and setting the coefficient to the count of the first bits minus the count of +-// the second bits, resulting in a centered binomial distribution. Since eta is +-// two this gives -2/2 with a probability of 1/16, -1/1 with probability 1/4, +-// and 0 with probability 3/8. +-static void scalar_centered_binomial_distribution_eta_2_with_prf( +- scalar *out, const uint8_t input[33]) { +- uint8_t entropy[128]; +- static_assert(sizeof(entropy) == 2 * /*kEta=*/2 * DEGREE / 8, ""); +- BORINGSSL_keccak(entropy, sizeof(entropy), input, 33, boringssl_shake256); ++/************************************************* ++* Name: sha3_512 ++* ++* Description: SHA3-512 with non-incremental API ++* ++* Arguments: - uint8_t *h: pointer to output (64 bytes) ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen) ++{ ++ unsigned int i; ++ uint64_t s[25]; + +- for (int i = 0; i < DEGREE; i += 2) { +- uint8_t byte = entropy[i / 2]; +- +- uint16_t value = kPrime; +- value += (byte & 1) + ((byte >> 1) & 1); +- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); +- out->c[i] = reduce_once(value); +- +- byte >>= 4; +- value = kPrime; +- value += (byte & 1) + ((byte >> 1) & 1); +- value -= ((byte >> 2) & 1) + ((byte >> 3) & 1); +- out->c[i + 1] = reduce_once(value); +- } ++ keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); ++ KeccakF1600_StatePermute(s); ++ for(i=0;i<8;i++) ++ store64(h+8*i,s[i]); + } + +-// Generates a secret vector by using +-// |scalar_centered_binomial_distribution_eta_2_with_prf|, using the given seed +-// appending and incrementing |counter| for entry of the vector. +-static void vector_generate_secret_eta_2(vector *out, uint8_t *counter, +- const uint8_t seed[32]) { +- uint8_t input[33]; +- OPENSSL_memcpy(input, seed, 32); +- for (int i = 0; i < RANK; i++) { +- input[32] = (*counter)++; +- scalar_centered_binomial_distribution_eta_2_with_prf(&out->v[i], input); +- } ++// ++// symmetric-shake.c ++// ++ ++/************************************************* ++* Name: kyber_shake128_absorb ++* ++* Description: Absorb step of the SHAKE128 specialized for the Kyber context. ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state ++* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state ++* - uint8_t i: additional byte of input ++* - uint8_t j: additional byte of input ++**************************************************/ ++static void kyber_shake128_absorb(keccak_state *state, ++ const uint8_t seed[KYBER_SYMBYTES], ++ uint8_t x, ++ uint8_t y) ++{ ++ uint8_t extseed[KYBER_SYMBYTES+2]; ++ ++ memcpy(extseed, seed, KYBER_SYMBYTES); ++ extseed[KYBER_SYMBYTES+0] = x; ++ extseed[KYBER_SYMBYTES+1] = y; ++ ++ shake128_absorb_once(state, extseed, sizeof(extseed)); + } + +-// Expands the matrix of a seed for key generation and for encaps-CPA. +-static void matrix_expand(matrix *out, const uint8_t rho[32]) { +- uint8_t input[34]; +- OPENSSL_memcpy(input, rho, 32); +- for (int i = 0; i < RANK; i++) { +- for (int j = 0; j < RANK; j++) { +- input[32] = i; +- input[33] = j; +- struct BORINGSSL_keccak_st keccak_ctx; +- BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake128); +- BORINGSSL_keccak_absorb(&keccak_ctx, input, sizeof(input)); +- scalar_from_keccak_vartime(&out->v[i][j], &keccak_ctx); +- } +- } ++/************************************************* ++* Name: kyber_shake256_prf ++* ++* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input ++* and then generates outlen bytes of SHAKE256 output ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: number of requested output bytes ++* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES) ++* - uint8_t nonce: single-byte nonce (public PRF input) ++**************************************************/ ++static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce) ++{ ++ uint8_t extkey[KYBER_SYMBYTES+1]; ++ ++ memcpy(extkey, key, KYBER_SYMBYTES); ++ extkey[KYBER_SYMBYTES] = nonce; ++ ++ shake256(out, outlen, extkey, sizeof(extkey)); + } + +-static const uint8_t kMasks[8] = {0x01, 0x03, 0x07, 0x0f, +- 0x1f, 0x3f, 0x7f, 0xff}; ++// ++// kem.c ++// + +-static void scalar_encode(uint8_t *out, const scalar *s, int bits) { +- assert(bits <= (int)sizeof(*s->c) * 8 && bits != 1); ++// Modified crypto_kem_keypair to BoringSSL style API ++void generate_key(struct public_key *out_pub, struct private_key *out_priv, ++ const uint8_t seed[KYBER_GENERATE_KEY_BYTES]) ++{ ++ size_t i; ++ uint8_t* pk = &out_pub->opaque[0]; ++ uint8_t* sk = &out_priv->opaque[0]; + +- uint8_t out_byte = 0; +- int out_byte_bits = 0; +- +- for (int i = 0; i < DEGREE; i++) { +- uint16_t element = s->c[i]; +- int element_bits_done = 0; +- +- while (element_bits_done < bits) { +- int chunk_bits = bits - element_bits_done; +- int out_bits_remaining = 8 - out_byte_bits; +- if (chunk_bits >= out_bits_remaining) { +- chunk_bits = out_bits_remaining; +- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; +- *out = out_byte; +- out++; +- out_byte_bits = 0; +- out_byte = 0; +- } else { +- out_byte |= (element & kMasks[chunk_bits - 1]) << out_byte_bits; +- out_byte_bits += chunk_bits; +- } +- +- element_bits_done += chunk_bits; +- element >>= chunk_bits; +- } +- } +- +- if (out_byte_bits > 0) { +- *out = out_byte; +- } ++ indcpa_keypair(pk, sk, seed); ++ for(i=0;ic[i + j] & 1) << j; +- } +- *out = out_byte; +- out++; +- } +-} ++// Modified crypto_kem_enc to BoringSSL style API ++int encap(uint8_t out_ciphertext[KYBER_CIPHERTEXTBYTES], ++ uint8_t ss[KYBER_KEY_BYTES], ++ const struct public_key *in_pub, ++ const uint8_t seed[KYBER_ENCAP_BYTES], int mlkem) ++{ ++ const uint8_t *pk = &in_pub->opaque[0]; ++ uint8_t *ct = out_ciphertext; ++ ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; + +-// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 +-// (DEGREE) is divisible by 8, the individual vector entries will always fill a +-// whole number of bytes, so we do not need to worry about bit packing here. +-static void vector_encode(uint8_t *out, const vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); +- } +-} ++ memcpy(buf, seed, KYBER_SYMBYTES); + +-// scalar_decode parses |DEGREE * bits| bits from |in| into |DEGREE| values in +-// |out|. It returns one on success and zero if any parsed value is >= +-// |kPrime|. +-static int scalar_decode(scalar *out, const uint8_t *in, int bits) { +- assert(bits <= (int)sizeof(*out->c) * 8 && bits != 1); ++ /* Don't release system RNG output */ ++ hash_h(buf, buf, KYBER_SYMBYTES); + +- uint8_t in_byte = 0; +- int in_byte_bits_left = 0; ++ /* Multitarget countermeasure for coins + contributory KEM */ ++ hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); ++ hash_g(kr, buf, 2*KYBER_SYMBYTES); + +- for (int i = 0; i < DEGREE; i++) { +- uint16_t element = 0; +- int element_bits_done = 0; ++ /* coins are in kr+KYBER_SYMBYTES */ ++ if(!indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES)) ++ return 0; + +- while (element_bits_done < bits) { +- if (in_byte_bits_left == 0) { +- in_byte = *in; +- in++; +- in_byte_bits_left = 8; +- } +- +- int chunk_bits = bits - element_bits_done; +- if (chunk_bits > in_byte_bits_left) { +- chunk_bits = in_byte_bits_left; +- } +- +- element |= (in_byte & kMasks[chunk_bits - 1]) << element_bits_done; +- in_byte_bits_left -= chunk_bits; +- in_byte >>= chunk_bits; +- +- element_bits_done += chunk_bits; +- } +- +- if (element >= kPrime) { +- return 0; +- } +- out->c[i] = element; +- } +- +- return 1; +-} +- +-// scalar_decode_1 is |scalar_decode| specialised for |bits| == 1. +-static void scalar_decode_1(scalar *out, const uint8_t in[32]) { +- for (int i = 0; i < DEGREE; i += 8) { +- uint8_t in_byte = *in; +- in++; +- for (int j = 0; j < 8; j++) { +- out->c[i + j] = in_byte & 1; +- in_byte >>= 1; +- } +- } +-} +- +-// Decodes 32*|RANK|*|bits| bytes from |in| into |out|. It returns one on +-// success or zero if any parsed value is >= |kPrime|. +-static int vector_decode(vector *out, const uint8_t *in, int bits) { +- for (int i = 0; i < RANK; i++) { +- if (!scalar_decode(&out->v[i], in + i * bits * DEGREE / 8, bits)) { +- return 0; +- } ++ if (mlkem == 1) { ++ memcpy(ss, kr, KYBER_SYMBYTES); ++ } else { ++ /* overwrite coins in kr with H(c) */ ++ hash_h(kr+KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); ++ /* hash concatenation of pre-k and H(c) to k */ ++ kdf(ss, kr, 2*KYBER_SYMBYTES); + } + return 1; + } + +-// Compresses (lossily) an input |x| mod 3329 into |bits| many bits by grouping +-// numbers close to each other together. The formula used is +-// round(2^|bits|/kPrime*x) mod 2^|bits|. +-// Uses Barrett reduction to achieve constant time. Since we need both the +-// remainder (for rounding) and the quotient (as the result), we cannot use +-// |reduce| here, but need to do the Barrett reduction directly. +-static uint16_t compress(uint16_t x, int bits) { +- uint32_t shifted = (uint32_t)x << bits; +- uint64_t product = (uint64_t)shifted * kBarrettMultiplier; +- uint32_t quotient = (uint32_t)(product >> kBarrettShift); +- uint32_t remainder = shifted - quotient * kPrime; ++// Modified crypto_kem_decap to BoringSSL style API ++void decap(uint8_t out_shared_key[KYBER_SSBYTES], ++ const struct private_key *in_priv, ++ const uint8_t *ct, size_t ciphertext_len, int mlkem) ++{ ++ uint8_t *ss = out_shared_key; ++ const uint8_t *sk = &in_priv->opaque[0]; + +- // Adjust the quotient to round correctly: +- // 0 <= remainder <= kHalfPrime round to 0 +- // kHalfPrime < remainder <= kPrime + kHalfPrime round to 1 +- // kPrime + kHalfPrime < remainder < 2 * kPrime round to 2 +- assert(remainder < 2u * kPrime); +- quotient += 1 & constant_time_lt_w(kHalfPrime, remainder); +- quotient += 1 & constant_time_lt_w(kPrime + kHalfPrime, remainder); +- return quotient & ((1 << bits) - 1); +-} ++ size_t i; ++ int fail = 1; ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; ++ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; ++ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; + +-// Decompresses |x| by using an equi-distant representative. The formula is +-// round(kPrime/2^|bits|*x). Note that 2^|bits| being the divisor allows us to +-// implement this logic using only bit operations. +-static uint16_t decompress(uint16_t x, int bits) { +- uint32_t product = (uint32_t)x * kPrime; +- uint32_t power = 1 << bits; +- // This is |product| % power, since |power| is a power of 2. +- uint32_t remainder = product & (power - 1); +- // This is |product| / power, since |power| is a power of 2. +- uint32_t lower = product >> bits; +- // The rounding logic works since the first half of numbers mod |power| have a +- // 0 as first bit, and the second half has a 1 as first bit, since |power| is +- // a power of 2. As a 12 bit number, |remainder| is always positive, so we +- // will shift in 0s for a right shift. +- return lower + (remainder >> (bits - 1)); +-} ++ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { ++ indcpa_dec(buf, ct, sk); + +-static void scalar_compress(scalar *s, int bits) { +- for (int i = 0; i < DEGREE; i++) { +- s->c[i] = compress(s->c[i], bits); ++ /* Multitarget countermeasure for coins + contributory KEM */ ++ for(i=0;ic[i] = decompress(s->c[i], bits); +- } ++void marshal_public_key(uint8_t out[KYBER_PUBLICKEYBYTES], ++ const struct public_key *in_pub) { ++ memcpy(out, &in_pub->opaque, KYBER_PUBLICKEYBYTES); + } + +-static void vector_compress(vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_compress(&a->v[i], bits); +- } +-} +- +-static void vector_decompress(vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_decompress(&a->v[i], bits); +- } +-} +- +-struct public_key { +- vector t; +- uint8_t rho[32]; +- uint8_t public_key_hash[32]; +- matrix m; +-}; +- +-static struct public_key *public_key_from_external( +- const struct KYBER_public_key *external) { +- static_assert(sizeof(struct KYBER_public_key) >= sizeof(struct public_key), +- "Kyber public key is too small"); +- static_assert(alignof(struct KYBER_public_key) >= alignof(struct public_key), +- "Kyber public key align incorrect"); +- return (struct public_key *)external; +-} +- +-struct private_key { +- struct public_key pub; +- vector s; +- uint8_t fo_failure_secret[32]; +-}; +- +-static struct private_key *private_key_from_external( +- const struct KYBER_private_key *external) { +- static_assert(sizeof(struct KYBER_private_key) >= sizeof(struct private_key), +- "Kyber private key too small"); +- static_assert( +- alignof(struct KYBER_private_key) >= alignof(struct private_key), +- "Kyber private key align incorrect"); +- return (struct private_key *)external; +-} +- +-// Calls |KYBER_generate_key_external_entropy| with random bytes from +-// |RAND_bytes|. +-void KYBER_generate_key(uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], +- struct KYBER_private_key *out_private_key) { +- uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]; +- RAND_bytes(entropy, sizeof(entropy)); +- KYBER_generate_key_external_entropy(out_encoded_public_key, out_private_key, +- entropy); +-} +- +-static int kyber_marshal_public_key(CBB *out, const struct public_key *pub) { +- uint8_t *vector_output; +- if (!CBB_add_space(out, &vector_output, kEncodedVectorSize)) { +- return 0; +- } +- vector_encode(vector_output, &pub->t, kLog2Prime); +- if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { +- return 0; +- } +- return 1; +-} +- +-// Algorithms 4 and 7 of the Kyber spec. Algorithms are combined since key +-// generation is not part of the FO transform, and the spec uses Algorithm 7 to +-// specify the actual key format. +-void KYBER_generate_key_external_entropy( +- uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], +- struct KYBER_private_key *out_private_key, +- const uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]) { +- struct private_key *priv = private_key_from_external(out_private_key); +- uint8_t hashed[64]; +- BORINGSSL_keccak(hashed, sizeof(hashed), entropy, 32, boringssl_sha3_512); +- const uint8_t *const rho = hashed; +- const uint8_t *const sigma = hashed + 32; +- OPENSSL_memcpy(priv->pub.rho, hashed, sizeof(priv->pub.rho)); +- matrix_expand(&priv->pub.m, rho); +- uint8_t counter = 0; +- vector_generate_secret_eta_2(&priv->s, &counter, sigma); +- vector_ntt(&priv->s); +- vector error; +- vector_generate_secret_eta_2(&error, &counter, sigma); +- vector_ntt(&error); +- matrix_mult_transpose(&priv->pub.t, &priv->pub.m, &priv->s); +- vector_add(&priv->pub.t, &error); +- +- CBB cbb; +- CBB_init_fixed(&cbb, out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES); +- if (!kyber_marshal_public_key(&cbb, &priv->pub)) { +- abort(); +- } +- - BORINGSSL_keccak(priv->pub.public_key_hash, sizeof(priv->pub.public_key_hash), - out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES, - boringssl_sha3_256); @@ -3180,65 +3261,18 @@ index 776c085f9..ccb5b3d9b 100644 - for (int i = 0; i < 32; i++) { - input[i] = constant_time_select_8(mask, prekey_and_randomness[i], - priv->fo_failure_secret[i]); -+ for(i=0;is, SHAKE128_RATE, in, inlen, 0x1F); -+ state->pos = SHAKE128_RATE; - } - +-} +- -// kyber_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate -// the value of |pub->public_key_hash|. -static int kyber_parse_public_key_no_hash(struct public_key *pub, CBS *in) { @@ -3250,336 +3284,27 @@ index 776c085f9..ccb5b3d9b 100644 - } - matrix_expand(&pub->m, pub->rho); - return 1; -+/************************************************* -+* Name: shake128_squeezeblocks -+* -+* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of -+* SHAKE128_RATE bytes each. Can be called multiple times -+* to keep squeezing. Assumes new block has not yet been -+* started (state->pos = SHAKE128_RATE). -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t nblocks: number of blocks to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) -+{ -+ keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); -+} -+ -+/************************************************* -+* Name: shake256_squeeze -+* -+* Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many -+* bytes. Can be called multiple times to keep squeezing. -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t outlen : number of bytes to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) -+{ -+ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); -+} -+ -+/************************************************* -+* Name: shake256_absorb_once -+* -+* Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental. -+* -+* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+**************************************************/ -+static void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) -+{ -+ keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); -+ state->pos = SHAKE256_RATE; -+} -+ -+/************************************************* -+* Name: shake256_squeezeblocks -+* -+* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of -+* SHAKE256_RATE bytes each. Can be called multiple times -+* to keep squeezing. Assumes next block has not yet been -+* started (state->pos = SHAKE256_RATE). -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t nblocks: number of blocks to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) -+{ -+ keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); -+} -+ -+/************************************************* -+* Name: shake256_absorb -+* -+* Description: Absorb step of the SHAKE256 XOF; incremental. -+* -+* Arguments: - keccak_state *state: pointer to (initialized) output Keccak state -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+**************************************************/ -+static void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen) -+{ -+ state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); -+} -+ -+/************************************************* -+* Name: shake256_finalize -+* -+* Description: Finalize absorb step of the SHAKE256 XOF. -+* -+* Arguments: - keccak_state *state: pointer to Keccak state -+**************************************************/ -+static void shake256_finalize(keccak_state *state) -+{ -+ keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); -+ state->pos = SHAKE256_RATE; -+} -+ -+/************************************************* -+* Name: keccak_init -+* -+* Description: Initializes the Keccak state. -+* -+* Arguments: - uint64_t *s: pointer to Keccak state -+**************************************************/ -+static void keccak_init(uint64_t s[25]) -+{ -+ unsigned int i; -+ for(i=0;i<25;i++) -+ s[i] = 0; -+} -+ -+/************************************************* -+* Name: shake256_init -+* -+* Description: Initilizes Keccak state for use as SHAKE256 XOF -+* -+* Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state -+**************************************************/ -+static void shake256_init(keccak_state *state) -+{ -+ keccak_init(state->s); -+ state->pos = 0; -+} -+ -+ -+/************************************************* -+* Name: shake256 -+* -+* Description: SHAKE256 XOF with non-incremental API -+* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: requested output length in bytes -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+static void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) -+{ -+ size_t nblocks; -+ keccak_state state; -+ -+ shake256_absorb_once(&state, in, inlen); -+ nblocks = outlen/SHAKE256_RATE; -+ shake256_squeezeblocks(out, nblocks, &state); -+ outlen -= nblocks*SHAKE256_RATE; -+ out += nblocks*SHAKE256_RATE; -+ shake256_squeeze(out, outlen, &state); -+} -+ -+/************************************************* -+* Name: sha3_256 -+* -+* Description: SHA3-256 with non-incremental API -+* -+* Arguments: - uint8_t *h: pointer to output (32 bytes) -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+static void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen) -+{ -+ unsigned int i; -+ uint64_t s[25]; -+ -+ keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); -+ KeccakF1600_StatePermute(s); -+ for(i=0;i<4;i++) -+ store64(h+8*i,s[i]); -+} -+ -+/************************************************* -+* Name: sha3_512 -+* -+* Description: SHA3-512 with non-incremental API -+* -+* Arguments: - uint8_t *h: pointer to output (64 bytes) -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+static void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen) -+{ -+ unsigned int i; -+ uint64_t s[25]; -+ -+ keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); -+ KeccakF1600_StatePermute(s); -+ for(i=0;i<8;i++) -+ store64(h+8*i,s[i]); -+} -+ -+// -+// symmetric-shake.c -+// -+ -+/************************************************* -+* Name: kyber_shake128_absorb -+* -+* Description: Absorb step of the SHAKE128 specialized for the Kyber context. -+* -+* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state -+* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state -+* - uint8_t i: additional byte of input -+* - uint8_t j: additional byte of input -+**************************************************/ -+static void kyber_shake128_absorb(keccak_state *state, -+ const uint8_t seed[KYBER_SYMBYTES], -+ uint8_t x, -+ uint8_t y) -+{ -+ uint8_t extseed[KYBER_SYMBYTES+2]; -+ -+ memcpy(extseed, seed, KYBER_SYMBYTES); -+ extseed[KYBER_SYMBYTES+0] = x; -+ extseed[KYBER_SYMBYTES+1] = y; -+ -+ shake128_absorb_once(state, extseed, sizeof(extseed)); - } - +-} +- -int KYBER_parse_public_key(struct KYBER_public_key *public_key, CBS *in) { - struct public_key *pub = public_key_from_external(public_key); - CBS orig_in = *in; - if (!kyber_parse_public_key_no_hash(pub, in) || // - CBS_len(in) != 0) { -+/************************************************* -+* Name: kyber_shake256_prf -+* -+* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input -+* and then generates outlen bytes of SHAKE256 output -+* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: number of requested output bytes -+* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES) -+* - uint8_t nonce: single-byte nonce (public PRF input) -+**************************************************/ -+static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce) -+{ -+ uint8_t extkey[KYBER_SYMBYTES+1]; -+ -+ memcpy(extkey, key, KYBER_SYMBYTES); -+ extkey[KYBER_SYMBYTES] = nonce; -+ -+ shake256(out, outlen, extkey, sizeof(extkey)); -+} -+ -+// -+// kem.c -+// -+ -+// Modified crypto_kem_keypair to BoringSSL style API -+void generate_key(struct public_key *out_pub, struct private_key *out_priv, -+ const uint8_t seed[KYBER_GENERATE_KEY_BYTES]) -+{ -+ size_t i; -+ uint8_t* pk = &out_pub->opaque[0]; -+ uint8_t* sk = &out_priv->opaque[0]; -+ -+ indcpa_keypair(pk, sk, seed); -+ for(i=0;iopaque[0]; -+ uint8_t *ct = out_ciphertext; -+ -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; -+ -+ memcpy(buf, seed, KYBER_SYMBYTES); -+ -+ /* Don't release system RNG output */ -+ hash_h(buf, buf, KYBER_SYMBYTES); -+ -+ /* Multitarget countermeasure for coins + contributory KEM */ -+ hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); -+ hash_g(kr, buf, 2*KYBER_SYMBYTES); -+ -+ /* coins are in kr+KYBER_SYMBYTES */ -+ if(!indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES)) - return 0; -+ -+ if (mlkem == 1) { -+ memcpy(ss, kr, KYBER_SYMBYTES); -+ } else { -+ /* overwrite coins in kr with H(c) */ -+ hash_h(kr+KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); -+ /* hash concatenation of pre-k and H(c) to k */ -+ kdf(ss, kr, 2*KYBER_SYMBYTES); - } +- return 0; +- } - BORINGSSL_keccak(pub->public_key_hash, sizeof(pub->public_key_hash), - CBS_data(&orig_in), CBS_len(&orig_in), boringssl_sha3_256); - return 1; - } - +- return 1; +-} +- -int KYBER_marshal_private_key(CBB *out, - const struct KYBER_private_key *private_key) { - const struct private_key *const priv = private_key_from_external(private_key); - uint8_t *s_output; - if (!CBB_add_space(out, &s_output, kEncodedVectorSize)) { - return 0; -+// Modified crypto_kem_decap to BoringSSL style API -+void decap(uint8_t out_shared_key[KYBER_SSBYTES], -+ const struct private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int mlkem) -+{ -+ uint8_t *ss = out_shared_key; -+ const uint8_t *sk = &in_priv->opaque[0]; -+ -+ size_t i; -+ int fail = 1; -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; -+ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; -+ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; -+ -+ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { -+ indcpa_dec(buf, ct, sk); -+ -+ /* Multitarget countermeasure for coins + contributory KEM */ -+ for(i=0;is, kLog2Prime); - if (!kyber_marshal_public_key(out, &priv->pub) || - !CBB_add_bytes(out, priv->pub.public_key_hash, @@ -3587,45 +3312,14 @@ index 776c085f9..ccb5b3d9b 100644 - !CBB_add_bytes(out, priv->fo_failure_secret, - sizeof(priv->fo_failure_secret))) { - return 0; -+ -+ if (mlkem == 1) { -+ /* Compute shared secret in case of rejection: ss2 = PRF(z || c). */ -+ uint8_t ss2[KYBER_SYMBYTES]; -+ keccak_state ks; -+ shake256_init(&ks); -+ shake256_absorb( -+ &ks, -+ sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, -+ KYBER_SYMBYTES -+ ); -+ shake256_absorb(&ks, ct, ciphertext_len); -+ shake256_finalize(&ks); -+ shake256_squeeze(ss2, KYBER_SYMBYTES, &ks); -+ -+ /* Set ss2 to the real shared secret if c = c' */ -+ cmov(ss2, kr, KYBER_SYMBYTES, 1-fail); -+ memcpy(ss, ss2, KYBER_SYMBYTES); -+ } else { -+ /* overwrite coins in kr with H(c) */ -+ hash_h(kr+KYBER_SYMBYTES, ct, ciphertext_len); -+ -+ /* Overwrite pre-k with z on re-encryption failure */ -+ cmov(kr, sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES, KYBER_SYMBYTES, fail); -+ -+ /* hash concatenation of pre-k and H(c) to k */ -+ kdf(ss, kr, 2*KYBER_SYMBYTES); - } +- } - return 1; - } - +-} +- -int KYBER_parse_private_key(struct KYBER_private_key *out_private_key, - CBS *in) { - struct private_key *const priv = private_key_from_external(out_private_key); -+void marshal_public_key(uint8_t out[KYBER_PUBLICKEYBYTES], -+ const struct public_key *in_pub) { -+ memcpy(out, &in_pub->opaque, KYBER_PUBLICKEYBYTES); -+} - +- - CBS s_bytes; - if (!CBS_get_bytes(in, &s_bytes, kEncodedVectorSize) || - !vector_decode(&priv->s, CBS_data(&s_bytes), kLog2Prime) || @@ -3642,33 +3336,33 @@ index 776c085f9..ccb5b3d9b 100644 + const uint8_t in[KYBER_PUBLICKEYBYTES]) { + memcpy(&out->opaque, in, KYBER_PUBLICKEYBYTES); } -diff --git a/src/crypto/kyber/kyber512.c b/src/crypto/kyber/kyber512.c +diff --git a/crypto/kyber/kyber512.c b/crypto/kyber/kyber512.c new file mode 100644 index 000000000..21eed11a2 --- /dev/null -+++ b/src/crypto/kyber/kyber512.c ++++ b/crypto/kyber/kyber512.c @@ -0,0 +1,5 @@ +#define KYBER_K 2 + +#include "kyber.c" + + -diff --git a/src/crypto/kyber/kyber768.c b/src/crypto/kyber/kyber768.c +diff --git a/crypto/kyber/kyber768.c b/crypto/kyber/kyber768.c new file mode 100644 index 000000000..3e572b72e --- /dev/null -+++ b/src/crypto/kyber/kyber768.c ++++ b/crypto/kyber/kyber768.c @@ -0,0 +1,4 @@ +#define KYBER_K 3 + +#include "kyber.c" + -diff --git a/src/crypto/kyber/kyber_test.cc b/src/crypto/kyber/kyber_test.cc +diff --git a/crypto/kyber/kyber_test.cc b/crypto/kyber/kyber_test.cc deleted file mode 100644 -index eb76b5bd7..000000000 ---- a/src/crypto/kyber/kyber_test.cc +index b9daa87d3..000000000 +--- a/crypto/kyber/kyber_test.cc +++ /dev/null -@@ -1,229 +0,0 @@ +@@ -1,184 +0,0 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -3695,55 +3389,10 @@ index eb76b5bd7..000000000 - -#include "../test/file_test.h" -#include "../test/test_util.h" +-#include "../keccak/internal.h" -#include "./internal.h" - - --static void KeccakFileTest(FileTest *t) { -- std::vector input, sha3_256_expected, sha3_512_expected, -- shake128_expected, shake256_expected; -- ASSERT_TRUE(t->GetBytes(&input, "Input")); -- ASSERT_TRUE(t->GetBytes(&sha3_256_expected, "SHA3-256")); -- ASSERT_TRUE(t->GetBytes(&sha3_512_expected, "SHA3-512")); -- ASSERT_TRUE(t->GetBytes(&shake128_expected, "SHAKE-128")); -- ASSERT_TRUE(t->GetBytes(&shake256_expected, "SHAKE-256")); -- -- uint8_t sha3_256_digest[32]; -- BORINGSSL_keccak(sha3_256_digest, sizeof(sha3_256_digest), input.data(), -- input.size(), boringssl_sha3_256); -- uint8_t sha3_512_digest[64]; -- BORINGSSL_keccak(sha3_512_digest, sizeof(sha3_512_digest), input.data(), -- input.size(), boringssl_sha3_512); -- uint8_t shake128_output[512]; -- BORINGSSL_keccak(shake128_output, sizeof(shake128_output), input.data(), -- input.size(), boringssl_shake128); -- uint8_t shake256_output[512]; -- BORINGSSL_keccak(shake256_output, sizeof(shake256_output), input.data(), -- input.size(), boringssl_shake256); -- -- EXPECT_EQ(Bytes(sha3_256_expected), Bytes(sha3_256_digest)); -- EXPECT_EQ(Bytes(sha3_512_expected), Bytes(sha3_512_digest)); -- EXPECT_EQ(Bytes(shake128_expected), Bytes(shake128_output)); -- EXPECT_EQ(Bytes(shake256_expected), Bytes(shake256_output)); -- -- struct BORINGSSL_keccak_st ctx; -- -- BORINGSSL_keccak_init(&ctx, input.data(), input.size(), boringssl_shake128); -- for (size_t i = 0; i < sizeof(shake128_output); i++) { -- BORINGSSL_keccak_squeeze(&ctx, &shake128_output[i], 1); -- } -- EXPECT_EQ(Bytes(shake128_expected), Bytes(shake128_output)); -- -- BORINGSSL_keccak_init(&ctx, input.data(), input.size(), boringssl_shake256); -- for (size_t i = 0; i < sizeof(shake256_output); i++) { -- BORINGSSL_keccak_squeeze(&ctx, &shake256_output[i], 1); -- } -- EXPECT_EQ(Bytes(shake256_expected), Bytes(shake256_output)); --} -- --TEST(KyberTest, KeccakTestVectors) { -- FileTestGTest("crypto/kyber/keccak_tests.txt", KeccakFileTest); --} -- -template -static std::vector Marshal(int (*marshal_func)(CBB *, const T *), - const T *t) { @@ -3898,10 +3547,10 @@ index eb76b5bd7..000000000 -TEST(KyberTest, TestVectors) { - FileTestGTest("crypto/kyber/kyber_tests.txt", KyberFileTest); -} -diff --git a/src/crypto/obj/obj_dat.h b/src/crypto/obj/obj_dat.h -index 654b3c08e..6cef2c079 100644 ---- a/src/crypto/obj/obj_dat.h -+++ b/src/crypto/obj/obj_dat.h +diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h +index 71ef2d2bd..74b99b098 100644 +--- a/crypto/obj/obj_dat.h ++++ b/crypto/obj/obj_dat.h @@ -57,7 +57,7 @@ /* This file is generated by crypto/obj/objects.go. */ @@ -3911,7 +3560,7 @@ index 654b3c08e..6cef2c079 100644 static const uint8_t kObjectData[] = { /* NID_rsadsi */ -@@ -8784,6 +8784,13 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { +@@ -8783,6 +8783,13 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { {"HKDF", "hkdf", NID_hkdf, 0, NULL, 0}, {"X25519Kyber768Draft00", "X25519Kyber768Draft00", NID_X25519Kyber768Draft00, 0, NULL, 0}, @@ -3925,7 +3574,7 @@ index 654b3c08e..6cef2c079 100644 }; static const uint16_t kNIDsInShortNameOrder[] = { -@@ -8916,6 +8923,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8915,6 +8922,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 18 /* OU */, 749 /* Oakley-EC2N-3 */, 750 /* Oakley-EC2N-4 */, @@ -3933,9 +3582,9 @@ index 654b3c08e..6cef2c079 100644 9 /* PBE-MD2-DES */, 168 /* PBE-MD2-RC2-64 */, 10 /* PBE-MD5-DES */, -@@ -8982,7 +8990,10 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8980,7 +8988,10 @@ static const uint16_t kNIDsInShortNameOrder[] = { + 143 /* SXNetID */, 458 /* UID */, - 0 /* UNDEF */, 948 /* X25519 */, + 965 /* X25519Kyber512Draft00 */, 964 /* X25519Kyber768Draft00 */, @@ -3944,7 +3593,7 @@ index 654b3c08e..6cef2c079 100644 961 /* X448 */, 11 /* X500 */, 378 /* X500algorithms */, -@@ -9829,6 +9840,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9827,6 +9838,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 366 /* OCSP Nonce */, 371 /* OCSP Service Locator */, 180 /* OCSP Signing */, @@ -3952,7 +3601,7 @@ index 654b3c08e..6cef2c079 100644 161 /* PBES2 */, 69 /* PBKDF2 */, 162 /* PBMAC1 */, -@@ -9853,7 +9865,10 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9851,7 +9863,10 @@ static const uint16_t kNIDsInLongNameOrder[] = { 133 /* Time Stamping */, 375 /* Trust Root */, 948 /* X25519 */, @@ -3963,10 +3612,10 @@ index 654b3c08e..6cef2c079 100644 961 /* X448 */, 12 /* X509 */, 402 /* X509v3 AC Targeting */, -diff --git a/src/crypto/obj/obj_mac.num b/src/crypto/obj/obj_mac.num +diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num index a0519acee..2a46adfe8 100644 ---- a/src/crypto/obj/obj_mac.num -+++ b/src/crypto/obj/obj_mac.num +--- a/crypto/obj/obj_mac.num ++++ b/crypto/obj/obj_mac.num @@ -952,3 +952,7 @@ X448 961 sha512_256 962 hkdf 963 @@ -3975,10 +3624,10 @@ index a0519acee..2a46adfe8 100644 +P256Kyber768Draft00 966 +X25519Kyber768Draft00Old 967 +X25519MLKEM768 968 -diff --git a/src/crypto/obj/objects.txt b/src/crypto/obj/objects.txt +diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt index 3ad32ea3d..347fc556a 100644 ---- a/src/crypto/obj/objects.txt -+++ b/src/crypto/obj/objects.txt +--- a/crypto/obj/objects.txt ++++ b/crypto/obj/objects.txt @@ -1332,8 +1332,12 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme : dh-std-kdf : dh-cofactor-kdf @@ -3993,10 +3642,10 @@ index 3ad32ea3d..347fc556a 100644 # See RFC 8410. 1 3 101 110 : X25519 -diff --git a/src/include/openssl/kyber.h b/src/include/openssl/kyber.h +diff --git a/include/openssl/kyber.h b/include/openssl/kyber.h index cafae9d17..a05eb8957 100644 ---- a/src/include/openssl/kyber.h -+++ b/src/include/openssl/kyber.h +--- a/include/openssl/kyber.h ++++ b/include/openssl/kyber.h @@ -1,17 +1,3 @@ -/* Copyright (c) 2023, Google Inc. - * @@ -4038,15 +3687,7 @@ index cafae9d17..a05eb8957 100644 - } opaque; +struct KYBER512_private_key { + uint8_t opaque[KYBER512_PRIVATE_KEY_BYTES]; - }; -- --// KYBER_private_key contains a Kyber768 private key. The contents of this --// object should never leave the address space since the format is unstable. --struct KYBER_private_key { -- union { -- uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; -- uint16_t alignment; -- } opaque; ++}; +struct KYBER768_private_key { + uint8_t opaque[KYBER768_PRIVATE_KEY_BYTES]; +}; @@ -4057,17 +3698,34 @@ index cafae9d17..a05eb8957 100644 + uint8_t opaque[KYBER768_PUBLIC_KEY_BYTES]; }; +-// KYBER_private_key contains a Kyber768 private key. The contents of this +-// object should never leave the address space since the format is unstable. +-struct KYBER_private_key { +- union { +- uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; +- uint16_t alignment; +- } opaque; +-}; ++// KYBER_GENERATE_KEY_BYTES is the number of bytes of entropy needed to ++// generate a keypair. ++#define KYBER_GENERATE_KEY_BYTES 64 + -// KYBER_PUBLIC_KEY_BYTES is the number of bytes in an encoded Kyber768 public -// key. -#define KYBER_PUBLIC_KEY_BYTES 1184 -- ++// KYBER_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a ++// session key. ++#define KYBER_ENCAP_BYTES 32 + -// KYBER_generate_key generates a random public/private key pair, writes the -// encoded public key to |out_encoded_public_key| and sets |out_private_key| to -// the private key. -OPENSSL_EXPORT void KYBER_generate_key( - uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], - struct KYBER_private_key *out_private_key); -- ++// KYBER_KEY_BYTES is the number of bytes in a shared key. ++#define KYBER_KEY_BYTES 32 + -// KYBER_public_from_private sets |*out_public_key| to the public key that -// corresponds to |private_key|. (This is faster than parsing the output of -// |KYBER_generate_key| if, for some reason, you need to encapsulate to a key @@ -4075,10 +3733,20 @@ index cafae9d17..a05eb8957 100644 -OPENSSL_EXPORT void KYBER_public_from_private( - struct KYBER_public_key *out_public_key, - const struct KYBER_private_key *private_key); -- ++// KYBER512_generate_key is a deterministic function that outputs a public and ++// private key based on the given entropy. ++OPENSSL_EXPORT void KYBER512_generate_key( ++ struct KYBER512_public_key *out_pub, struct KYBER512_private_key *out_priv, ++ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); + -// KYBER_CIPHERTEXT_BYTES is number of bytes in the Kyber768 ciphertext. -#define KYBER_CIPHERTEXT_BYTES 1088 -- ++// KYBER768_generate_key is a deterministic function that outputs a public and ++// private key based on the given entropy. ++OPENSSL_EXPORT void KYBER768_generate_key( ++ struct KYBER768_public_key *out_pub, struct KYBER768_private_key *out_priv, ++ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); + -// KYBER_encap encrypts a random secret key of length |out_shared_secret_len| to -// |public_key|, writes the ciphertext to |ciphertext|, and writes the random -// key to |out_shared_secret|. The party calling |KYBER_decap| must already know @@ -4087,7 +3755,15 @@ index cafae9d17..a05eb8957 100644 - uint8_t *out_shared_secret, - size_t out_shared_secret_len, - const struct KYBER_public_key *public_key); -- ++// KYBER512_encap is a deterministic function the generates and encrypts a random ++// session key from the given entropy, writing those values to |out_shared_key| ++// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-512. ++OPENSSL_EXPORT int KYBER512_encap(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], ++ uint8_t out_shared_key[KYBER_KEY_BYTES], ++ const struct KYBER512_public_key *in_pub, ++ const uint8_t in[KYBER_ENCAP_BYTES], ++ int mlkem); + -// KYBER_decap decrypts a key of length |out_shared_secret_len| from -// |ciphertext| using |private_key| and writes it to |out_shared_secret|. If -// |ciphertext| is invalid, |out_shared_secret| is filled with a key that @@ -4100,23 +3776,57 @@ index cafae9d17..a05eb8957 100644 - uint8_t *out_shared_secret, size_t out_shared_secret_len, - const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES], - const struct KYBER_private_key *private_key); -- -- ++// KYBER768_encap is a deterministic function the generates and encrypts a random ++// session key from the given entropy, writing those values to |out_shared_key| ++// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-768. ++OPENSSL_EXPORT int KYBER768_encap(uint8_t out_ciphertext[KYBER768_CIPHERTEXT_BYTES], ++ uint8_t out_shared_key[KYBER_KEY_BYTES], ++ const struct KYBER768_public_key *in_pub, ++ const uint8_t in[KYBER_ENCAP_BYTES], ++ int mlkem); + ++// KYBER_decap decrypts a session key from |ciphertext_len| bytes of ++// |ciphertext|. If the ciphertext is valid, the decrypted key is written to ++// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept ++// in |in_priv|) is written. If the ciphertext is the wrong length then it will ++// leak which was done via side-channels. Otherwise it should perform either ++// action in constant-time. If |mlkem| is 1, will use ML-KEM-512. ++OPENSSL_EXPORT void KYBER512_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], ++ const struct KYBER512_private_key *in_priv, ++ const uint8_t *ciphertext, size_t ciphertext_len, ++ int mlkem); + -// Serialisation of keys. -- ++// KYBER_decap decrypts a session key from |ciphertext_len| bytes of ++// |ciphertext|. If the ciphertext is valid, the decrypted key is written to ++// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept ++// in |in_priv|) is written. If the ciphertext is the wrong length then it will ++// leak which was done via side-channels. Otherwise it should perform either ++// action in constant-time. If |mlkem| is 1, will use ML-KEM-768. ++OPENSSL_EXPORT void KYBER768_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], ++ const struct KYBER768_private_key *in_priv, ++ const uint8_t *ciphertext, size_t ciphertext_len, ++ int mlkem); + -// KYBER_marshal_public_key serializes |public_key| to |out| in the standard -// format for Kyber public keys. It returns one on success or zero on allocation -// error. -OPENSSL_EXPORT int KYBER_marshal_public_key( - CBB *out, const struct KYBER_public_key *public_key); -- ++// KYBER512_marshal_public_key serialises |in_pub| to |out|. ++OPENSSL_EXPORT void KYBER512_marshal_public_key( ++ uint8_t out[KYBER512_PUBLIC_KEY_BYTES], const struct KYBER512_public_key *in_pub); + -// KYBER_parse_public_key parses a public key, in the format generated by -// |KYBER_marshal_public_key|, from |in| and writes the result to -// |out_public_key|. It returns one on success or zero on parse error or if -// there are trailing bytes in |in|. -OPENSSL_EXPORT int KYBER_parse_public_key( - struct KYBER_public_key *out_public_key, CBS *in); -- ++// KYBER768_marshal_public_key serialises |in_pub| to |out|. ++OPENSSL_EXPORT void KYBER768_marshal_public_key( ++ uint8_t out[KYBER768_PUBLIC_KEY_BYTES], const struct KYBER768_public_key *in_pub); + -// KYBER_marshal_private_key serializes |private_key| to |out| in the standard -// format for Kyber private keys. It returns one on success or zero on -// allocation error. @@ -4133,92 +3843,20 @@ index cafae9d17..a05eb8957 100644 -// there are trailing bytes in |in|. -OPENSSL_EXPORT int KYBER_parse_private_key( - struct KYBER_private_key *out_private_key, CBS *in); -- -+// KYBER_GENERATE_KEY_BYTES is the number of bytes of entropy needed to -+// generate a keypair. -+#define KYBER_GENERATE_KEY_BYTES 64 -+ -+// KYBER_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a -+// session key. -+#define KYBER_ENCAP_BYTES 32 -+ -+// KYBER_KEY_BYTES is the number of bytes in a shared key. -+#define KYBER_KEY_BYTES 32 -+ -+// KYBER512_generate_key is a deterministic function that outputs a public and -+// private key based on the given entropy. -+OPENSSL_EXPORT void KYBER512_generate_key( -+ struct KYBER512_public_key *out_pub, struct KYBER512_private_key *out_priv, -+ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); -+ -+// KYBER768_generate_key is a deterministic function that outputs a public and -+// private key based on the given entropy. -+OPENSSL_EXPORT void KYBER768_generate_key( -+ struct KYBER768_public_key *out_pub, struct KYBER768_private_key *out_priv, -+ const uint8_t input[KYBER_GENERATE_KEY_BYTES]); -+ -+// KYBER512_encap is a deterministic function the generates and encrypts a random -+// session key from the given entropy, writing those values to |out_shared_key| -+// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-512. -+OPENSSL_EXPORT int KYBER512_encap(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], -+ uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER512_public_key *in_pub, -+ const uint8_t in[KYBER_ENCAP_BYTES], -+ int mlkem); -+ -+// KYBER768_encap is a deterministic function the generates and encrypts a random -+// session key from the given entropy, writing those values to |out_shared_key| -+// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-768. -+OPENSSL_EXPORT int KYBER768_encap(uint8_t out_ciphertext[KYBER768_CIPHERTEXT_BYTES], -+ uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER768_public_key *in_pub, -+ const uint8_t in[KYBER_ENCAP_BYTES], -+ int mlkem); -+ -+// KYBER_decap decrypts a session key from |ciphertext_len| bytes of -+// |ciphertext|. If the ciphertext is valid, the decrypted key is written to -+// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept -+// in |in_priv|) is written. If the ciphertext is the wrong length then it will -+// leak which was done via side-channels. Otherwise it should perform either -+// action in constant-time. If |mlkem| is 1, will use ML-KEM-512. -+OPENSSL_EXPORT void KYBER512_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER512_private_key *in_priv, -+ const uint8_t *ciphertext, size_t ciphertext_len, -+ int mlkem); -+ -+// KYBER_decap decrypts a session key from |ciphertext_len| bytes of -+// |ciphertext|. If the ciphertext is valid, the decrypted key is written to -+// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept -+// in |in_priv|) is written. If the ciphertext is the wrong length then it will -+// leak which was done via side-channels. Otherwise it should perform either -+// action in constant-time. If |mlkem| is 1, will use ML-KEM-768. -+OPENSSL_EXPORT void KYBER768_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER768_private_key *in_priv, -+ const uint8_t *ciphertext, size_t ciphertext_len, -+ int mlkem); -+ -+// KYBER512_marshal_public_key serialises |in_pub| to |out|. -+OPENSSL_EXPORT void KYBER512_marshal_public_key( -+ uint8_t out[KYBER512_PUBLIC_KEY_BYTES], const struct KYBER512_public_key *in_pub); -+ -+// KYBER768_marshal_public_key serialises |in_pub| to |out|. -+OPENSSL_EXPORT void KYBER768_marshal_public_key( -+ uint8_t out[KYBER768_PUBLIC_KEY_BYTES], const struct KYBER768_public_key *in_pub); -+ +// KYBER512_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER512_parse_public_key( + struct KYBER512_public_key *out, const uint8_t in[KYBER512_PUBLIC_KEY_BYTES]); -+ + +// KYBER768_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER768_parse_public_key( + struct KYBER768_public_key *out, const uint8_t in[KYBER768_PUBLIC_KEY_BYTES]); #if defined(__cplusplus) } // extern C -diff --git a/src/include/openssl/nid.h b/src/include/openssl/nid.h +diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 4dd8841b1..5b102c610 100644 ---- a/src/include/openssl/nid.h -+++ b/src/include/openssl/nid.h +--- a/include/openssl/nid.h ++++ b/include/openssl/nid.h @@ -4255,6 +4255,18 @@ extern "C" { #define SN_X25519Kyber768Draft00 "X25519Kyber768Draft00" #define NID_X25519Kyber768Draft00 964 @@ -4238,53 +3876,60 @@ index 4dd8841b1..5b102c610 100644 #if defined(__cplusplus) } /* extern C */ -diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..f9683f4cf 100644 ---- a/src/include/openssl/ssl.h -+++ b/src/include/openssl/ssl.h -@@ -2378,6 +2378,10 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); - #define SSL_CURVE_SECP521R1 25 - #define SSL_CURVE_X25519 29 - #define SSL_CURVE_X25519_KYBER768_DRAFT00 0x6399 -+#define SSL_CURVE_X25519_KYBER512_DRAFT00 0xfe30 -+#define SSL_CURVE_X25519_KYBER768_DRAFT00_OLD 0xfe31 -+#define SSL_CURVE_P256_KYBER768_DRAFT00 0xfe32 -+#define SSL_CURVE_X25519_MLKEM768 0x11ec +diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h +index 003e0a5f7..884685ba9 100644 +--- a/include/openssl/ssl.h ++++ b/include/openssl/ssl.h +@@ -2363,6 +2363,10 @@ OPENSSL_EXPORT size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx); + #define SSL_GROUP_SECP521R1 25 + #define SSL_GROUP_X25519 29 + #define SSL_GROUP_X25519_KYBER768_DRAFT00 0x6399 ++#define SSL_GROUP_X25519_KYBER512_DRAFT00 0xfe30 ++#define SSL_GROUP_X25519_KYBER768_DRAFT00_OLD 0xfe31 ++#define SSL_GROUP_P256_KYBER768_DRAFT00 0xfe32 ++#define SSL_GROUP_X25519_MLKEM768 0x11ec - // SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently - // completed handshake or 0 if not applicable. -diff --git a/src/sources.cmake b/src/sources.cmake -index 5c7e881bf..3c0770cf3 100644 ---- a/src/sources.cmake -+++ b/src/sources.cmake -@@ -66,8 +66,6 @@ set( - crypto/fipsmodule/rand/ctrdrbg_vectors.txt + // SSL_CTX_set1_group_ids sets the preferred groups for |ctx| to |group_ids|. + // Each element of |group_ids| should be one of the |SSL_GROUP_*| constants. It +diff --git a/sources.cmake b/sources.cmake +index ba2f5bc9e..d7ef5153a 100644 +--- a/sources.cmake ++++ b/sources.cmake +@@ -52,7 +52,6 @@ set( + crypto/hrss/hrss_test.cc + crypto/impl_dispatch_test.cc + crypto/keccak/keccak_test.cc +- crypto/kyber/kyber_test.cc + crypto/lhash/lhash_test.cc + crypto/obj/obj_test.cc + crypto/pem/pem_test.cc +@@ -145,7 +144,6 @@ set( crypto/hmac_extra/hmac_tests.txt crypto/hpke/hpke_test_vectors.txt -- crypto/kyber/keccak_tests.txt + crypto/keccak/keccak_tests.txt - crypto/kyber/kyber_tests.txt crypto/pkcs8/test/empty_password.p12 crypto/pkcs8/test/no_encryption.p12 crypto/pkcs8/test/nss.p12 -diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..aae3e6a7f 100644 ---- a/src/ssl/extensions.cc -+++ b/src/ssl/extensions.cc +diff --git a/ssl/extensions.cc b/ssl/extensions.cc +index b13400097..4655b1881 100644 +--- a/ssl/extensions.cc ++++ b/ssl/extensions.cc @@ -207,6 +207,10 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { static bool is_post_quantum_group(uint16_t id) { switch (id) { - case SSL_CURVE_X25519_KYBER768_DRAFT00: -+ case SSL_CURVE_X25519_KYBER768_DRAFT00_OLD: -+ case SSL_CURVE_X25519_KYBER512_DRAFT00: -+ case SSL_CURVE_P256_KYBER768_DRAFT00: -+ case SSL_CURVE_X25519_MLKEM768: + case SSL_GROUP_X25519_KYBER768_DRAFT00: ++ case SSL_GROUP_X25519_KYBER768_DRAFT00_OLD: ++ case SSL_GROUP_X25519_KYBER512_DRAFT00: ++ case SSL_GROUP_P256_KYBER768_DRAFT00: ++ case SSL_GROUP_X25519_MLKEM768: return true; default: return false; -diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc -index 09a9ad380..d7a8f0a80 100644 ---- a/src/ssl/ssl_key_share.cc -+++ b/src/ssl/ssl_key_share.cc +diff --git a/ssl/ssl_key_share.cc b/ssl/ssl_key_share.cc +index 694bec11d..3e4d2e7c4 100644 +--- a/ssl/ssl_key_share.cc ++++ b/ssl/ssl_key_share.cc @@ -26,6 +26,7 @@ #include #include @@ -4293,7 +3938,7 @@ index 09a9ad380..d7a8f0a80 100644 #include #include #include -@@ -193,63 +194,292 @@ class X25519KeyShare : public SSLKeyShare { +@@ -191,63 +192,145 @@ class X25519KeyShare : public SSLKeyShare { uint8_t private_key_[32]; }; @@ -4302,18 +3947,27 @@ index 09a9ad380..d7a8f0a80 100644 public: - X25519Kyber768KeyShare() {} + P256Kyber768Draft00KeyShare() {} -+ -+ uint16_t GroupID() const override { return SSL_CURVE_P256_KYBER768_DRAFT00; } -+ -+ bool Generate(CBB *out) override { + +- uint16_t GroupID() const override { +- return SSL_GROUP_X25519_KYBER768_DRAFT00; +- } ++ uint16_t GroupID() const override { return SSL_GROUP_P256_KYBER768_DRAFT00; } + + bool Generate(CBB *out) override { +- uint8_t x25519_public_key[32]; +- X25519_keypair(x25519_public_key, x25519_private_key_); + assert(!p256_private_key_); -+ + +- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(kyber_public_key, &kyber_private_key_); + // Set up a shared |BN_CTX| for P-256 operations. + UniquePtr bn_ctx(BN_CTX_new()); + if (!bn_ctx) { + return false; + } -+ + +- if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || +- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { + BN_CTXScope scope(bn_ctx.get()); + + // Generate a P-256 private key. @@ -4345,33 +3999,58 @@ index 09a9ad380..d7a8f0a80 100644 + + uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; + KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); - -- uint16_t GroupID() const override { -- return SSL_CURVE_X25519_KYBER768_DRAFT00; ++ + if (!CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { -+ return false; -+ } -+ -+ return true; + return false; + } + + return true; } +- bool Encap(CBB *out_ciphertext, Array *out_secret, +- uint8_t *out_alert, Span peer_key) override { +- Array secret; +- if (!secret.Init(32 + 32)) { +- return false; +- } + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { + assert(!p256_private_key_); -+ + +- uint8_t x25519_public_key[32]; +- X25519_keypair(x25519_public_key, x25519_private_key_); +- KYBER_public_key peer_kyber_pub; +- CBS peer_key_cbs; +- CBS peer_x25519_cbs; +- CBS peer_kyber_cbs; +- CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size()); +- if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) || +- !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs, +- KYBER_PUBLIC_KEY_BYTES) || +- CBS_len(&peer_key_cbs) != 0 || +- !X25519(secret.data(), x25519_private_key_, +- CBS_data(&peer_x25519_cbs)) || +- !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) { + if (peer_key.size() != 65 + KYBER768_PUBLIC_KEY_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); + return false; + } + +- uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES]; +- KYBER_encap(kyber_ciphertext, secret.data() + 32, secret.size() - 32, +- &peer_kyber_pub); + // Set up a shared |BN_CTX| for P-256 operations. + UniquePtr bn_ctx(BN_CTX_new()); + if (!bn_ctx) { + return false; + } -+ + +- if (!CBB_add_bytes(out_ciphertext, x25519_public_key, +- sizeof(x25519_public_key)) || +- !CBB_add_bytes(out_ciphertext, kyber_ciphertext, +- sizeof(kyber_ciphertext))) { + BN_CTXScope scope(bn_ctx.get()); + + UniquePtr group; @@ -4440,30 +4119,35 @@ index 09a9ad380..d7a8f0a80 100644 + return false; + } + if(!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { -+ return false; -+ } -+ -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ bool Decap(Array *out_secret, uint8_t *out_alert, + return false; + } + +@@ -256,30 +339,380 @@ class X25519Kyber768KeyShare : public SSLKeyShare { + } + + bool Decap(Array *out_secret, uint8_t *out_alert, +- Span ciphertext) override { + Span peer_key) override { + assert(p256_private_key_); -+ *out_alert = SSL_AD_INTERNAL_ERROR; -+ -+ Array secret; + *out_alert = SSL_AD_INTERNAL_ERROR; + + Array secret; +- if (!secret.Init(32 + 32)) { + if (!secret.Init(32 + KYBER_KEY_BYTES)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ + return false; + } + +- if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES || +- !X25519(secret.data(), x25519_private_key_, ciphertext.data())) { + if (peer_key.size() != 65 + KYBER768_CIPHERTEXT_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); + return false; + } + +- KYBER_decap(secret.data() + 32, secret.size() - 32, ciphertext.data() + 32, +- &kyber_private_key_); + // Set up a shared |BN_CTX| for P-256 operations. + UniquePtr bn_ctx(BN_CTX_new()); + if (!bn_ctx) { @@ -4523,18 +4207,16 @@ index 09a9ad380..d7a8f0a80 100644 +class X25519Kyber768Draft00KeyShare : public SSLKeyShare { + public: + X25519Kyber768Draft00KeyShare(uint16_t group_id) : group_id_(group_id) { -+ assert(group_id == SSL_CURVE_X25519_KYBER768_DRAFT00 -+ || group_id == SSL_CURVE_X25519_KYBER768_DRAFT00_OLD); ++ assert(group_id == SSL_GROUP_X25519_KYBER768_DRAFT00 ++ || group_id == SSL_GROUP_X25519_KYBER768_DRAFT00_OLD); + } + + uint16_t GroupID() const override { return group_id_; } + - bool Generate(CBB *out) override { - uint8_t x25519_public_key[32]; - X25519_keypair(x25519_public_key, x25519_private_key_); - -- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; -- KYBER_generate_key(kyber_public_key, &kyber_private_key_); ++ bool Generate(CBB *out) override { ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ + uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; + KYBER768_public_key kyber_public_key; + RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); @@ -4542,42 +4224,26 @@ index 09a9ad380..d7a8f0a80 100644 + + uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; + KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); - - if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || -- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { ++ ++ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || + !CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { - return false; - } - - return true; - } - -- bool Encap(CBB *out_ciphertext, Array *out_secret, -- uint8_t *out_alert, Span peer_key) override { ++ return false; ++ } ++ ++ return true; ++ } ++ + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { - Array secret; -- if (!secret.Init(32 + 32)) { ++ Array secret; + if (!secret.Init(32 + KYBER_KEY_BYTES)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return false; - } - - uint8_t x25519_public_key[32]; - X25519_keypair(x25519_public_key, x25519_private_key_); -- KYBER_public_key peer_kyber_pub; -- CBS peer_key_cbs; -- CBS peer_x25519_cbs; -- CBS peer_kyber_cbs; -- CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size()); -- if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) || -- !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs, -- KYBER_PUBLIC_KEY_BYTES) || -- CBS_len(&peer_key_cbs) != 0 || -- !X25519(secret.data(), x25519_private_key_, -- CBS_data(&peer_x25519_cbs)) || -- !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) { ++ return false; ++ } ++ ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); + + KYBER768_public_key peer_public_key; + if (peer_key.size() != 32 + KYBER768_PUBLIC_KEY_BYTES) { @@ -4589,36 +4255,30 @@ index 09a9ad380..d7a8f0a80 100644 + KYBER768_parse_public_key(&peer_public_key, peer_key.data() + 32); + + if (!X25519(secret.data(), x25519_private_key_, peer_key.data())) { - *out_alert = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); - return false; - } - -- uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES]; -- KYBER_encap(kyber_ciphertext, secret.data() + 32, secret.size() - 32, -- &peer_kyber_pub); ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ + uint8_t ciphertext[KYBER768_CIPHERTEXT_BYTES]; + uint8_t entropy[KYBER_ENCAP_BYTES]; + RAND_bytes(entropy, sizeof(entropy)); - -- if (!CBB_add_bytes(out_ciphertext, x25519_public_key, ++ + if(!KYBER768_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy, 0)) { + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return false; + } + if(!CBB_add_bytes(out_public_key, x25519_public_key, - sizeof(x25519_public_key)) || -- !CBB_add_bytes(out_ciphertext, kyber_ciphertext, -- sizeof(kyber_ciphertext))) { ++ sizeof(x25519_public_key)) || + !CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { - return false; - } - -@@ -258,30 +488,233 @@ class X25519Kyber768KeyShare : public SSLKeyShare { - } - - bool Decap(Array *out_secret, uint8_t *out_alert, -- Span ciphertext) override { ++ return false; ++ } ++ ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ bool Decap(Array *out_secret, uint8_t *out_alert, + Span peer_key) override { + *out_alert = SSL_AD_INTERNAL_ERROR; + @@ -4638,12 +4298,13 @@ index 09a9ad380..d7a8f0a80 100644 + KYBER768_decap(secret.data() + 32, &kyber_private_key_, + peer_key.data() + 32, peer_key.size() - 32, 0); + -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ private: -+ uint8_t x25519_private_key_[32]; + *out_secret = std::move(secret); + return true; + } + + private: + uint8_t x25519_private_key_[32]; +- KYBER_private_key kyber_private_key_; + KYBER768_private_key kyber_private_key_; + uint16_t group_id_; +}; @@ -4652,7 +4313,7 @@ index 09a9ad380..d7a8f0a80 100644 + public: + X25519MLKEM768KeyShare() {} + -+ uint16_t GroupID() const override { return SSL_CURVE_X25519_MLKEM768; } ++ uint16_t GroupID() const override { return SSL_GROUP_X25519_MLKEM768; } + + bool Generate(CBB *out) override { + uint8_t x25519_public_key[32]; @@ -4720,27 +4381,22 @@ index 09a9ad380..d7a8f0a80 100644 + + bool Decap(Array *out_secret, uint8_t *out_alert, + Span peer_key) override { - *out_alert = SSL_AD_INTERNAL_ERROR; - - Array secret; -- if (!secret.Init(32 + 32)) { ++ *out_alert = SSL_AD_INTERNAL_ERROR; ++ ++ Array secret; + if (!secret.Init(32 + KYBER_KEY_BYTES)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return false; - } - -- if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES || -- !X25519(secret.data(), x25519_private_key_, ciphertext.data())) { ++ return false; ++ } ++ + if (peer_key.size() != KYBER768_CIPHERTEXT_BYTES + 32 || + !X25519(secret.data() + 32, x25519_private_key_, + peer_key.data() + KYBER768_CIPHERTEXT_BYTES )) { - *out_alert = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); - return false; - } - -- KYBER_decap(secret.data() + 32, secret.size() - 32, ciphertext.data() + 32, -- &kyber_private_key_); ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ + KYBER768_decap(secret.data(), &kyber_private_key_, + peer_key.data(), peer_key.size() - 32, 1); + @@ -4757,7 +4413,7 @@ index 09a9ad380..d7a8f0a80 100644 + public: + X25519Kyber512Draft00KeyShare() {} + -+ uint16_t GroupID() const override { return SSL_CURVE_X25519_KYBER512_DRAFT00; } ++ uint16_t GroupID() const override { return SSL_GROUP_X25519_KYBER512_DRAFT00; } + + bool Generate(CBB *out) override { + uint8_t x25519_public_key[32]; @@ -4844,113 +4500,112 @@ index 09a9ad380..d7a8f0a80 100644 + KYBER512_decap(secret.data() + 32, &kyber_private_key_, + peer_key.data() + 32, peer_key.size() - 32, 0); + - *out_secret = std::move(secret); - return true; - } - - private: - uint8_t x25519_private_key_[32]; -- KYBER_private_key kyber_private_key_; ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ private: ++ uint8_t x25519_private_key_[32]; + KYBER512_private_key kyber_private_key_; }; constexpr NamedGroup kNamedGroups[] = { -@@ -290,8 +723,16 @@ constexpr NamedGroup kNamedGroups[] = { - {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, - {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, - {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, -+ {NID_X25519Kyber512Draft00, SSL_CURVE_X25519_KYBER512_DRAFT00, +@@ -288,8 +721,16 @@ constexpr NamedGroup kNamedGroups[] = { + {NID_secp384r1, SSL_GROUP_SECP384R1, "P-384", "secp384r1"}, + {NID_secp521r1, SSL_GROUP_SECP521R1, "P-521", "secp521r1"}, + {NID_X25519, SSL_GROUP_X25519, "X25519", "x25519"}, ++ {NID_X25519Kyber512Draft00, SSL_GROUP_X25519_KYBER512_DRAFT00, + "X25519Kyber512Draft00", "Xyber512D00"}, - {NID_X25519Kyber768Draft00, SSL_CURVE_X25519_KYBER768_DRAFT00, + {NID_X25519Kyber768Draft00, SSL_GROUP_X25519_KYBER768_DRAFT00, - "X25519Kyber768Draft00", ""}, + "X25519Kyber768Draft00", "Xyber768D00"}, -+ {NID_X25519Kyber768Draft00Old, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD, ++ {NID_X25519Kyber768Draft00Old, SSL_GROUP_X25519_KYBER768_DRAFT00_OLD, + "X25519Kyber768Draft00Old", "Xyber768D00Old"}, -+ {NID_P256Kyber768Draft00, SSL_CURVE_P256_KYBER768_DRAFT00, ++ {NID_P256Kyber768Draft00, SSL_GROUP_P256_KYBER768_DRAFT00, + "P256Kyber768Draft00", "P256Kyber768D00"}, -+ {NID_X25519MLKEM768, SSL_CURVE_X25519_MLKEM768, ++ {NID_X25519MLKEM768, SSL_GROUP_X25519_MLKEM768, + "X25519MLKEM768", "X25519MLKEM768"} }; } // namespace -@@ -312,8 +753,18 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { - return MakeUnique(NID_secp521r1, SSL_CURVE_SECP521R1); - case SSL_CURVE_X25519: +@@ -310,8 +751,18 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { + return MakeUnique(EC_group_p521(), SSL_GROUP_SECP521R1); + case SSL_GROUP_X25519: return MakeUnique(); -+ case SSL_CURVE_X25519_KYBER512_DRAFT00: ++ case SSL_GROUP_X25519_KYBER512_DRAFT00: + return UniquePtr(New()); - case SSL_CURVE_X25519_KYBER768_DRAFT00: + case SSL_GROUP_X25519_KYBER768_DRAFT00: - return MakeUnique(); + return UniquePtr(New( + group_id)); -+ case SSL_CURVE_X25519_KYBER768_DRAFT00_OLD: ++ case SSL_GROUP_X25519_KYBER768_DRAFT00_OLD: + return UniquePtr(New( + group_id)); -+ case SSL_CURVE_P256_KYBER768_DRAFT00: ++ case SSL_GROUP_P256_KYBER768_DRAFT00: + return UniquePtr(New()); -+ case SSL_CURVE_X25519_MLKEM768: ++ case SSL_GROUP_X25519_MLKEM768: + return UniquePtr(New()); default: return nullptr; } -diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc -index 838761af5..9eb201d37 100644 ---- a/src/ssl/ssl_lib.cc -+++ b/src/ssl/ssl_lib.cc -@@ -3151,7 +3151,7 @@ namespace fips202205 { +diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc +index 58b68e675..38c8e906c 100644 +--- a/ssl/ssl_lib.cc ++++ b/ssl/ssl_lib.cc +@@ -3260,7 +3260,7 @@ namespace fips202205 { // Section 3.3.1 // "The server shall be configured to only use cipher suites that are // composed entirely of NIST approved algorithms" --static const int kCurves[] = {NID_X9_62_prime256v1, NID_secp384r1}; -+static const int kCurves[] = {NID_P256Kyber768Draft00, NID_X9_62_prime256v1, NID_secp384r1}; +-static const uint16_t kGroups[] = {SSL_GROUP_SECP256R1, SSL_GROUP_SECP384R1}; ++static const uint16_t kGroups[] = {SSL_GROUP_P256_KYBER768_DRAFT00, SSL_GROUP_SECP256R1, SSL_GROUP_SECP384R1}; static const uint16_t kSigAlgs[] = { SSL_SIGN_RSA_PKCS1_SHA256, -diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc -index ef43a9e98..22178b5f6 100644 ---- a/src/ssl/ssl_test.cc -+++ b/src/ssl/ssl_test.cc -@@ -409,7 +409,34 @@ static const CurveTest kCurveTests[] = { +diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc +index a8f4f215b..e0ebb505e 100644 +--- a/ssl/ssl_test.cc ++++ b/ssl/ssl_test.cc +@@ -484,7 +484,34 @@ static const CurveTest kCurveTests[] = { "P-256:X25519Kyber768Draft00", - { SSL_CURVE_SECP256R1, SSL_CURVE_X25519_KYBER768_DRAFT00 }, + { SSL_GROUP_SECP256R1, SSL_GROUP_X25519_KYBER768_DRAFT00 }, }, - + { + "Xyber512D00", -+ { SSL_CURVE_X25519_KYBER512_DRAFT00 }, ++ { SSL_GROUP_X25519_KYBER512_DRAFT00 }, + }, + { + "Xyber768D00", -+ { SSL_CURVE_X25519_KYBER768_DRAFT00 }, ++ { SSL_GROUP_X25519_KYBER768_DRAFT00 }, + }, + { + "Xyber768D00:Xyber768D00Old", -+ { SSL_CURVE_X25519_KYBER768_DRAFT00, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD }, ++ { SSL_GROUP_X25519_KYBER768_DRAFT00, SSL_GROUP_X25519_KYBER768_DRAFT00_OLD }, + }, + { + "P-256:Xyber512D00", -+ { SSL_CURVE_SECP256R1, SSL_CURVE_X25519_KYBER512_DRAFT00 }, ++ { SSL_GROUP_SECP256R1, SSL_GROUP_X25519_KYBER512_DRAFT00 }, + }, + { + "P256Kyber768D00", -+ { SSL_CURVE_P256_KYBER768_DRAFT00 }, ++ { SSL_GROUP_P256_KYBER768_DRAFT00 }, + }, + { + "X25519MLKEM768", -+ { SSL_CURVE_X25519_MLKEM768 }, ++ { SSL_GROUP_X25519_MLKEM768 }, + }, + { + "P-256:P256Kyber768D00", -+ { SSL_CURVE_SECP256R1, SSL_CURVE_P256_KYBER768_DRAFT00 }, ++ { SSL_GROUP_SECP256R1, SSL_GROUP_P256_KYBER768_DRAFT00 }, + }, { "P-256:P-384:P-521:X25519", { -diff --git a/src/tool/speed.cc b/src/tool/speed.cc -index 5b0205953..6b3c67dab 100644 ---- a/src/tool/speed.cc -+++ b/src/tool/speed.cc -@@ -904,6 +904,116 @@ static bool SpeedScrypt(const std::string &selected) { +diff --git a/tool/speed.cc b/tool/speed.cc +index 942dcade1..f31e9e244 100644 +--- a/tool/speed.cc ++++ b/tool/speed.cc +@@ -1018,6 +1018,116 @@ static bool SpeedScrypt(const std::string &selected) { return true; } @@ -5067,7 +4722,7 @@ index 5b0205953..6b3c67dab 100644 static bool SpeedHRSS(const std::string &selected) { if (!selected.empty() && selected != "HRSS") { return true; -@@ -958,55 +1068,6 @@ static bool SpeedHRSS(const std::string &selected) { +@@ -1079,55 +1189,6 @@ static bool SpeedHRSS(const std::string &selected) { return true; } @@ -5078,39 +4733,39 @@ index 5b0205953..6b3c67dab 100644 - - TimeResults results; - -- KYBER_private_key priv; -- uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; - uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES]; - // This ciphertext is nonsense, but Kyber decap is constant-time so, for the - // purposes of timing, it's fine. - memset(ciphertext, 42, sizeof(ciphertext)); -- if (!TimeFunction(&results, -- [&priv, &encoded_public_key, &ciphertext]() -> bool { -- uint8_t shared_secret[32]; -- KYBER_generate_key(encoded_public_key, &priv); -- KYBER_decap(shared_secret, sizeof(shared_secret), -- ciphertext, &priv); -- return true; -- })) { +- if (!TimeFunctionParallel(&results, [&]() -> bool { +- KYBER_private_key priv; +- uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(encoded_public_key, &priv); +- uint8_t shared_secret[32]; +- KYBER_decap(shared_secret, sizeof(shared_secret), ciphertext, &priv); +- return true; +- })) { - fprintf(stderr, "Failed to time KYBER_generate_key + KYBER_decap.\n"); - return false; - } - - results.Print("Kyber generate + decap"); - +- KYBER_private_key priv; +- uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(encoded_public_key, &priv); - KYBER_public_key pub; -- if (!TimeFunction( -- &results, [&pub, &ciphertext, &encoded_public_key]() -> bool { -- CBS encoded_public_key_cbs; -- CBS_init(&encoded_public_key_cbs, encoded_public_key, -- sizeof(encoded_public_key)); -- if (!KYBER_parse_public_key(&pub, &encoded_public_key_cbs)) { -- return false; -- } -- uint8_t shared_secret[32]; -- KYBER_encap(ciphertext, shared_secret, sizeof(shared_secret), &pub); -- return true; -- })) { +- if (!TimeFunctionParallel(&results, [&]() -> bool { +- CBS encoded_public_key_cbs; +- CBS_init(&encoded_public_key_cbs, encoded_public_key, +- sizeof(encoded_public_key)); +- if (!KYBER_parse_public_key(&pub, &encoded_public_key_cbs)) { +- return false; +- } +- uint8_t shared_secret[32]; +- KYBER_encap(ciphertext, shared_secret, sizeof(shared_secret), &pub); +- return true; +- })) { - fprintf(stderr, "Failed to time KYBER_encap.\n"); - return false; - } @@ -5120,19 +4775,16 @@ index 5b0205953..6b3c67dab 100644 - return true; -} - - static bool SpeedHashToCurve(const std::string &selected) { - if (!selected.empty() && selected.find("hashtocurve") == std::string::npos) { + static bool SpeedSpx(const std::string &selected) { + if (!selected.empty() && selected.find("spx") == std::string::npos) { return true; -@@ -1487,7 +1548,8 @@ bool Speed(const std::vector &args) { - !SpeedScrypt(selected) || - !SpeedRSAKeyGen(selected) || - !SpeedHRSS(selected) || -- !SpeedKyber(selected) || +@@ -1661,7 +1722,8 @@ bool Speed(const std::vector &args) { + !SpeedScrypt(selected) || // + !SpeedRSAKeyGen(selected) || // + !SpeedHRSS(selected) || // +- !SpeedKyber(selected) || // + !SpeedKyber512(selected) || + !SpeedKyber768(selected) || - !SpeedHashToCurve(selected) || + !SpeedSpx(selected) || // + !SpeedHashToCurve(selected) || // !SpeedTrustToken("TrustToken-Exp1-Batch1", TRUST_TOKEN_experiment_v1(), 1, - selected) || --- -2.46.0 - diff --git a/boring-sys/patches/rpk.patch b/boring-sys/patches/rpk.patch index bc2e3a8f..edf97708 100644 --- a/boring-sys/patches/rpk.patch +++ b/boring-sys/patches/rpk.patch @@ -1,7 +1,7 @@ -diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..87309c3e1 100644 ---- a/src/include/openssl/ssl.h -+++ b/src/include/openssl/ssl.h +diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h +index 003e0a5f7..b8f8d49c8 100644 +--- a/include/openssl/ssl.h ++++ b/include/openssl/ssl.h @@ -138,6 +138,25 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. @@ -28,7 +28,7 @@ index 53aa9b453..87309c3e1 100644 #ifndef OPENSSL_HEADER_SSL_H #define OPENSSL_HEADER_SSL_H -@@ -1136,6 +1155,16 @@ OPENSSL_EXPORT int SSL_CTX_set_chain_and_key( +@@ -1138,6 +1157,16 @@ OPENSSL_EXPORT int SSL_CTX_set_chain_and_key( SSL_CTX *ctx, CRYPTO_BUFFER *const *certs, size_t num_certs, EVP_PKEY *privkey, const SSL_PRIVATE_KEY_METHOD *privkey_method); @@ -45,7 +45,7 @@ index 53aa9b453..87309c3e1 100644 // SSL_set_chain_and_key sets the certificate chain and private key for a TLS // client or server. References to the given |CRYPTO_BUFFER| and |EVP_PKEY| // objects are added as needed. Exactly one of |privkey| or |privkey_method| -@@ -1144,6 +1173,16 @@ OPENSSL_EXPORT int SSL_set_chain_and_key( +@@ -1146,6 +1175,16 @@ OPENSSL_EXPORT int SSL_set_chain_and_key( SSL *ssl, CRYPTO_BUFFER *const *certs, size_t num_certs, EVP_PKEY *privkey, const SSL_PRIVATE_KEY_METHOD *privkey_method); @@ -62,8 +62,8 @@ index 53aa9b453..87309c3e1 100644 // SSL_CTX_get0_chain returns the list of |CRYPTO_BUFFER|s that were set by // |SSL_CTX_set_chain_and_key|. Reference counts are not incremented by this // call. The return value may be |NULL| if no chain has been set. -@@ -3023,6 +3062,21 @@ OPENSSL_EXPORT void SSL_get0_peer_application_settings(const SSL *ssl, - OPENSSL_EXPORT int SSL_has_application_settings(const SSL *ssl); +@@ -3041,6 +3080,21 @@ OPENSSL_EXPORT int SSL_has_application_settings(const SSL *ssl); + OPENSSL_EXPORT void SSL_set_alps_use_new_codepoint(SSL *ssl, int use_new); +// Server Certificate Type. @@ -84,10 +84,10 @@ index 53aa9b453..87309c3e1 100644 // Certificate compression. // // Certificates in TLS 1.3 can be compressed (RFC 8879). BoringSSL supports this -diff --git a/src/include/openssl/tls1.h b/src/include/openssl/tls1.h -index 772fb87a3..be605c1aa 100644 ---- a/src/include/openssl/tls1.h -+++ b/src/include/openssl/tls1.h +diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h +index c1207a3b7..ac6ed222a 100644 +--- a/include/openssl/tls1.h ++++ b/include/openssl/tls1.h @@ -146,6 +146,25 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. @@ -124,10 +124,10 @@ index 772fb87a3..be605c1aa 100644 // ExtensionType value from RFC 7685 #define TLSEXT_TYPE_padding 21 -diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..2692e5478 100644 ---- a/src/ssl/extensions.cc -+++ b/src/ssl/extensions.cc +diff --git a/ssl/extensions.cc b/ssl/extensions.cc +index b13400097..8694712fd 100644 +--- a/ssl/extensions.cc ++++ b/ssl/extensions.cc @@ -105,6 +105,25 @@ * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim @@ -154,7 +154,7 @@ index 5ee280221..2692e5478 100644 #include -@@ -3094,6 +3113,146 @@ bool ssl_negotiate_alps(SSL_HANDSHAKE *hs, uint8_t *out_alert, +@@ -3108,6 +3127,146 @@ bool ssl_negotiate_alps(SSL_HANDSHAKE *hs, uint8_t *out_alert, return true; } @@ -301,9 +301,9 @@ index 5ee280221..2692e5478 100644 // kExtensions contains all the supported extensions. static const struct tls_extension kExtensions[] = { { -@@ -3267,6 +3426,13 @@ static const struct tls_extension kExtensions[] = { +@@ -3289,6 +3448,13 @@ static const struct tls_extension kExtensions[] = { ignore_parse_clienthello, - ext_alps_add_serverhello, + ext_alps_add_serverhello_old, }, + { + TLSEXT_TYPE_server_certificate_type, @@ -315,10 +315,10 @@ index 5ee280221..2692e5478 100644 }; #define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) -diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc -index 8d5a23872..b9ac70dfe 100644 ---- a/src/ssl/handshake.cc -+++ b/src/ssl/handshake.cc +diff --git a/ssl/handshake.cc b/ssl/handshake.cc +index 8d5a23872..c8ca629e8 100644 +--- a/ssl/handshake.cc ++++ b/ssl/handshake.cc @@ -109,6 +109,25 @@ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * ECC cipher suite support in OpenSSL originally developed by @@ -345,14 +345,14 @@ index 8d5a23872..b9ac70dfe 100644 #include -@@ -150,6 +169,7 @@ SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg) +@@ -148,6 +167,7 @@ SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg) + handback(false), + hints_requested(false), cert_compression_negotiated(false), + server_certificate_type_negotiated(false), apply_jdk11_workaround(false), can_release_private_key(false), channel_id_negotiated(false) { - assert(ssl); - @@ -365,7 +385,21 @@ enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) { uint8_t alert = SSL_AD_CERTIFICATE_UNKNOWN; @@ -376,10 +376,10 @@ index 8d5a23872..b9ac70dfe 100644 ret = hs->config->custom_verify_callback(ssl, &alert); switch (ret) { case ssl_verify_ok: -diff --git a/src/ssl/internal.h b/src/ssl/internal.h -index 1e6da2153..f04888384 100644 ---- a/src/ssl/internal.h -+++ b/src/ssl/internal.h +diff --git a/ssl/internal.h b/ssl/internal.h +index c9facb699..d7363e729 100644 +--- a/ssl/internal.h ++++ b/ssl/internal.h @@ -138,6 +138,25 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. @@ -406,7 +406,7 @@ index 1e6da2153..f04888384 100644 #ifndef OPENSSL_HEADER_SSL_INTERNAL_H #define OPENSSL_HEADER_SSL_INTERNAL_H -@@ -1286,6 +1305,8 @@ int ssl_write_buffer_flush(SSL *ssl); +@@ -1311,6 +1330,8 @@ int ssl_write_buffer_flush(SSL *ssl); // configured. bool ssl_has_certificate(const SSL_HANDSHAKE *hs); @@ -415,7 +415,7 @@ index 1e6da2153..f04888384 100644 // ssl_parse_cert_chain parses a certificate list from |cbs| in the format used // by a TLS Certificate message. On success, it advances |cbs| and returns // true. Otherwise, it returns false and sets |*out_alert| to an alert to send -@@ -1887,6 +1908,8 @@ struct SSL_HANDSHAKE { +@@ -1912,6 +1933,8 @@ struct SSL_HANDSHAKE { // |cert_compression_negotiated| is true. uint16_t cert_compression_alg_id; @@ -424,7 +424,7 @@ index 1e6da2153..f04888384 100644 // ech_hpke_ctx is the HPKE context used in ECH. On the server, it is // initialized if |ech_status| is |ssl_ech_accepted|. On the client, it is // initialized if |selected_ech_config| is not nullptr. -@@ -2037,6 +2060,8 @@ struct SSL_HANDSHAKE { +@@ -2062,6 +2085,8 @@ struct SSL_HANDSHAKE { // cert_compression_negotiated is true iff |cert_compression_alg_id| is valid. bool cert_compression_negotiated : 1; @@ -433,7 +433,7 @@ index 1e6da2153..f04888384 100644 // apply_jdk11_workaround is true if the peer is probably a JDK 11 client // which implemented TLS 1.3 incorrectly. bool apply_jdk11_workaround : 1; -@@ -3049,6 +3074,9 @@ struct SSL_CONFIG { +@@ -3074,6 +3099,9 @@ struct SSL_CONFIG { // along with their corresponding ALPS values. GrowableArray alps_configs; @@ -443,7 +443,7 @@ index 1e6da2153..f04888384 100644 // Contains the QUIC transport params that this endpoint will send. Array quic_transport_params; -@@ -3648,6 +3676,9 @@ struct ssl_ctx_st { +@@ -3666,6 +3694,9 @@ struct ssl_ctx_st { // format. bssl::Array alpn_client_proto_list; @@ -453,10 +453,10 @@ index 1e6da2153..f04888384 100644 // SRTP profiles we are willing to do from RFC 5764 bssl::UniquePtr srtp_profiles; -diff --git a/src/ssl/ssl_cert.cc b/src/ssl/ssl_cert.cc +diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc index aa46a8bb6..d90840fce 100644 ---- a/src/ssl/ssl_cert.cc -+++ b/src/ssl/ssl_cert.cc +--- a/ssl/ssl_cert.cc ++++ b/ssl/ssl_cert.cc @@ -111,6 +111,25 @@ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * ECC cipher suite support in OpenSSL originally developed by @@ -573,10 +573,10 @@ index aa46a8bb6..d90840fce 100644 const STACK_OF(CRYPTO_BUFFER)* SSL_CTX_get0_chain(const SSL_CTX *ctx) { return ctx->cert->chain.get(); } -diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc -index 838761af5..e4f1a12b7 100644 ---- a/src/ssl/ssl_lib.cc -+++ b/src/ssl/ssl_lib.cc +diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc +index 58b68e675..384debbd3 100644 +--- a/ssl/ssl_lib.cc ++++ b/ssl/ssl_lib.cc @@ -137,6 +137,25 @@ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR @@ -615,8 +615,8 @@ index 838761af5..e4f1a12b7 100644 if (!ssl->method->ssl_new(ssl.get()) || !ssl->ctx->x509_method->ssl_new(ssl->s3->hs.get())) { return nullptr; -@@ -3140,6 +3164,53 @@ int SSL_CTX_set_tlsext_status_arg(SSL_CTX *ctx, void *arg) { - return 1; +@@ -3249,6 +3273,53 @@ int SSL_set1_curves_list(SSL *ssl, const char *curves) { + return SSL_set1_groups_list(ssl, curves); } +int SSL_CTX_set_server_raw_public_key_certificate(SSL_CTX *ctx, @@ -669,10 +669,10 @@ index 838761af5..e4f1a12b7 100644 namespace fips202205 { // (References are to SP 800-52r2): -diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc +diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc index 5ab5a1c93..79135613e 100644 ---- a/src/ssl/tls13_both.cc -+++ b/src/ssl/tls13_both.cc +--- a/ssl/tls13_both.cc ++++ b/ssl/tls13_both.cc @@ -11,6 +11,25 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN @@ -750,10 +750,10 @@ index 5ab5a1c93..79135613e 100644 if (!ssl_has_certificate(hs)) { return ssl_add_message_cbb(ssl, cbb.get()); } -diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc -index 9d26f4e00..a92689761 100644 ---- a/src/ssl/tls13_server.cc -+++ b/src/ssl/tls13_server.cc +diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc +index 707cf846b..6916606c2 100644 +--- a/ssl/tls13_server.cc ++++ b/ssl/tls13_server.cc @@ -11,6 +11,25 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN diff --git a/boring-sys/patches/underscore-wildcards.patch b/boring-sys/patches/underscore-wildcards.patch index f281b3a1..38e406a2 100644 --- a/boring-sys/patches/underscore-wildcards.patch +++ b/boring-sys/patches/underscore-wildcards.patch @@ -1,21 +1,10 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:underscore-wildcards ---- a/src/crypto/x509v3/v3_utl.c -+++ b/src/crypto/x509v3/v3_utl.c -@@ -790,7 +790,9 @@ static int wildcard_match(const unsigned char *prefix, size_t prefix_len, - // Check that the part matched by the wildcard contains only - // permitted characters and only matches a single label. - for (p = wildcard_start; p != wildcard_end; ++p) { -- if (!OPENSSL_isalnum(*p) && *p != '-') { -+ if (!OPENSSL_isalnum(*p) && *p != '-' && -+ !(*p == '_' && -+ (flags & X509_CHECK_FLAG_UNDERSCORE_WILDCARDS))) { - return 0; - } - } ---- a/src/crypto/x509/x509_test.cc -+++ b/src/crypto/x509/x509_test.cc -@@ -4500,6 +4500,31 @@ TEST(X509Test, Names) { +diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc +index 9699b5a75..b0e9b34a6 100644 +--- a/crypto/x509/x509_test.cc ++++ b/crypto/x509/x509_test.cc +@@ -4420,6 +4420,31 @@ TEST(X509Test, Names) { /*invalid_emails=*/{}, /*flags=*/0, }, @@ -47,9 +36,26 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:unders }; size_t i = 0; ---- a/src/include/openssl/x509c3.h -+++ b/src/include/openssl/x509v3.h -@@ -4497,6 +4497,8 @@ OPENSSL_EXPORT int X509_PURPOSE_get_id(const X509_PURPOSE *); +diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c +index bbc82e283..e61e1901d 100644 +--- a/crypto/x509v3/v3_utl.c ++++ b/crypto/x509v3/v3_utl.c +@@ -790,7 +790,9 @@ static int wildcard_match(const unsigned char *prefix, size_t prefix_len, + // Check that the part matched by the wildcard contains only + // permitted characters and only matches a single label. + for (p = wildcard_start; p != wildcard_end; ++p) { +- if (!OPENSSL_isalnum(*p) && *p != '-') { ++ if (!OPENSSL_isalnum(*p) && *p != '-' && ++ !(*p == '_' && ++ (flags & X509_CHECK_FLAG_UNDERSCORE_WILDCARDS))) { + return 0; + } + } +diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h +index 2a2e02c2e..24e0604b0 100644 +--- a/include/openssl/x509v3.h ++++ b/include/openssl/x509v3.h +@@ -939,6 +939,8 @@ OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); #define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0 // Skip the subject common name fallback if subjectAltNames is missing. #define X509_CHECK_FLAG_NEVER_CHECK_SUBJECT 0x20 @@ -58,4 +64,3 @@ https://github.com/google/boringssl/compare/master...cloudflare:boringssl:unders OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen, unsigned int flags, char **peername); --- diff --git a/boring/Cargo.toml b/boring/Cargo.toml index f9a3527b..caac99f2 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -19,29 +19,11 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Controlling the build -# NOTE: This feature is deprecated. It is needed for the submoduled -# boringssl-fips, which is extremely old and requires modifications to the -# bindings, as some newer APIs don't exist and some function signatures have -# changed. It is highly recommended to use `fips-precompiled` instead. -# -# This feature sets `fips-compat` on behalf of the user to guarantee bindings -# compatibility with the submoduled boringssl-fips. -# # Use a FIPS-validated version of BoringSSL. -fips = ["fips-compat", "boring-sys/fips"] +fips = ["boring-sys/fips"] -# Build with compatibility for the submoduled boringssl-fips, without enabling -# the `fips` feature itself (useful e.g. if `fips-link-precompiled` is used -# with an older BoringSSL version). -fips-compat = [] - -# Use a precompiled FIPS-validated version of BoringSSL. Meant to be used with -# FIPS-20230428 or newer. Users must set `BORING_BSSL_FIPS_PATH` to use this -# feature, or else the build will fail. -fips-precompiled = ["boring-sys/fips-precompiled"] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = ["boring-sys/fips-link-precompiled"] +# **DO NOT USE** This will be removed without warning in future releases. +legacy-compat-deprecated = [] # Enables Raw public key API (https://datatracker.ietf.org/doc/html/rfc7250) # This feature is necessary in order to compile the bindings for the diff --git a/boring/src/bio.rs b/boring/src/bio.rs index 71120606..2e6b2572 100644 --- a/boring/src/bio.rs +++ b/boring/src/bio.rs @@ -19,9 +19,9 @@ impl Drop for MemBioSlice<'_> { impl<'a> MemBioSlice<'a> { pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { - #[cfg(not(feature = "fips-compat"))] + #[cfg(not(feature = "legacy-compat-deprecated"))] type BufLen = isize; - #[cfg(feature = "fips-compat")] + #[cfg(feature = "legacy-compat-deprecated")] type BufLen = libc::c_int; ffi::init(); diff --git a/boring/src/fips.rs b/boring/src/fips.rs index 8e451226..708b0903 100644 --- a/boring/src/fips.rs +++ b/boring/src/fips.rs @@ -15,16 +15,8 @@ pub fn enabled() -> bool { #[test] fn is_enabled() { - #[cfg(any( - feature = "fips", - feature = "fips-precompiled", - feature = "fips-link-precompiled" - ))] + #[cfg(feature = "fips")] assert!(enabled()); - #[cfg(not(any( - feature = "fips", - feature = "fips-precompiled", - feature = "fips-link-precompiled" - )))] + #[cfg(not(feature = "fips"))] assert!(!enabled()); } diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 4b84b7c5..77f3e726 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -137,7 +137,6 @@ pub mod error; pub mod ex_data; pub mod fips; pub mod hash; -#[cfg(not(feature = "fips"))] pub mod hpke; pub mod memcmp; pub mod nid; diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 9cd40405..00fa5ba9 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -104,7 +104,6 @@ pub use self::async_callbacks::{ pub use self::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; -#[cfg(not(feature = "fips"))] pub use self::ech::{SslEchKeys, SslEchKeysRef}; pub use self::error::{Error, ErrorCode, HandshakeError}; @@ -112,7 +111,6 @@ mod async_callbacks; mod bio; mod callbacks; mod connector; -#[cfg(not(feature = "fips"))] mod ech; mod error; mod mut_only; @@ -708,45 +706,32 @@ pub struct SslCurveNid(c_int); pub struct SslCurve(c_int); impl SslCurve { - pub const SECP224R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP224R1 as _); + pub const SECP224R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP224R1 as _); - pub const SECP256R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP256R1 as _); + pub const SECP256R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP256R1 as _); - pub const SECP384R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP384R1 as _); + pub const SECP384R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP384R1 as _); - pub const SECP521R1: SslCurve = SslCurve(ffi::SSL_CURVE_SECP521R1 as _); + pub const SECP521R1: SslCurve = SslCurve(ffi::SSL_GROUP_SECP521R1 as _); - pub const X25519: SslCurve = SslCurve(ffi::SSL_CURVE_X25519 as _); + pub const X25519: SslCurve = SslCurve(ffi::SSL_GROUP_X25519 as _); - #[cfg(not(any(feature = "fips", feature = "fips-precompiled")))] pub const X25519_KYBER768_DRAFT00: SslCurve = - SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 as _); + SslCurve(ffi::SSL_GROUP_X25519_KYBER768_DRAFT00 as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] + #[cfg(feature = "pq-experimental")] pub const X25519_KYBER768_DRAFT00_OLD: SslCurve = - SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD as _); + SslCurve(ffi::SSL_GROUP_X25519_KYBER768_DRAFT00_OLD as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] + #[cfg(feature = "pq-experimental")] pub const X25519_KYBER512_DRAFT00: SslCurve = - SslCurve(ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 as _); + SslCurve(ffi::SSL_GROUP_X25519_KYBER512_DRAFT00 as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_P256_KYBER768_DRAFT00 as _); + #[cfg(feature = "pq-experimental")] + pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_GROUP_P256_KYBER768_DRAFT00 as _); - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - pub const X25519_MLKEM768: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_MLKEM768 as _); + #[cfg(feature = "pq-experimental")] + pub const X25519_MLKEM768: SslCurve = SslCurve(ffi::SSL_GROUP_X25519_MLKEM768 as _); /// Returns the curve name #[corresponds(SSL_get_curve_name)] @@ -766,7 +751,7 @@ impl SslCurve { // against the absence of the `kx-safe-default` feature and thus this function is never used. // // **NOTE**: This function only exists because the version of boringssl we currently use does - // not expose SSL_CTX_set1_group_ids. Because `SslRef::curve()` returns the public SSL_CURVE id + // not expose SSL_CTX_set1_group_ids. Because `SslRef::curve()` returns the public SSL_GROUP id // as opposed to the internal NID, but `SslContextBuilder::set_curves()` requires the internal // NID, we need this mapping in place to avoid breaking changes to the public API. Once the // underlying boringssl version is upgraded, this should be removed in favor of the new @@ -774,33 +759,20 @@ impl SslCurve { #[allow(dead_code)] pub fn nid(&self) -> Option { match self.0 { - ffi::SSL_CURVE_SECP224R1 => Some(ffi::NID_secp224r1), - ffi::SSL_CURVE_SECP256R1 => Some(ffi::NID_X9_62_prime256v1), - ffi::SSL_CURVE_SECP384R1 => Some(ffi::NID_secp384r1), - ffi::SSL_CURVE_SECP521R1 => Some(ffi::NID_secp521r1), - ffi::SSL_CURVE_X25519 => Some(ffi::NID_X25519), - #[cfg(not(any(feature = "fips", feature = "fips-precompiled")))] - ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), - #[cfg(all( - not(any(feature = "fips", feature = "fips-precompiled")), - feature = "pq-experimental" - ))] - ffi::SSL_CURVE_X25519_MLKEM768 => Some(ffi::NID_X25519MLKEM768), + ffi::SSL_GROUP_SECP224R1 => Some(ffi::NID_secp224r1), + ffi::SSL_GROUP_SECP256R1 => Some(ffi::NID_X9_62_prime256v1), + ffi::SSL_GROUP_SECP384R1 => Some(ffi::NID_secp384r1), + ffi::SSL_GROUP_SECP521R1 => Some(ffi::NID_secp521r1), + ffi::SSL_GROUP_X25519 => Some(ffi::NID_X25519), + ffi::SSL_GROUP_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), + #[cfg(feature = "pq-experimental")] + ffi::SSL_GROUP_X25519_MLKEM768 => Some(ffi::NID_X25519MLKEM768), _ => None, } .map(SslCurveNid) @@ -809,12 +781,11 @@ impl SslCurve { /// A compliance policy. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[cfg(not(feature = "fips-compat"))] pub struct CompliancePolicy(ffi::ssl_compliance_policy_t); -#[cfg(not(feature = "fips-compat"))] impl CompliancePolicy { /// Does nothing, however setting this does not undo other policies, so trying to set this is an error. + #[cfg(not(feature = "legacy-compat-deprecated"))] pub const NONE: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_none); /// Configures a TLS connection to try and be compliant with NIST requirements, but does not guarantee success. @@ -824,6 +795,7 @@ impl CompliancePolicy { /// Partially configures a TLS connection to be compliant with WPA3. Callers must enforce certificate chain requirements themselves. /// Use of this policy is less secure than the default and not recommended. + #[cfg(not(feature = "legacy-compat-deprecated"))] pub const WPA3_192_202304: Self = Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_wpa3_192_202304); } @@ -1609,7 +1581,10 @@ impl SslContextBuilder { #[corresponds(SSL_CTX_set_alpn_protos)] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { - #[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))] + #[cfg_attr( + not(feature = "legacy-compat-deprecated"), + allow(clippy::unnecessary_cast) + )] { assert!(protocols.len() <= ProtosLen::MAX as usize); } @@ -2009,7 +1984,6 @@ impl SslContextBuilder { /// version of BoringSSL which doesn't yet include these APIs. /// Once the submoduled fips commit is upgraded, these gates can be removed. #[corresponds(SSL_CTX_set_permute_extensions)] - #[cfg(not(feature = "fips-compat"))] pub fn set_permute_extensions(&mut self, enabled: bool) { unsafe { ffi::SSL_CTX_set_permute_extensions(self.as_ptr(), enabled as _) } } @@ -2087,7 +2061,6 @@ impl SslContextBuilder { /// /// This feature isn't available in the certified version of BoringSSL. #[corresponds(SSL_CTX_set_compliance_policy)] - #[cfg(not(feature = "fips-compat"))] pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } } @@ -2108,7 +2081,6 @@ impl SslContextBuilder { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } @@ -2376,7 +2348,6 @@ impl SslContextRef { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } @@ -2390,9 +2361,9 @@ impl SslContextRef { #[derive(Debug)] pub struct GetSessionPendingError; -#[cfg(not(feature = "fips-compat"))] +#[cfg(not(feature = "legacy-compat-deprecated"))] type ProtosLen = usize; -#[cfg(feature = "fips-compat")] +#[cfg(feature = "legacy-compat-deprecated")] type ProtosLen = libc::c_uint; /// Information about the state of a cipher. @@ -3161,7 +3132,6 @@ impl SslRef { /// Note: This is gated to non-fips because the fips feature builds with a separate /// version of BoringSSL which doesn't yet include these APIs. /// Once the submoduled fips commit is upgraded, these gates can be removed. - #[cfg(not(feature = "fips-compat"))] pub fn set_permute_extensions(&mut self, enabled: bool) { unsafe { ffi::SSL_set_permute_extensions(self.as_ptr(), enabled as _) } } @@ -3172,7 +3142,10 @@ impl SslRef { #[corresponds(SSL_set_alpn_protos)] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { - #[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))] + #[cfg_attr( + not(feature = "legacy-compat-deprecated"), + allow(clippy::unnecessary_cast) + )] { assert!(protocols.len() <= ProtosLen::MAX as usize); } @@ -3886,7 +3859,6 @@ impl SslRef { /// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH /// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh /// set of ECHConfigs. If the retry also fails, clients should report a connection failure. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_set1_ech_config_list)] pub fn set_ech_config_list(&mut self, ech_config_list: &[u8]) -> Result<(), ErrorStack> { unsafe { @@ -3905,7 +3877,6 @@ impl SslRef { /// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to /// recover from potential key mismatches. If the result is `Some`, the client should retry the /// connection using the returned `ECHConfigList`. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_get0_ech_retry_configs)] #[must_use] pub fn get_ech_retry_configs(&self) -> Option<&[u8]> { @@ -3928,7 +3899,6 @@ impl SslRef { /// Clients should call this function during the certificate verification callback to /// ensure the server's certificate is valid for the public name, which is required to /// authenticate retry configs. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_get0_ech_name_override)] #[must_use] pub fn get_ech_name_override(&self) -> Option<&[u8]> { @@ -3946,7 +3916,6 @@ impl SslRef { } // Whether or not `SSL` negotiated ECH. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_ech_accepted)] #[must_use] pub fn ech_accepted(&self) -> bool { @@ -3954,7 +3923,6 @@ impl SslRef { } // Whether or not to enable ECH grease on `SSL`. - #[cfg(not(feature = "fips"))] #[corresponds(SSL_set_enable_ech_grease)] pub fn set_enable_ech_grease(&self, enable: bool) { let enable = if enable { 1 } else { 0 }; @@ -3965,7 +3933,6 @@ impl SslRef { } /// Sets the compliance policy on `SSL`. - #[cfg(not(feature = "fips-compat"))] #[corresponds(SSL_set_compliance_policy)] pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { unsafe { cvt_0i(ffi::SSL_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 9b7b024c..6ac6ca75 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -22,13 +22,11 @@ use crate::x509::store::X509StoreBuilder; use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; -#[cfg(not(feature = "fips"))] use super::CompliancePolicy; mod cert_compressor; mod cert_verify; mod custom_verify; -#[cfg(not(feature = "fips"))] mod ech; mod private_key_method; mod server; @@ -1037,7 +1035,6 @@ fn test_get_ciphers() { } #[test] -#[cfg(not(feature = "fips"))] fn test_set_compliance() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) @@ -1118,7 +1115,6 @@ fn test_info_callback() { assert!(CALLED_BACK.load(Ordering::Relaxed)); } -#[cfg(not(feature = "fips-compat"))] #[test] fn test_ssl_set_compliance() { let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index 8bf96d33..17115d68 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -1120,9 +1120,9 @@ impl X509NameBuilder { } } -#[cfg(not(feature = "fips-compat"))] +#[cfg(not(feature = "legacy-compat-deprecated"))] type ValueLen = isize; -#[cfg(feature = "fips-compat")] +#[cfg(feature = "legacy-compat-deprecated")] type ValueLen = i32; foreign_type_and_impl_send_sync! { diff --git a/boring/src/x509/tests/trusted_first.rs b/boring/src/x509/tests/trusted_first.rs index b5e714b5..9f49ffe3 100644 --- a/boring/src/x509/tests/trusted_first.rs +++ b/boring/src/x509/tests/trusted_first.rs @@ -15,7 +15,7 @@ fn test_verify_cert() { assert_eq!(Ok(()), verify(&leaf, &[&root1], &[&intermediate], |_| {})); - #[cfg(not(feature = "fips-compat"))] + #[cfg(not(feature = "legacy-compat-deprecated"))] assert_eq!( Ok(()), verify( @@ -26,7 +26,7 @@ fn test_verify_cert() { ) ); - #[cfg(feature = "fips-compat")] + #[cfg(feature = "legacy-compat-deprecated")] assert_eq!( Err(X509VerifyError::CERT_HAS_EXPIRED), verify( diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index 77a8a788..25f360fd 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -17,20 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Use a FIPS-validated version of boringssl. -fips = ["tokio-boring/fips"] - -# Use a FIPS build of BoringSSL, but don't set "fips-compat". -# -# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer -# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, -# which means the "fips-compat" feature is no longer needed. -# -# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply -# "fips-compat". -fips-precompiled = ["tokio-boring/fips-precompiled"] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = ["tokio-boring/fips-link-precompiled"] +fips = ["boring/fips", "tokio-boring/fips"] # Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/) pq-experimental = ["tokio-boring/pq-experimental"] diff --git a/tokio-boring/Cargo.toml b/tokio-boring/Cargo.toml index 75c64129..c5735341 100644 --- a/tokio-boring/Cargo.toml +++ b/tokio-boring/Cargo.toml @@ -19,19 +19,6 @@ rustdoc-args = ["--cfg", "docsrs"] # Use a FIPS-validated version of boringssl. fips = ["boring/fips", "boring-sys/fips"] -# Use a FIPS build of BoringSSL, but don't set "fips-compat". -# -# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer -# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, -# which means the "fips-compat" feature is no longer needed. -# -# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply -# "fips-compat". -fips-precompiled = ["boring/fips-precompiled"] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = ["boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"] - # Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/) pq-experimental = ["boring/pq-experimental"]