From 047f6d89f48719642dbe8abf82191a6d26334b75 Mon Sep 17 00:00:00 2001 From: Richard Zak Date: Fri, 7 Oct 2022 19:28:25 -0400 Subject: [PATCH] feat: use wasi-crypto as an optionl wasi feature Signed-off-by: Richard Zak --- .cargo/config | 10 ++++- Cargo.lock | 89 +++++++++++++++++++++++++++++------------ Cargo.toml | 7 ++++ rust-toolchain.toml | 2 +- src/crypto/hashing.rs | 51 ++++++++++++++++++++++++ src/crypto/mod.rs | 2 + src/crypto/spki.rs | 92 +++++++++++++++++++++++++++++++++++++++++++ src/ext/sgx/mod.rs | 3 +- src/ext/snp/mod.rs | 3 +- 9 files changed, 227 insertions(+), 32 deletions(-) create mode 100644 src/crypto/hashing.rs diff --git a/.cargo/config b/.cargo/config index bf0daa6d..17f4109d 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,3 +1,11 @@ +[env] +RUST_BACKTRACE = "1" +WASMTIME_BACKTRACE_DETAILS = "1" + +[build] +target = "wasm32-wasi" + [target.wasm32-wasi] rustflags = ["--cfg", "tokio_unstable"] -runner = ["enarx", "run", "--wasmcfgfile", "Enarx.toml"] +# runner = ["./enarx", "run", "--wasmcfgfile", "Enarx.toml"] +runner = ["/home/rjzak/bin/wasmtime-wasi-crypto", "--wasi-modules", "experimental-wasi-crypto", "--"] diff --git a/Cargo.lock b/Cargo.lock index 97ca4959..8a85647b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anyhow" version = "1.0.65" @@ -624,9 +615,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "lazy_static" @@ -706,6 +697,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint-dig" version = "0.8.1" @@ -764,6 +765,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "once_cell" version = "1.15.0" @@ -776,6 +798,12 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "p256" version = "0.11.1" @@ -992,9 +1020,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.7.0-rc.0" +version = "0.7.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a0c597c9fdb501f592f52e8ab754dc43787dd8a8bf20c191f562817d50b08" +checksum = "981bbf816bc9b572f90289a88a40fece97d096e68f3f26d7c0c45cf1f1c65790" dependencies = [ "byteorder", "digest", @@ -1159,9 +1187,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.3" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest", "rand_core", @@ -1243,6 +1271,7 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", + "wasi-crypto-guest", "x509-cert", "zeroize", ] @@ -1261,9 +1290,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", @@ -1412,9 +1441,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", @@ -1425,9 +1454,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -1436,9 +1465,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", "valuable", @@ -1467,12 +1496,12 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ - "ansi_term", "matchers", + "nu-ansi-term", "once_cell", "regex", "serde", @@ -1547,6 +1576,14 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi-crypto-guest" +version = "0.1.2" +source = "git+https://github.com/WebAssembly/wasi-crypto?branch=main#b9d6bad8c0e4a77403035ca5e4c62c86c869c80a" +dependencies = [ + "num_enum", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 36c526e6..0dbf9911 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,9 @@ confargs = "^0.1.3" [target.'cfg(not(target_os = "wasi"))'.dependencies] tokio = { version = "^1.21.2", features = ["rt-multi-thread", "macros"] } +[target.'cfg(target_os = "wasi")'.dependencies] +wasi-crypto-guest = { git = "https://github.com/WebAssembly/wasi-crypto", branch = "main", optional = true } + [dev-dependencies] tower = { version = "^0.4.11", features = ["util"] } axum = "^0.5.16" @@ -51,6 +54,10 @@ memoffset = "0.6.4" rstest = "0.15" testaso = "0.1" +[features] +default = [] +wasi-crypto = ["dep:wasi-crypto-guest"] + [profile.release] incremental = false codegen-units = 1 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c4700541..5d8aaf9e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "stable" +channel = "nightly" components = [ "rustfmt", "clippy" ] profile = "minimal" targets = [ "wasm32-wasi", "x86_64-unknown-linux-musl" ] diff --git a/src/crypto/hashing.rs b/src/crypto/hashing.rs new file mode 100644 index 00000000..3f6d3a6f --- /dev/null +++ b/src/crypto/hashing.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2022 Profian Inc. +// SPDX-License-Identifier: AGPL-3.0-only + +use anyhow::Result; + +#[cfg(all(target_os = "wasi", feature = "wasi-crypto"))] +use anyhow::anyhow; +#[cfg(all(target_os = "wasi", feature = "wasi-crypto"))] +use wasi_crypto_guest::prelude::Hash; + +#[cfg(any(not(target_os = "wasi"), not(feature = "wasi-crypto")))] +use sha2::{Digest, Sha256, Sha384}; + +#[inline] +pub fn sha256(data: impl AsRef<[u8]>) -> Result> { + #[cfg(all(target_os = "wasi", feature = "wasi-crypto"))] + return Ok(Hash::hash("SHA-256", data, 32, None).or_else(|_| Err(anyhow!("hash error")))?); + + #[cfg(any(not(target_os = "wasi"), not(feature = "wasi-crypto")))] + Ok(Sha256::digest(data).as_slice().to_vec()) +} + +#[inline] +pub fn sha384(data: impl AsRef<[u8]>) -> Result> { + #[cfg(all(target_os = "wasi", feature = "wasi-crypto"))] + return Ok(Hash::hash("SHA-384", data, 48, None).or_else(|_| Err(anyhow!("hash error")))?); + + #[cfg(any(not(target_os = "wasi"), not(feature = "wasi-crypto")))] + Ok(Sha384::digest(data).as_slice().to_vec()) +} + +#[cfg(all(target_os = "wasi", feature = "wasi-crypto"))] +#[cfg(test)] +mod wasi_crypto { + use crate::{sha256, sha384}; + use sha2::Digest; + + const DATA: &[u8] = b"SOME_TEST_DATA"; + + #[test] + fn test_sha256() { + let hash = sha256(DATA).unwrap(); + assert_eq!(hash, sha2::Sha256::digest(DATA).as_slice()); + } + + #[test] + fn test_sha384() { + let hash = sha384(DATA).unwrap(); + assert_eq!(hash, sha2::Sha384::digest(DATA).as_slice()); + } +} diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index a1a98822..598de0dd 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -3,10 +3,12 @@ mod cert; mod certreq; +mod hashing; mod pki; mod spki; pub use self::cert::TbsCertificateExt; pub use self::certreq::{CertReqExt, CertReqInfoExt}; +pub use self::hashing::{sha256, sha384}; pub use self::pki::PrivateKeyInfoExt; pub use self::spki::SubjectPublicKeyInfoExt; diff --git a/src/crypto/spki.rs b/src/crypto/spki.rs index a197eeb2..61fa4cbb 100644 --- a/src/crypto/spki.rs +++ b/src/crypto/spki.rs @@ -4,6 +4,8 @@ use anyhow::{anyhow, Result}; use const_oid::ObjectIdentifier; use der::{asn1::AnyRef, Sequence}; + +#[cfg(any(not(target_os = "wasi"), not(feature = "wasi-crypto")))] use rsa::pkcs1::DecodeRsaPublicKey; use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo}; @@ -13,6 +15,9 @@ use const_oid::db::rfc5912::{ SECP_256_R_1 as P256, SECP_384_R_1 as P384, }; +#[cfg(all(target_os = "wasi", feature = "wasi-crypto"))] +use wasi_crypto_guest::signatures::{Signature, SignaturePublicKey}; + const ES256: (ObjectIdentifier, Option>) = (ECDSA_WITH_SHA_256, None); const ES384: (ObjectIdentifier, Option>) = (ECDSA_WITH_SHA_384, None); @@ -43,6 +48,93 @@ pub trait SubjectPublicKeyInfoExt { } impl<'a> SubjectPublicKeyInfoExt for SubjectPublicKeyInfo<'a> { + #[cfg(all(target_os = "wasi", feature = "wasi-crypto"))] + fn verify(&self, body: &[u8], algo: AlgorithmIdentifier<'_>, sign: &[u8]) -> Result<()> { + let algo_name = match (self.algorithm.oids()?, (algo.oid, algo.parameters)) { + ((ECPK, Some(P256)), ES256) => "ECDSA_P256_SHA256", + ((ECPK, Some(P384)), ES384) => "ECDSA_P384_SHA384", + ((RSA, None), (ID_RSASSA_PSS, Some(p))) => { + // Decompose the RSA PSS parameters. + let RsaSsaPssParams { + hash_algorithm: hash, + mask_algorithm: mask, + salt_length: salt, + trailer_field: tfld, + } = p.decode_into().unwrap(); + + // Validate the sanity of the mask algorithm. + let algo = match (mask.oid, mask.parameters) { + (ID_MGF_1, Some(p)) => { + let p = p.decode_into::>()?; + match (p.oids()?, salt, tfld) { + ((SHA256, None), 32, 1) => Ok(SHA256), + ((SHA384, None), 48, 1) => Ok(SHA384), + ((SHA512, None), 64, 1) => Ok(SHA512), + ((x, y), s, t) => { + eprint!( + "Unknown RSA hash and components: {:?}, {:?}, salt {}, tfld {}", + x, y, s, t + ); + Err(anyhow!("unsupported")) + } + } + } + (x, _) => { + eprintln!("Unknown RSA OID {:?}", x); + Err(anyhow!("unsupported")) + } + } + .map_err(|e| { + eprintln!("Some algo error {:?}", e); + anyhow!("{:?}", e) + }) + .unwrap(); + + match (hash.oids()?, algo) { + ((SHA256, None), SHA256) => "RSA_PSS_2048_SHA256", + ((SHA384, None), SHA384) => "RSA_PSS_3072_SHA384", + ((SHA512, None), SHA512) => "RSA_PSS_4096_SHA512", + _ => { + eprintln!("Error unknown hash.oids"); + bail!("unsupported") + } + } + } + _ => { + eprintln!("Unknown algorithm, should not be here!"); + bail!("unsupported") + } + }; + + eprintln!("spki.rs verify() algo: {}", algo_name); + + let public_key = SignaturePublicKey::from_raw(algo_name, self.subject_public_key) + .map_err(|e| anyhow!("{:?}", e)) + .unwrap(); + + let signature = match algo_name { + "ECDSA_P256_SHA256" => { + let temp = p256::ecdsa::Signature::from_der(sign)?; + temp.to_vec() + } + "ECDSA_P384_SHA384" => { + let temp = p384::ecdsa::Signature::from_der(sign)?; + temp.to_vec() + } + _ => sign.to_vec(), + }; + + let signature = Signature::from_raw(algo_name, &signature) + .map_err(|e| anyhow!("{:?}", e)) + .unwrap(); + + Ok(public_key + .signature_verify(body, &signature) + .map_err(|e| anyhow!("{:?}", e)) + .unwrap()) + } + + #[cfg(any(not(target_os = "wasi"), not(feature = "wasi-crypto")))] fn verify(&self, body: &[u8], algo: AlgorithmIdentifier<'_>, sign: &[u8]) -> Result<()> { match (self.algorithm.oids()?, (algo.oid, algo.parameters)) { ((ECPK, Some(P256)), ES256) => { diff --git a/src/ext/sgx/mod.rs b/src/ext/sgx/mod.rs index d2828dbd..4b7a3e09 100644 --- a/src/ext/sgx/mod.rs +++ b/src/ext/sgx/mod.rs @@ -13,7 +13,6 @@ use anyhow::{anyhow, Result}; use const_oid::ObjectIdentifier; use der::{Decode, Encode}; use sgx::parameters::{Attributes, MiscSelect}; -use sha2::{Digest, Sha256}; use x509::{ext::Extension, request::CertReqInfo, Certificate, TbsCertificate}; #[derive(Clone, Debug)] @@ -84,7 +83,7 @@ impl ExtVerifier for Sgx { if !dbg { // TODO: Validate that the certification request came from an SGX enclave. - let hash = Sha256::digest(&cri.public_key.to_vec()?); + let hash = sha256(&cri.public_key.to_vec()?)?; if hash.as_slice() != &rpt.reportdata[..hash.as_slice().len()] { return Err(anyhow!("sgx report data is invalid")); } diff --git a/src/ext/snp/mod.rs b/src/ext/snp/mod.rs index 19a9e3b4..1c106605 100644 --- a/src/ext/snp/mod.rs +++ b/src/ext/snp/mod.rs @@ -13,7 +13,6 @@ use der::asn1::UIntRef; use der::{Decode, Encode, Sequence}; use flagset::{flags, FlagSet}; use pkcs8::AlgorithmIdentifier; -use sha2::Digest; use x509::ext::Extension; use x509::{request::CertReqInfo, Certificate}; use x509::{PkiPath, TbsCertificate}; @@ -374,7 +373,7 @@ impl ExtVerifier for Snp { if !dbg { // Validate that the certification request came from an SNP VM. - let hash = sha2::Sha384::digest(&cri.public_key.to_vec()?); + let hash = sha384(&cri.public_key.to_vec()?)?; if hash.as_slice() != &report.body.report_data[..hash.as_slice().len()] { return Err(anyhow!("snp report.report_data is invalid")); }