Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions build/wpt_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ PORT_BINDINGS = [
### (Invokes wpt_js_test_gen, wpt_wd_test_gen and wd_test to assemble a complete test suite.)
### -----------------------------------------------------------------------------------------

def wpt_test(name, wpt_directory, config, compat_date = "", compat_flags = [], autogates = [], start_server = False, **kwargs):
def wpt_test(name, wpt_directory, config, compat_date = "", compat_flags = [], autogates = [], start_server = False, include_tentative = False, **kwargs):
"""
Main entry point.

Expand Down Expand Up @@ -51,6 +51,7 @@ def wpt_test(name, wpt_directory, config, compat_date = "", compat_flags = [], a
wpt_directory = wpt_directory,
test_config = test_config_as_js,
wpt_tsproject = wpt_tsproject,
include_tentative = include_tentative,
)

wd_test_gen_rule = "{}@_wpt_wd_test_gen".format(name)
Expand Down Expand Up @@ -153,7 +154,7 @@ def _wpt_js_test_gen_impl(ctx):
base = ctx.attr.wpt_directory[WPTModuleInfo].base

files = ctx.attr.wpt_directory.files.to_list()
test_files = [file for file in files if is_test_file(file)]
test_files = [file for file in files if is_test_file(file, ctx.attr.include_tentative)]

ctx.actions.write(
output = src,
Expand All @@ -180,6 +181,8 @@ _wpt_js_test_gen = rule(
"test_config": attr.label(allow_single_file = True),
# Dependency: The ts_project rule that compiles the tests to JS
"wpt_tsproject": attr.label(),
# Whether to include tentative test files
"include_tentative": attr.bool(default = False),
},
)

Expand All @@ -196,7 +199,7 @@ const {{ run, printResults }} = createRunner(config, '{test_name}', allTestFiles
export const zzz_results = printResults();
"""

def is_test_file(file):
def is_test_file(file, include_tentative = False):
if not file.path.endswith(".js"):
# Not JS code, not a test
return False
Expand All @@ -207,7 +210,7 @@ def is_test_file(file):
# into the main directory, and would need to manually be marked as skipAllTests
return False

if ".tentative." in file.path or "/tentative/" in file.path:
if not include_tentative and (".tentative." in file.path or "/tentative/" in file.path):
# Tentative tests are for proposed features that are not yet standardized.
# We skip these to avoid noise from unstable specifications.
return False
Expand Down
51 changes: 51 additions & 0 deletions deps/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions deps/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ syn = { version = "2", features = ["full"] }
ada-url = "3"
anyhow = "1"
async-trait = { version = "0", default-features = false }
aws-lc-rs = { version = "1", default-features = false, features = ["non-fips"] }
aws-lc-sys = { version = "0", default-features = false }
capnp = "0"
capnpc = "0"
capnp-rpc = "0"
Expand Down
11 changes: 11 additions & 0 deletions src/rust/sha3/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
load("//:build/wd_rust_crate.bzl", "wd_rust_crate")

wd_rust_crate(
name = "sha3",
cxx_bridge_src = "lib.rs",
visibility = ["//visibility:public"],
deps = [
"@crates_vendor//:aws-lc-rs",
"@crates_vendor//:aws-lc-sys",
],
)
99 changes: 99 additions & 0 deletions src/rust/sha3/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::ptr::null_mut;

use aws_lc_rs::digest;
use aws_lc_sys::EVP_DigestFinalXOF;
use aws_lc_sys::EVP_DigestInit_ex;
use aws_lc_sys::EVP_DigestUpdate;
use aws_lc_sys::EVP_MD;
use aws_lc_sys::EVP_MD_CTX;
use aws_lc_sys::EVP_MD_CTX_free;
use aws_lc_sys::EVP_MD_CTX_new;
use aws_lc_sys::EVP_shake128;
use aws_lc_sys::EVP_shake256;

#[cxx::bridge(namespace = "workerd::rust::sha3")]
mod ffi {
extern "Rust" {
fn sha3_256(data: &[u8]) -> Vec<u8>;
fn sha3_384(data: &[u8]) -> Vec<u8>;
fn sha3_512(data: &[u8]) -> Vec<u8>;
fn cshake128(data: &[u8], output_len: usize) -> Vec<u8>;
fn cshake256(data: &[u8], output_len: usize) -> Vec<u8>;
}
}

#[must_use]
pub fn sha3_256(data: &[u8]) -> Vec<u8> {
digest::digest(&digest::SHA3_256, data).as_ref().to_vec()
}

#[must_use]
pub fn sha3_384(data: &[u8]) -> Vec<u8> {
digest::digest(&digest::SHA3_384, data).as_ref().to_vec()
}

#[must_use]
pub fn sha3_512(data: &[u8]) -> Vec<u8> {
digest::digest(&digest::SHA3_512, data).as_ref().to_vec()
}

struct EvpMdCtx(*mut EVP_MD_CTX);

impl EvpMdCtx {
fn new(md: *const EVP_MD) -> Self {
assert!(!md.is_null());

// SAFETY: EVP_MD_CTX_new does not take arguments and returns an owned context pointer or null.
let ctx = unsafe { EVP_MD_CTX_new() };
assert!(!ctx.is_null());

// SAFETY: ctx is a non-null context created above, md is a non-null AWS-LC digest descriptor,
// and a null ENGINE pointer is accepted by EVP_DigestInit_ex.
let ok = unsafe { EVP_DigestInit_ex(ctx, md, null_mut()) };
assert_eq!(ok, 1);
Self(ctx)
}
}

impl Drop for EvpMdCtx {
fn drop(&mut self) {
// SAFETY: self.0 is exclusively owned by this wrapper and was returned by EVP_MD_CTX_new.
unsafe {
EVP_MD_CTX_free(self.0);
}
}
}

type EvpMdFactory = unsafe extern "C" fn() -> *const EVP_MD;

fn shake(data: &[u8], output_len: usize, md_factory: EvpMdFactory) -> Vec<u8> {
if output_len == 0 {
return Vec::new();
}

// SAFETY: md_factory is one of AWS-LC's EVP_shake* functions and returns a static descriptor.
let md = unsafe { md_factory() };
let ctx = EvpMdCtx::new(md);
if !data.is_empty() {
// SAFETY: ctx owns a valid initialized EVP_MD_CTX, and data.as_ptr() is valid for data.len()
// bytes because data is non-empty.
let ok = unsafe { EVP_DigestUpdate(ctx.0, data.as_ptr().cast(), data.len()) };
assert_eq!(ok, 1);
}

let mut output = vec![0u8; output_len];
// SAFETY: ctx owns a valid SHAKE EVP_MD_CTX, and output is non-empty and writable for output.len().
let ok = unsafe { EVP_DigestFinalXOF(ctx.0, output.as_mut_ptr(), output.len()) };
assert_eq!(ok, 1);
output
}

#[must_use]
pub fn cshake128(data: &[u8], output_len: usize) -> Vec<u8> {
shake(data, output_len, EVP_shake128)
}

#[must_use]
pub fn cshake256(data: &[u8], output_len: usize) -> Vec<u8> {
shake(data, output_len, EVP_shake256)
}
7 changes: 4 additions & 3 deletions src/workerd/api/crypto/aes.c++
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,9 @@ class AesKeyBase: public CryptoKey::Impl {
}

SubtleCrypto::ExportKeyData exportKey(jsg::Lock& js, kj::StringPtr format) const override final {
JSG_REQUIRE(format == "raw" || format == "jwk", DOMNotSupportedError, getAlgorithmName(),
" key only supports exporting \"raw\" & \"jwk\", not \"", format, "\".");
JSG_REQUIRE(format == "raw" || format == "raw-secret" || format == "jwk", DOMNotSupportedError,
getAlgorithmName(),
" key only supports exporting \"raw\", \"raw-secret\" & \"jwk\", not \"", format, "\".");

if (format == "jwk") {
auto lengthInBytes = keyData.size();
Expand Down Expand Up @@ -786,7 +787,7 @@ kj::Own<CryptoKey::Impl> CryptoKey::Impl::importAes(jsg::Lock& js,

kj::Array<kj::byte> keyDataArray;

if (format == "raw") {
if (format == "raw" || format == "raw-secret") {
// NOTE: Checked in SubtleCrypto::importKey().
auto& source = keyData.get<jsg::JsRef<jsg::JsBufferSource>>();
auto handle = source.getHandle(js);
Expand Down
Loading
Loading