diff --git a/internal/crypto/Cargo.toml b/internal/crypto/Cargo.toml index 3d7540a26..7c55915c7 100644 --- a/internal/crypto/Cargo.toml +++ b/internal/crypto/Cargo.toml @@ -31,6 +31,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] json_schema = ["dep:schemars"] +rust_native_crypto = ["dep:ed25519-dalek"] [dependencies] asn1-rs = "0.6.2" @@ -43,6 +44,7 @@ c2pa-status-tracker = { path = "../status-tracker", version = "0.2.0" } ciborium = "0.2.2" const-hex = "1.14" coset = "0.3.1" +ed25519-dalek = { version = "2.1.1", features = ["alloc", "digest", "pem", "pkcs8"], optional = true } getrandom = { version = "0.2.7", features = ["js"] } hex = "0.4.3" nom = "7.1.3" @@ -101,8 +103,12 @@ web-sys = { version = "0.3.58", features = [ getrandom = { version = "0.2.7", features = ["js"] } js-sys = "0.3.58" +[dev-dependencies] +ed25519-dalek = { version = "2.1.1", features = ["alloc", "digest", "pem", "pkcs8"] } + [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] actix = "0.13.1" +ed25519-dalek = { version = "2.1.1", features = ["alloc", "digest", "pem", "pkcs8"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3.31" diff --git a/internal/crypto/README.md b/internal/crypto/README.md index 75f91760f..a57f5315c 100644 --- a/internal/crypto/README.md +++ b/internal/crypto/README.md @@ -4,6 +4,61 @@ This crate contains some of the internal cryptography implementation that is shared between the [c2pa crate](https://crates.io/crates/c2pa) and the [CAWG identity SDK crate](https://crates.io/crates/cawg-identity). It is not intended to be used directly in most cases. +## Crate features + +This crate has two features, neither of which are enabled by default: + +* `json_schema`: Used by c2pa-rs documentation code to generate JSON schema for types defined in this crate. +* `rust_native_crypto`: Where available, prefer Rust-native cryptography libraries for raw signature and validation implementations. (Experimental) + +## Cryptographic library support + +`c2pa-crypto` will use different cryptography libraries depending on which platform and feature flags are used: + +### Signing (synchronous or asynchronous) + +| C2PA `SigningAlg` | Default (*) | `feature = "rust_native_crypto"` (*) | WASM | +| --- | --- | --- | --- | +| `es256` | OpenSSL | OpenSSL | ❌ | +| `es384` | OpenSSL | OpenSSL | ❌ | +| `es512` | OpenSSL | OpenSSL | ❌ | +| `ed25519` | OpenSSL | `ed25519-dalek` | `ed25519-dalek` | +| `ps256` | OpenSSL | OpenSSL | ❌ | +| `ps384` | OpenSSL | OpenSSL | ❌ | +| `ps512` | OpenSSL | OpenSSL | ❌ | + +(*) Applies to all supported platforms except WASM
+❌ = not supported + +### Validation (synchronous) + +| C2PA `SigningAlg` | Default (*) | `feature = "rust_native_crypto"` (*) | WASM | +| --- | --- | --- | --- | +| `es256` | OpenSSL | OpenSSL | `p256` | +| `es384` | OpenSSL | OpenSSL | `p384` | +| `es512` | OpenSSL | OpenSSL | ❌ | +| `ed25519` | OpenSSL | `ed25519-dalek` | `ed25519-dalek` | +| `ps256` | OpenSSL | OpenSSL | `rsa` | +| `ps384` | OpenSSL | OpenSSL | `rsa` | +| `ps512` | OpenSSL | OpenSSL | `rsa` | + +(*) Applies to all supported platforms except WASM
+❌ = not supported + +### Validation (asynchronous) + +| C2PA `SigningAlg` | Default (*) | `feature = "rust_native_crypto"` (*) | WASM | +| --- | --- | --- | --- | +| `es256` | OpenSSL | OpenSSL | WebCrypto | +| `es384` | OpenSSL | OpenSSL | WebCrypto | +| `es512` | OpenSSL | OpenSSL | WebCrypto | +| `ed25519` | OpenSSL | `ed25519-dalek` | `ed25519-dalek` | +| `ps256` | OpenSSL | OpenSSL | `rsa` | +| `ps384` | OpenSSL | OpenSSL | `rsa` | +| `ps512` | OpenSSL | OpenSSL | `rsa` | + +(*) Applies to all supported platforms except WASM + ### Contributions and feedback We welcome contributions to this project. For information on contributing, providing feedback, and about ongoing work, see [Contributing](https://github.com/contentauth/c2pa-rs/blob/main/CONTRIBUTING.md). For additional information on nightly builds and testing, see [Contributing to the project](docs/project-contributions.md). diff --git a/internal/crypto/src/raw_signature/mod.rs b/internal/crypto/src/raw_signature/mod.rs index e28f61542..c5caf309f 100644 --- a/internal/crypto/src/raw_signature/mod.rs +++ b/internal/crypto/src/raw_signature/mod.rs @@ -18,6 +18,9 @@ pub(crate) mod oids; #[cfg(not(target_arch = "wasm32"))] pub(crate) mod openssl; +#[cfg(any(target_arch = "wasm32", feature = "rust_native_crypto", test))] +pub(crate) mod rust_native; + pub(crate) mod signer; pub use signer::{ async_signer_from_cert_chain_and_private_key, signer_from_cert_chain_and_private_key, diff --git a/internal/crypto/src/raw_signature/openssl/mod.rs b/internal/crypto/src/raw_signature/openssl/mod.rs index 7cbff7d7a..98aec396f 100644 --- a/internal/crypto/src/raw_signature/openssl/mod.rs +++ b/internal/crypto/src/raw_signature/openssl/mod.rs @@ -21,8 +21,8 @@ mod cert_chain; mod ffi_mutex; -pub use ffi_mutex::{OpenSslMutex, OpenSslMutexUnavailable}; +pub(crate) use ffi_mutex::{OpenSslMutex, OpenSslMutexUnavailable}; pub(crate) mod check_certificate_trust; pub(crate) mod signers; -pub mod validators; +pub(crate) mod validators; diff --git a/internal/crypto/src/raw_signature/rust_native/mod.rs b/internal/crypto/src/raw_signature/rust_native/mod.rs new file mode 100644 index 000000000..dce099230 --- /dev/null +++ b/internal/crypto/src/raw_signature/rust_native/mod.rs @@ -0,0 +1,24 @@ +// Copyright 2025 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. + +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +#![allow(unused)] // Not used on all platforms or all configs + +//! Experimental support for synchronous raw signatures using Rust-native +//! crates. Intended mostly for the synchronous use cases on WASM, but may +//! eventually be used on all platforms. +//! +//! At the moment, does not offer support for all C2PA-supported cryptography +//! algorithms. + +pub(crate) mod signers; +pub(crate) mod validators; diff --git a/internal/crypto/src/raw_signature/webcrypto/signers/ed25519_signer.rs b/internal/crypto/src/raw_signature/rust_native/signers/ed25519_signer.rs similarity index 100% rename from internal/crypto/src/raw_signature/webcrypto/signers/ed25519_signer.rs rename to internal/crypto/src/raw_signature/rust_native/signers/ed25519_signer.rs diff --git a/internal/crypto/src/raw_signature/webcrypto/signers/mod.rs b/internal/crypto/src/raw_signature/rust_native/signers/mod.rs similarity index 88% rename from internal/crypto/src/raw_signature/webcrypto/signers/mod.rs rename to internal/crypto/src/raw_signature/rust_native/signers/mod.rs index 29d195f65..3e6904cea 100644 --- a/internal/crypto/src/raw_signature/webcrypto/signers/mod.rs +++ b/internal/crypto/src/raw_signature/rust_native/signers/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2024 Adobe. All rights reserved. +// Copyright 2025 Adobe. All rights reserved. // This file is licensed to you under the Apache License, // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) // or the MIT license (http://opensource.org/licenses/MIT), @@ -11,6 +11,9 @@ // specific language governing permissions and limitations under // each license. +//! This module binds Rust native logic for generating raw signatures to this +//! crate's [`RawSigner`] trait. + use crate::raw_signature::{RawSigner, RawSignerError, SigningAlg}; mod ed25519_signer; @@ -39,7 +42,7 @@ pub(crate) fn signer_from_cert_chain_and_private_key( )), _ => Err(RawSignerError::InternalError(format!( - "unsupported algorithm: {alg}" + "unsupported signing algorithm {alg}" ))), } } diff --git a/internal/crypto/src/raw_signature/webcrypto/validators/ed25519_validator.rs b/internal/crypto/src/raw_signature/rust_native/validators/ed25519_validator.rs similarity index 92% rename from internal/crypto/src/raw_signature/webcrypto/validators/ed25519_validator.rs rename to internal/crypto/src/raw_signature/rust_native/validators/ed25519_validator.rs index f38556280..b4cc795db 100644 --- a/internal/crypto/src/raw_signature/webcrypto/validators/ed25519_validator.rs +++ b/internal/crypto/src/raw_signature/rust_native/validators/ed25519_validator.rs @@ -27,7 +27,7 @@ impl RawSignatureValidator for Ed25519Validator { data: &[u8], public_key: &[u8], ) -> Result<(), RawSignatureValidationError> { - let (_, public_key) = SubjectPublicKeyInfo::from_der(&public_key) + let (_, public_key) = SubjectPublicKeyInfo::from_der(public_key) .map_err(|_| RawSignatureValidationError::InvalidPublicKey)?; let public_key = public_key @@ -43,7 +43,7 @@ impl RawSignatureValidator for Ed25519Validator { } let mut public_key_slice: [u8; PUBLIC_KEY_LENGTH] = Default::default(); - public_key_slice.copy_from_slice(&public_key); + public_key_slice.copy_from_slice(public_key); let vk = VerifyingKey::from_bytes(&public_key_slice) .map_err(|_| RawSignatureValidationError::InvalidPublicKey)?; @@ -51,7 +51,7 @@ impl RawSignatureValidator for Ed25519Validator { let ed_sig = Signature::from_slice(sig) .map_err(|_| RawSignatureValidationError::InvalidSignature)?; - match vk.verify(&data, &ed_sig) { + match vk.verify(data, &ed_sig) { Ok(_) => Ok(()), Err(_) => Err(RawSignatureValidationError::SignatureMismatch), } diff --git a/internal/crypto/src/raw_signature/rust_native/validators/mod.rs b/internal/crypto/src/raw_signature/rust_native/validators/mod.rs new file mode 100644 index 000000000..5264993e0 --- /dev/null +++ b/internal/crypto/src/raw_signature/rust_native/validators/mod.rs @@ -0,0 +1,30 @@ +// Copyright 2025 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. + +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +//! This module binds Rust native logic for generating raw signatures to this +//! crate's [`RawSignatureValidator`] trait. + +use bcder::Oid; + +use crate::raw_signature::{oids::*, RawSignatureValidator, SigningAlg}; + +mod ed25519_validator; +pub use ed25519_validator::Ed25519Validator; + +/// Return a validator for the given signing algorithm. +pub fn validator_for_signing_alg(alg: SigningAlg) -> Option> { + match alg { + SigningAlg::Ed25519 => Some(Box::new(Ed25519Validator {})), + _ => None, + } +} diff --git a/internal/crypto/src/raw_signature/signer.rs b/internal/crypto/src/raw_signature/signer.rs index 37957fd56..f5f7c1bac 100644 --- a/internal/crypto/src/raw_signature/signer.rs +++ b/internal/crypto/src/raw_signature/signer.rs @@ -165,19 +165,23 @@ pub fn signer_from_cert_chain_and_private_key( alg: SigningAlg, time_stamp_service_url: Option, ) -> Result, RawSignerError> { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(any(target_arch = "wasm32", feature = "rust_native_crypto"))] { - return crate::raw_signature::openssl::signers::signer_from_cert_chain_and_private_key( + match crate::raw_signature::rust_native::signers::signer_from_cert_chain_and_private_key( cert_chain, private_key, alg, - time_stamp_service_url, - ); + time_stamp_service_url.clone(), + ) { + Ok(signer) => return Ok(signer), + Err(RawSignerError::InternalError(_)) => (), + Err(err) => return Err(err), + } } - #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] + #[cfg(not(target_arch = "wasm32"))] { - return crate::raw_signature::webcrypto::signers::signer_from_cert_chain_and_private_key( + return crate::raw_signature::openssl::signers::signer_from_cert_chain_and_private_key( cert_chain, private_key, alg, diff --git a/internal/crypto/src/raw_signature/validator.rs b/internal/crypto/src/raw_signature/validator.rs index caab5948b..0e597e1ac 100644 --- a/internal/crypto/src/raw_signature/validator.rs +++ b/internal/crypto/src/raw_signature/validator.rs @@ -65,6 +65,15 @@ pub trait AsyncRawSignatureValidator { /// Which validators are available may vary depending on the platform and /// which crate features were enabled. pub fn validator_for_signing_alg(alg: SigningAlg) -> Option> { + #[cfg(any(target_arch = "wasm32", feature = "rust_native_crypto"))] + { + if let Some(validator) = + crate::raw_signature::rust_native::validators::validator_for_signing_alg(alg) + { + return Some(validator); + } + } + #[cfg(not(target_arch = "wasm32"))] if let Some(validator) = crate::raw_signature::openssl::validators::validator_for_signing_alg(alg) diff --git a/internal/crypto/src/raw_signature/webcrypto/async_validators/ed25519_validator.rs b/internal/crypto/src/raw_signature/webcrypto/async_validators/ed25519_validator.rs index db1656d5e..73cf95017 100644 --- a/internal/crypto/src/raw_signature/webcrypto/async_validators/ed25519_validator.rs +++ b/internal/crypto/src/raw_signature/webcrypto/async_validators/ed25519_validator.rs @@ -31,7 +31,7 @@ impl AsyncRawSignatureValidator for Ed25519Validator { ) -> Result<(), RawSignatureValidationError> { // Sync and async cases are identical for Ed25519. - let sync_validator = crate::raw_signature::webcrypto::validators::Ed25519Validator {}; + let sync_validator = crate::raw_signature::rust_native::validators::Ed25519Validator {}; sync_validator.validate(sig, data, public_key) } } diff --git a/internal/crypto/src/raw_signature/webcrypto/mod.rs b/internal/crypto/src/raw_signature/webcrypto/mod.rs index ec62a2f1a..874f80e40 100644 --- a/internal/crypto/src/raw_signature/webcrypto/mod.rs +++ b/internal/crypto/src/raw_signature/webcrypto/mod.rs @@ -25,8 +25,7 @@ pub(crate) use async_validators::{ }; pub(crate) mod check_certificate_trust; -pub(crate) mod signers; -pub mod validators; +pub(crate) mod validators; mod window_or_worker; pub use window_or_worker::{WasmCryptoError, WindowOrWorker}; diff --git a/internal/crypto/src/raw_signature/webcrypto/validators/mod.rs b/internal/crypto/src/raw_signature/webcrypto/validators/mod.rs index 679e83c0c..2c28218f1 100644 --- a/internal/crypto/src/raw_signature/webcrypto/validators/mod.rs +++ b/internal/crypto/src/raw_signature/webcrypto/validators/mod.rs @@ -21,9 +21,6 @@ use crate::raw_signature::{oids::*, RawSignatureValidator, SigningAlg}; mod ecdsa_validator; pub use ecdsa_validator::EcdsaValidator; -mod ed25519_validator; -pub use ed25519_validator::Ed25519Validator; - mod rsa_legacy_validator; pub(crate) use rsa_legacy_validator::RsaLegacyValidator; @@ -36,10 +33,10 @@ pub fn validator_for_signing_alg(alg: SigningAlg) -> Option Some(Box::new(EcdsaValidator::Es256)), SigningAlg::Es384 => Some(Box::new(EcdsaValidator::Es384)), SigningAlg::Es512 => None, /* why is this unimplemented? */ - SigningAlg::Ed25519 => Some(Box::new(Ed25519Validator {})), SigningAlg::Ps256 => Some(Box::new(RsaValidator::Ps256)), SigningAlg::Ps384 => Some(Box::new(RsaValidator::Ps384)), SigningAlg::Ps512 => Some(Box::new(RsaValidator::Ps512)), + _ => None, } } diff --git a/internal/crypto/src/tests/raw_signature/mod.rs b/internal/crypto/src/tests/raw_signature/mod.rs index 0981a4dce..287dcc213 100644 --- a/internal/crypto/src/tests/raw_signature/mod.rs +++ b/internal/crypto/src/tests/raw_signature/mod.rs @@ -13,5 +13,6 @@ mod async_signers; mod async_validators; +mod rust_native; mod signers; mod validators; diff --git a/internal/crypto/src/tests/raw_signature/rust_native/mod.rs b/internal/crypto/src/tests/raw_signature/rust_native/mod.rs new file mode 100644 index 000000000..0ee060244 --- /dev/null +++ b/internal/crypto/src/tests/raw_signature/rust_native/mod.rs @@ -0,0 +1,15 @@ +// Copyright 2025 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. + +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +mod signers; +mod validators; diff --git a/internal/crypto/src/tests/raw_signature/rust_native/signers.rs b/internal/crypto/src/tests/raw_signature/rust_native/signers.rs new file mode 100644 index 000000000..381dac4c8 --- /dev/null +++ b/internal/crypto/src/tests/raw_signature/rust_native/signers.rs @@ -0,0 +1,180 @@ +// Copyright 2025 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. + +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::wasm_bindgen_test; + +use crate::raw_signature::{rust_native, SigningAlg}; + +/* Not implemented in rust_native yet. +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn es256() { + let cert_chain = include_bytes!("../../fixtures/raw_signature/es256.pub"); + let private_key = include_bytes!("../../fixtures/raw_signature/es256.priv"); + + let signer = + rust_native::signer_from_cert_chain_and_private_key(cert_chain, private_key, SigningAlg::Es256, None) + .unwrap(); + + let data = b"some sample content to sign"; + let signature = signer.sign(data).unwrap(); + + println!("signature len = {}", signature.len()); + assert!(signature.len() <= signer.reserve_size()); + + let pub_key = include_bytes!("../../fixtures/raw_signature/es256.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es256).unwrap(); + validator.validate(&signature, data, pub_key).unwrap(); +} + +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn es384() { + let cert_chain = include_bytes!("../../fixtures/raw_signature/es384.pub"); + let private_key = include_bytes!("../../fixtures/raw_signature/es384.priv"); + + let signer = + rust_native::signer_from_cert_chain_and_private_key(cert_chain, private_key, SigningAlg::Es384, None) + .unwrap(); + + let data = b"some sample content to sign"; + let signature = signer.sign(data).unwrap(); + + println!("signature len = {}", signature.len()); + assert!(signature.len() <= signer.reserve_size()); + + let pub_key = include_bytes!("../../fixtures/raw_signature/es384.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es384).unwrap(); + validator.validate(&signature, data, pub_key).unwrap(); +} + +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn es512() { + let cert_chain = include_bytes!("../../fixtures/raw_signature/es512.pub"); + let private_key = include_bytes!("../../fixtures/raw_signature/es512.priv"); + + let signer = + rust_native::signer_from_cert_chain_and_private_key(cert_chain, private_key, SigningAlg::Es512, None) + .unwrap(); + + let data = b"some sample content to sign"; + let signature = signer.sign(data).unwrap(); + + println!("signature len = {}", signature.len()); + assert!(signature.len() <= signer.reserve_size()); + + let pub_key = include_bytes!("../../fixtures/raw_signature/es512.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es512).unwrap(); + validator.validate(&signature, data, pub_key).unwrap(); +} +*/ + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ed25519() { + let cert_chain = include_bytes!("../../fixtures/raw_signature/ed25519.pub"); + let private_key = include_bytes!("../../fixtures/raw_signature/ed25519.priv"); + + let signer = rust_native::signers::signer_from_cert_chain_and_private_key( + cert_chain, + private_key, + SigningAlg::Ed25519, + None, + ) + .unwrap(); + + let data = b"some sample content to sign"; + let signature = signer.sign(data).unwrap(); + + println!("signature len = {}", signature.len()); + assert!(signature.len() <= signer.reserve_size()); + + let pub_key = include_bytes!("../../fixtures/raw_signature/ed25519.pub_key"); + + let validator = + rust_native::validators::validator_for_signing_alg(SigningAlg::Ed25519).unwrap(); + validator.validate(&signature, data, pub_key).unwrap(); +} + +/* Not implemented in rust_native yet. +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps256() { + let cert_chain = include_bytes!("../../fixtures/raw_signature/ps256.pub"); + let private_key = include_bytes!("../../fixtures/raw_signature/ps256.priv"); + + let signer = + rust_native::signer_from_cert_chain_and_private_key(cert_chain, private_key, SigningAlg::Ps256, None) + .unwrap(); + + let data = b"some sample content to sign"; + let signature = signer.sign(data).unwrap(); + + println!("signature len = {}", signature.len()); + assert!(signature.len() <= signer.reserve_size()); + + let pub_key = include_bytes!("../../fixtures/raw_signature/ps256.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps256).unwrap(); + validator.validate(&signature, data, pub_key).unwrap(); +} + +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps384() { + let cert_chain = include_bytes!("../../fixtures/raw_signature/ps384.pub"); + let private_key = include_bytes!("../../fixtures/raw_signature/ps384.priv"); + + let signer = + rust_native::signer_from_cert_chain_and_private_key(cert_chain, private_key, SigningAlg::Ps384, None) + .unwrap(); + + let data = b"some sample content to sign"; + let signature = signer.sign(data).unwrap(); + + println!("signature len = {}", signature.len()); + assert!(signature.len() <= signer.reserve_size()); + + let pub_key = include_bytes!("../../fixtures/raw_signature/ps384.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps384).unwrap(); + validator.validate(&signature, data, pub_key).unwrap(); +} + +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps512() { + let cert_chain = include_bytes!("../../fixtures/raw_signature/ps512.pub"); + let private_key = include_bytes!("../../fixtures/raw_signature/ps512.priv"); + + let signer = + rust_native::signer_from_cert_chain_and_private_key(cert_chain, private_key, SigningAlg::Ps512, None) + .unwrap(); + + let data = b"some sample content to sign"; + let signature = signer.sign(data).unwrap(); + + println!("signature len = {}", signature.len()); + assert!(signature.len() <= signer.reserve_size()); + + let pub_key = include_bytes!("../../fixtures/raw_signature/ps512.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps512).unwrap(); + validator.validate(&signature, data, pub_key).unwrap(); +} +*/ diff --git a/internal/crypto/src/tests/raw_signature/rust_native/validators.rs b/internal/crypto/src/tests/raw_signature/rust_native/validators.rs new file mode 100644 index 000000000..a58ec18af --- /dev/null +++ b/internal/crypto/src/tests/raw_signature/rust_native/validators.rs @@ -0,0 +1,288 @@ +// Copyright 2024 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. + +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::wasm_bindgen_test; + +use crate::raw_signature::{rust_native, RawSignatureValidationError, SigningAlg}; + +const SAMPLE_DATA: &[u8] = b"some sample content to sign"; + +/* Not implemented in rust_native yet. +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn es256() { + let signature = include_bytes!("../../fixtures/raw_signature/es256.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/es256.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es256).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn es256_bad_signature() { + let mut signature = include_bytes!("../../fixtures/raw_signature/es256.raw_sig").to_vec(); + assert_ne!(signature[10], 10); + signature[10] = 10; + + let pub_key = include_bytes!("../../fixtures/raw_signature/es256.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es256).unwrap(); + + assert_eq!( + validator + .validate(&signature, SAMPLE_DATA, pub_key) + .unwrap_err(), + RawSignatureValidationError::SignatureMismatch + ); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn es256_bad_data() { + let signature = include_bytes!("../../fixtures/raw_signature/es256.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/es256.pub_key"); + + let mut data = SAMPLE_DATA.to_vec(); + data[10] = 0; + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es256).unwrap(); + + assert_eq!( + validator.validate(signature, &data, pub_key).unwrap_err(), + RawSignatureValidationError::SignatureMismatch + ); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn es384() { + let signature = include_bytes!("../../fixtures/raw_signature/es384.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/es384.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es384).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] // ES512 not +// implemented +fn es512() { + let signature = include_bytes!("../../fixtures/raw_signature/es512.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/es512.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Es512).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} +*/ + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ed25519() { + let signature = include_bytes!("../../fixtures/raw_signature/ed25519.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/ed25519.pub_key"); + + let validator = + rust_native::validators::validator_for_signing_alg(SigningAlg::Ed25519).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ed25519_bad_data() { + let signature = include_bytes!("../../fixtures/raw_signature/ed25519.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/ed25519.pub_key"); + + let mut data = SAMPLE_DATA.to_vec(); + data[5] = 10; + data[6] = 11; + + let validator = + rust_native::validators::validator_for_signing_alg(SigningAlg::Ed25519).unwrap(); + + assert_eq!( + validator.validate(signature, &data, pub_key).unwrap_err(), + RawSignatureValidationError::SignatureMismatch + ); +} + +/* Not implemented in rust_native yet. +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps256() { + let signature = include_bytes!("../../fixtures/raw_signature/ps256.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/ps256.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps256).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps256_bad_signature() { + let mut signature = include_bytes!("../../fixtures/raw_signature/ps256.raw_sig").to_vec(); + assert_ne!(signature[10], 10); + signature[10] = 10; + + let pub_key = include_bytes!("../../fixtures/raw_signature/ps256.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps256).unwrap(); + + assert_eq!( + validator + .validate(&signature, SAMPLE_DATA, pub_key) + .unwrap_err(), + RawSignatureValidationError::SignatureMismatch + ); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps256_bad_data() { + let signature = include_bytes!("../../fixtures/raw_signature/ps256.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/ps256.pub_key"); + + let mut data = SAMPLE_DATA.to_vec(); + data[10] = 0; + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps256).unwrap(); + + assert_eq!( + validator.validate(signature, &data, pub_key).unwrap_err(), + RawSignatureValidationError::SignatureMismatch + ); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps384() { + let signature = include_bytes!("../../fixtures/raw_signature/ps384.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/ps384.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps384).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn ps512() { + let signature = include_bytes!("../../fixtures/raw_signature/ps512.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/ps512.pub_key"); + + let validator = rust_native::validators::validator_for_signing_alg(SigningAlg::Ps512).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +// Argh. Different Oid types across different crates, so we have to construct +// our own constants here. +const RSA_OID: Oid = bcder::Oid(OctetString::from_static(&[ + 42, 134, 72, 134, 247, 13, 1, 1, 1, +])); + +const SHA256_OID: Oid = bcder::Oid(OctetString::from_static(&[96, 134, 72, 1, 101, 3, 4, 2, 1])); + +const SHA384_OID: Oid = bcder::Oid(OctetString::from_static(&[96, 134, 72, 1, 101, 3, 4, 2, 2])); + +const SHA512_OID: Oid = bcder::Oid(OctetString::from_static(&[96, 134, 72, 1, 101, 3, 4, 2, 3])); + +const SHA1_OID: Oid = bcder::Oid(OctetString::from_static(&[43, 14, 3, 2, 26])); + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn legacy_rs256() { + let signature = include_bytes!("../../fixtures/raw_signature/legacy/rs256.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/legacy/rs256.pub_key"); + + let validator = validator_for_sig_and_hash_algs(&RSA_OID, &SHA256_OID).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn legacy_rs256_bad_signature() { + let mut signature = include_bytes!("../../fixtures/raw_signature/legacy/rs256.raw_sig").to_vec(); + assert_ne!(signature[10], 10); + signature[10] = 10; + + let pub_key = include_bytes!("../../fixtures/raw_signature/legacy/rs256.pub_key"); + + let validator = validator_for_sig_and_hash_algs(&RSA_OID, &SHA256_OID).unwrap(); + + assert_eq!( + validator + .validate(&signature, SAMPLE_DATA, pub_key) + .unwrap_err(), + RawSignatureValidationError::SignatureMismatch + ); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn legacy_rs256_bad_data() { + let signature = include_bytes!("../../fixtures/raw_signature/legacy/rs256.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/legacy/rs256.pub_key"); + + let mut data = SAMPLE_DATA.to_vec(); + data[10] = 0; + + let validator = validator_for_sig_and_hash_algs(&RSA_OID, &SHA256_OID).unwrap(); + + assert_eq!( + validator.validate(signature, &data, pub_key).unwrap_err(), + RawSignatureValidationError::SignatureMismatch + ); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn rs384() { + let signature = include_bytes!("../../fixtures/raw_signature/legacy/rs384.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/legacy/rs384.pub_key"); + + let validator = validator_for_sig_and_hash_algs(&RSA_OID, &SHA384_OID).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn rs512() { + let signature = include_bytes!("../../fixtures/raw_signature/legacy/rs512.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/legacy/rs512.pub_key"); + + let validator = validator_for_sig_and_hash_algs(&RSA_OID, &SHA512_OID).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} + +#[test] +// #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] // SHA1 not +// implemented +fn sha1() { + let signature = include_bytes!("../../fixtures/raw_signature/legacy/sha1.raw_sig"); + let pub_key = include_bytes!("../../fixtures/raw_signature/legacy/sha1.pub_key"); + + let validator = validator_for_sig_and_hash_algs(&RSA_OID, &SHA1_OID).unwrap(); + + validator.validate(signature, SAMPLE_DATA, pub_key).unwrap(); +} +*/