Add new "wasm32_c" feature to enable more functionality for wasm32 targets.

This commit is contained in:
Brian Smith 2020-05-27 10:41:53 -05:00
parent 42f110abe5
commit 10c4b68e63
8 changed files with 124 additions and 56 deletions

View File

@ -331,6 +331,7 @@ internal_benches = []
slow_tests = []
std = ["alloc"]
test_logging = []
wasm32_c = []
# XXX: debug = false because of https://github.com/rust-lang/rust/issues/34122

131
build.rs
View File

@ -54,17 +54,18 @@ const ARM: &str = "arm";
#[cfg_attr(rustfmt, rustfmt_skip)]
const RING_SRCS: &[(&[&str], &str)] = &[
(&[], "crypto/fipsmodule/bn/generic.c"),
(&[], "crypto/fipsmodule/bn/montgomery.c"),
(&[], "crypto/fipsmodule/bn/montgomery_inv.c"),
(&[], "crypto/crypto.c"),
(&[], "crypto/fipsmodule/ec/ecp_nistz.c"),
(&[], "crypto/fipsmodule/ec/ecp_nistz256.c"),
(&[], "crypto/fipsmodule/ec/gfp_p256.c"),
(&[], "crypto/fipsmodule/ec/gfp_p384.c"),
(&[], "crypto/limbs/limbs.c"),
(&[], "crypto/mem.c"),
(&[], "third_party/fiat/curve25519.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/bn/generic.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/bn/montgomery.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/bn/montgomery_inv.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/crypto.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/ecp_nistz.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/ecp_nistz256.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/gfp_p256.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/gfp_p384.c"),
(&[AARCH64, ARM, X86_64, X86], "crypto/limbs/limbs.c"),
(&[AARCH64, ARM, X86_64, X86], "third_party/fiat/curve25519.c"),
(&[X86_64, X86], "crypto/cpu-intel.c"),
@ -229,18 +230,19 @@ const LD_FLAGS: &[&str] = &[];
// None means "any OS" or "any target". The first match in sequence order is
// taken.
const ASM_TARGETS: &[(&str, Option<&str>, &str)] = &[
("x86_64", Some("ios"), "macosx"),
("x86_64", Some("macos"), "macosx"),
("x86_64", Some(WINDOWS), "nasm"),
("x86_64", None, "elf"),
("aarch64", Some("ios"), "ios64"),
("aarch64", None, "linux64"),
("x86", Some(WINDOWS), "win32n"),
("x86", Some("ios"), "macosx"),
("x86", None, "elf"),
("arm", Some("ios"), "ios32"),
("arm", None, "linux32"),
const ASM_TARGETS: &[(&str, Option<&str>, Option<&str>)] = &[
("x86_64", Some("ios"), Some("macosx")),
("x86_64", Some("macos"), Some("macosx")),
("x86_64", Some(WINDOWS), Some("nasm")),
("x86_64", None, Some("elf")),
("aarch64", Some("ios"), Some("ios64")),
("aarch64", None, Some("linux64")),
("x86", Some(WINDOWS), Some("win32n")),
("x86", Some("ios"), Some("macosx")),
("x86", None, Some("elf")),
("arm", Some("ios"), Some("ios32")),
("arm", None, Some("linux32")),
("wasm32", None, None),
];
const WINDOWS: &str = "windows";
@ -314,15 +316,18 @@ fn pregenerate_asm_main() {
&pregenerated
};
let perlasm_src_dsts = perlasm_src_dsts(&asm_dir, target_arch, target_os, perlasm_format);
perlasm(&perlasm_src_dsts, target_arch, perlasm_format, None);
if let Some(perlasm_format) = perlasm_format {
let perlasm_src_dsts =
perlasm_src_dsts(&asm_dir, target_arch, target_os, perlasm_format);
perlasm(&perlasm_src_dsts, target_arch, perlasm_format, None);
if target_os == Some(WINDOWS) {
let srcs = asm_srcs(perlasm_src_dsts);
for src in srcs {
let src_path = PathBuf::from(src);
let obj_path = obj_path(&pregenerated, &src_path, MSVC_OBJ_EXT);
run_command(yasm(&src_path, target_arch, &obj_path));
if target_os == Some(WINDOWS) {
let srcs = asm_srcs(perlasm_src_dsts);
for src in srcs {
let src_path = PathBuf::from(src);
let obj_path = obj_path(&pregenerated, &src_path, MSVC_OBJ_EXT);
run_command(yasm(&src_path, target_arch, &obj_path));
}
}
}
}
@ -339,8 +344,11 @@ struct Target {
}
fn build_c_code(target: &Target, pregenerated: PathBuf, out_dir: &Path) {
if &target.arch == "wasm32" {
return;
#[cfg(not(feature = "wasm32_c"))]
{
if &target.arch == "wasm32" {
return;
}
}
let includes_modified = RING_INCLUDES
@ -379,31 +387,37 @@ fn build_c_code(target: &Target, pregenerated: PathBuf, out_dir: &Path) {
out_dir
};
let perlasm_src_dsts =
perlasm_src_dsts(asm_dir, &target.arch, Some(&target.os), perlasm_format);
let asm_srcs = if let Some(perlasm_format) = perlasm_format {
let perlasm_src_dsts =
perlasm_src_dsts(asm_dir, &target.arch, Some(&target.os), perlasm_format);
if !use_pregenerated {
perlasm(
&perlasm_src_dsts[..],
&target.arch,
perlasm_format,
Some(includes_modified),
);
}
if !use_pregenerated {
perlasm(
&perlasm_src_dsts[..],
&target.arch,
perlasm_format,
Some(includes_modified),
);
}
let mut asm_srcs = asm_srcs(perlasm_src_dsts);
let mut asm_srcs = asm_srcs(perlasm_src_dsts);
// For Windows we also pregenerate the object files for non-Git builds so
// the user doesn't need to install the assembler. On other platforms we
// assume the C compiler also assembles.
if use_pregenerated && &target.os == WINDOWS {
// The pregenerated object files always use ".obj" as the extension,
// even when the C/C++ compiler outputs files with the ".o" extension.
asm_srcs = asm_srcs
.iter()
.map(|src| obj_path(&pregenerated, src.as_path(), "obj"))
.collect::<Vec<_>>();
}
// For Windows we also pregenerate the object files for non-Git builds so
// the user doesn't need to install the assembler. On other platforms we
// assume the C compiler also assembles.
if use_pregenerated && &target.os == WINDOWS {
// The pregenerated object files always use ".obj" as the extension,
// even when the C/C++ compiler outputs files with the ".o" extension.
asm_srcs = asm_srcs
.iter()
.map(|src| obj_path(&pregenerated, src.as_path(), "obj"))
.collect::<Vec<_>>();
}
asm_srcs
} else {
Vec::new()
};
let core_srcs = sources_for_arch(&target.arch)
.into_iter()
@ -549,7 +563,11 @@ fn cc(
for f in cpp_flags(target) {
let _ = c.flag(&f);
}
if &target.os != "none" && &target.os != "redox" && &target.os != "windows" {
if &target.os != "none"
&& &target.os != "redox"
&& &target.os != "windows"
&& target.arch != "wasm32"
{
let _ = c.flag("-fstack-protector");
}
@ -563,7 +581,8 @@ fn cc(
let _ = c.flag("-g3");
}
};
if !target.is_debug {
// We don't have assert.h for wasm32 targets.
if !target.is_debug || target.arch == "wasm32" {
let _ = c.define("NDEBUG", None);
}

View File

@ -87,6 +87,8 @@
#elif defined(__mips__) && defined(__LP64__)
#define OPENSSL_64_BIT
#define OPENSSL_MIPS64
#elif defined(__wasm__)
#define OPENSSL_32_BIT
#else
// Note BoringSSL only supports standard 32-bit and 64-bit two's-complement,
// little-endian architectures. Functions will not produce the correct answer

View File

@ -35,6 +35,16 @@
//! <tr><td><code>std</code>
//! <td>Enable features that use libstd, in particular `std::error::Error`
//! integration.
//! <tr><td><code>wasm32_c</code>
//! <td>Enables features that require a C compiler on wasm32 targets, such as
//! the <code>constant_time</code> module, HMAC verification, and PBKDF2
//! verification. Without this feature, only a subset of functionality
//! is provided to wasm32 targets so that a C compiler isn't needed. A
//! typical invocation would be:
//! <code>TARGET_AR=llvm-ar cargo test --target=wasm32-unknown-unknown --features=wasm32_c</code>
//! with <code>llvm-ar</code> and <code>clang</code> in <code>$PATH</code>.
//! (Going forward more functionality should be enabled by default, without
//! requiring these hacks, and without requiring a C compiler.)
//! </table>
#![doc(html_root_url = "https://briansmith.org/rustdoc/")]

View File

@ -14,8 +14,18 @@
use ring::{constant_time, error, rand};
#[cfg(all(target_arch = "wasm32", feature = "wasm32_c"))]
use wasm_bindgen_test::wasm_bindgen_test;
#[cfg(all(target_arch = "wasm32", feature = "wasm32_c"))]
use wasm_bindgen_test::wasm_bindgen_test_configure;
#[cfg(all(target_arch = "wasm32", feature = "wasm32_c"))]
wasm_bindgen_test_configure!(run_in_browser);
// This logic is loosly based on BoringSSL's `TEST(ConstantTimeTest, MemCmp)`.
#[test]
#[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
fn test_verify_slices_are_equal() {
let initial: [u8; 256] = rand::generate(&rand::SystemRandom::new()).unwrap().expose();

View File

@ -77,6 +77,7 @@ fn hkdf_tests() {
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn hkdf_output_len_tests() {
for &alg in &[hkdf::HKDF_SHA256, hkdf::HKDF_SHA384, hkdf::HKDF_SHA512] {
const MAX_BLOCKS: usize = 255;

View File

@ -32,7 +32,17 @@
use ring::{digest, error, hmac, test, test_file};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test_configure;
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test_configure!(run_in_browser);
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn hmac_tests() {
test::run(test_file!("hmac_tests.txt"), |section, test_case| {
assert_eq!(section, "");
@ -87,6 +97,8 @@ fn hmac_test_case_inner(
{
let signature = hmac::sign(&key, input);
assert_eq!(is_ok, signature.as_ref() == output);
#[cfg(any(not(target_arch = "wasm32"), feature = "wasm32_c"))]
assert_eq!(is_ok, hmac::verify(&key, input, output).is_ok());
}
@ -112,6 +124,7 @@ fn hmac_test_case_inner(
}
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn hmac_debug() {
let key = hmac::Key::new(hmac::HMAC_SHA256, &[0; 32]);
assert_eq!("Key { algorithm: SHA256 }", format!("{:?}", &key));

View File

@ -33,7 +33,18 @@
use core::num::NonZeroU32;
use ring::{digest, error, pbkdf2, test, test_file};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::wasm_bindgen_test_configure;
#[cfg(target_arch = "wasm32")]
wasm_bindgen_test_configure!(run_in_browser);
/// Test vectors from BoringSSL, Go, and other sources.
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
pub fn pbkdf2_tests() {
test::run(test_file!("pbkdf2_tests.txt"), |section, test_case| {
assert_eq!(section, "");
@ -69,6 +80,7 @@ pub fn pbkdf2_tests() {
assert_eq!(dk == out, verify_expected_result.is_ok() || dk.is_empty());
}
#[cfg(any(not(target_arch = "wasm32"), feature = "wasm32_c"))]
assert_eq!(
pbkdf2::verify(algorithm, iterations, &salt, &secret, &dk),
verify_expected_result