diff --git a/export_schema/Cargo.toml b/export_schema/Cargo.toml index f5baf9e3b..3c81e827b 100644 --- a/export_schema/Cargo.toml +++ b/export_schema/Cargo.toml @@ -8,6 +8,6 @@ rust-version = "1.76.0" [dependencies] anyhow = "1.0.40" -c2pa = { path = "../sdk", features = ["json_schema", "unstable_api"] } +c2pa = { path = "../sdk", default-features = false, features = ["json_schema", "unstable_api"] } schemars = "0.8.21" serde_json = "1.0.117" diff --git a/internal/crypto/Cargo.toml b/internal/crypto/Cargo.toml index c74b6d582..277782da4 100644 --- a/internal/crypto/Cargo.toml +++ b/internal/crypto/Cargo.toml @@ -27,7 +27,11 @@ rustdoc-args = ["--cfg", "docsrs"] [features] json_schema = ["dep:schemars"] -openssl = ["dep:openssl"] +openssl = ["dep:openssl", "_anyssl"] +boringssl = ["dep:boring", "dep:pkcs8", "dep:pkcs1", "_anyssl"] + +# Internal-only. Use the `openssl` feature to enable it. +_anyssl = [] [dependencies] base64 = "0.22.1" @@ -45,6 +49,9 @@ x509-certificate = "0.21.0" x509-parser = "0.16.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] +boring = { version = "4.13", optional = true } +pkcs8 = { version = "0.10.2", features = ["std"], optional = true } +pkcs1 = { version = "0.7.5", features = ["pem", "std"], optional = true } openssl = { version = "0.10.61", features = ["vendored"], optional = true } ureq = "2.4.0" url = "2.5.3" diff --git a/internal/crypto/src/lib.rs b/internal/crypto/src/lib.rs index f19a50fa0..d06ec4467 100644 --- a/internal/crypto/src/lib.rs +++ b/internal/crypto/src/lib.rs @@ -26,12 +26,15 @@ pub(crate) mod internal; pub mod ocsp; -#[cfg(all(feature = "openssl", not(target_arch = "wasm32")))] -pub mod openssl; - -#[cfg(all(feature = "openssl", target_arch = "wasm32"))] +#[cfg(all(feature = "_anyssl", target_arch = "wasm32"))] compile_error!("OpenSSL feature is not compatible with WASM platform"); +#[cfg(all(feature = "boringssl", feature = "openssl"))] +compile_error!("BoringSSL and OpenSSL can't be both enabled at the same time"); + +#[cfg(feature = "_anyssl")] +pub mod openssl; + pub mod raw_signature; mod signing_alg; diff --git a/internal/crypto/src/openssl/validators/ecdsa_validator.rs b/internal/crypto/src/openssl/validators/ecdsa_validator.rs index 59019e613..03308e697 100644 --- a/internal/crypto/src/openssl/validators/ecdsa_validator.rs +++ b/internal/crypto/src/openssl/validators/ecdsa_validator.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::{ bn::BigNum, ec::EcKey, ecdsa::EcdsaSig, hash::MessageDigest, pkey::PKey, sign::Verifier, }; diff --git a/internal/crypto/src/openssl/validators/ed25519_validator.rs b/internal/crypto/src/openssl/validators/ed25519_validator.rs index d58f2fb9c..9c8b7b4f9 100644 --- a/internal/crypto/src/openssl/validators/ed25519_validator.rs +++ b/internal/crypto/src/openssl/validators/ed25519_validator.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::{pkey::PKey, sign::Verifier}; use crate::{ diff --git a/internal/crypto/src/openssl/validators/rsa_legacy_validator.rs b/internal/crypto/src/openssl/validators/rsa_legacy_validator.rs index 77f292fec..6c665d8d9 100644 --- a/internal/crypto/src/openssl/validators/rsa_legacy_validator.rs +++ b/internal/crypto/src/openssl/validators/rsa_legacy_validator.rs @@ -13,6 +13,8 @@ #![allow(missing_docs)] // REMOVE once this becomes `pub(crate)` +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa, sign::Verifier}; use crate::{ diff --git a/internal/crypto/src/openssl/validators/rsa_validator.rs b/internal/crypto/src/openssl/validators/rsa_validator.rs index 111474cc8..c16420e94 100644 --- a/internal/crypto/src/openssl/validators/rsa_validator.rs +++ b/internal/crypto/src/openssl/validators/rsa_validator.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::{ hash::MessageDigest, pkey::PKey, @@ -45,7 +47,55 @@ impl RawSignatureValidator for RsaValidator { public_key: &[u8], ) -> Result<(), RawSignatureValidationError> { let _openssl = OpenSslMutex::acquire()?; - let rsa = Rsa::public_key_from_der(public_key)?; + let rsa = match Rsa::public_key_from_der(public_key) { + Ok(rsa) => rsa, + #[cfg(not(feature = "boringssl"))] + Err(err) => return Err(err.into()), + #[cfg(feature = "boringssl")] + Err(err) => { + use boring::bn::BigNum; + use pkcs8::der::asn1::BitStringRef; + + // BoringSSL can't parse RSA-PSS parameters. This doesn't matter, because + // OpenSSL can't parse them either, and the C2PA SDK throws away + // "incompatible values" anyway. + + // It's safe to ignore PSS parameters in signature verification: + // - the digest algorithm can't be changed, because the same algorithm is used + // for the message digest. + // - the mask parameter is always MGF1 + // - salt len defaults to hash output len, and the salt is never used directly, + // only hashed. + // + // They're checked in this implementation anyway. + + let pk = pkcs8::SubjectPublicKeyInfo::, BitStringRef<'_>>::try_from(public_key) + .ok() + .filter(|spki| { + // OID for RSASSA-PSS ASN.1 + spki.algorithm.oid + == pkcs8::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10") + }) + .and_then(|spki| { + let pss = spki.algorithm.parameters?; + let required_salt_len = match self { + Self::Ps256 => 32, + Self::Ps384 => 48, + Self::Ps512 => 64, + }; + // OID for MGF1 ASN.1 + if pss.salt_len != required_salt_len || pss.mask_gen.oid != pkcs8::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8") { + return None; + } + pkcs1::RsaPublicKey::try_from(spki.subject_public_key.raw_bytes()).ok() + }) + .ok_or(err)?; + + let n = BigNum::from_slice(pk.modulus.as_bytes())?; + let e = BigNum::from_slice(pk.public_exponent.as_bytes())?; + Rsa::from_public_components(n, e)? + } + }; // Rebuild RSA keys to eliminate incompatible values. let n = rsa.n().to_owned()?; diff --git a/internal/crypto/src/raw_signature/validator.rs b/internal/crypto/src/raw_signature/validator.rs index 089f2de57..0436f4357 100644 --- a/internal/crypto/src/raw_signature/validator.rs +++ b/internal/crypto/src/raw_signature/validator.rs @@ -12,6 +12,8 @@ // each license. use bcder::Oid; +#[cfg(feature = "boringssl")] +use boring as openssl; use thiserror::Error; use super::oids::*; @@ -40,7 +42,7 @@ pub trait RawSignatureValidator { /// 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(feature = "openssl")] + #[cfg(feature = "_anyssl")] if let Some(validator) = crate::openssl::validators::validator_for_signing_alg(alg) { return Some(validator); } @@ -50,6 +52,7 @@ pub fn validator_for_signing_alg(alg: SigningAlg) -> Option for RawSignatureValidationError { fn from(err: openssl::error::ErrorStack) -> Self { Self::OpenSslError(err.to_string()) diff --git a/internal/crypto/src/tests/mod.rs b/internal/crypto/src/tests/mod.rs index 1fc61d740..f0cdae592 100644 --- a/internal/crypto/src/tests/mod.rs +++ b/internal/crypto/src/tests/mod.rs @@ -26,7 +26,7 @@ mod hash; mod internal; mod ocsp; -#[cfg(all(feature = "openssl", not(target_arch = "wasm32")))] +#[cfg(all(feature = "_anyssl", not(target_arch = "wasm32")))] mod openssl; mod raw_signature; diff --git a/internal/crypto/src/tests/openssl/validators/ecdsa_validator.rs b/internal/crypto/src/tests/openssl/validators/ecdsa_validator.rs index cb6327620..9b732af07 100644 --- a/internal/crypto/src/tests/openssl/validators/ecdsa_validator.rs +++ b/internal/crypto/src/tests/openssl/validators/ecdsa_validator.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::x509::X509; use crate::{ diff --git a/internal/crypto/src/tests/openssl/validators/ed25519_validator.rs b/internal/crypto/src/tests/openssl/validators/ed25519_validator.rs index 184afe9ca..105338898 100644 --- a/internal/crypto/src/tests/openssl/validators/ed25519_validator.rs +++ b/internal/crypto/src/tests/openssl/validators/ed25519_validator.rs @@ -11,6 +11,9 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; + use crate::{ openssl::validators::Ed25519Validator, raw_signature::{RawSignatureValidationError, RawSignatureValidator}, diff --git a/internal/crypto/src/tests/openssl/validators/rsa_legacy_validator.rs b/internal/crypto/src/tests/openssl/validators/rsa_legacy_validator.rs index 2b692d168..5bba1f807 100644 --- a/internal/crypto/src/tests/openssl/validators/rsa_legacy_validator.rs +++ b/internal/crypto/src/tests/openssl/validators/rsa_legacy_validator.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::x509::X509; use crate::{ diff --git a/internal/crypto/src/tests/openssl/validators/rsa_validator.rs b/internal/crypto/src/tests/openssl/validators/rsa_validator.rs index b7effddf2..68c026755 100644 --- a/internal/crypto/src/tests/openssl/validators/rsa_validator.rs +++ b/internal/crypto/src/tests/openssl/validators/rsa_validator.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::x509::X509; use crate::{ diff --git a/internal/crypto/src/tests/raw_signature/mod.rs b/internal/crypto/src/tests/raw_signature/mod.rs index e9a37e9de..d13b88946 100644 --- a/internal/crypto/src/tests/raw_signature/mod.rs +++ b/internal/crypto/src/tests/raw_signature/mod.rs @@ -11,4 +11,5 @@ // specific language governing permissions and limitations under // each license. +#[cfg(any(target_arch = "wasm32", feature = "_anyssl"))] mod validator; diff --git a/make_test_images/Cargo.toml b/make_test_images/Cargo.toml index d1e9599ce..134a6716e 100644 --- a/make_test_images/Cargo.toml +++ b/make_test_images/Cargo.toml @@ -6,14 +6,13 @@ license = "MIT OR Apache-2.0" edition = "2021" rust-version = "1.76.0" +[[bin]] +name = "make_test_images" +required-features = ["default"] + [dependencies] anyhow = "1.0.40" -c2pa = { path = "../sdk", default-features = false, features = [ - "file_io", - "openssl_sign", - "unstable_api", - "file_io", -] } +c2pa = { path = "../sdk", default-features = false, features = ["unstable_api"] } env_logger = "0.11" log = "0.4.8" image = { version = "0.25.2", default-features = false, features = [ @@ -26,3 +25,7 @@ regex = "1.5.6" serde = "1.0.197" serde_json = { version = "1.0.117", features = ["preserve_order"] } tempfile = "3.10.1" + +[features] +# prevents these features from being always enabled in the workspace +default = ["c2pa/openssl_sign", "c2pa/file_io"] diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index ebbc25c2c..4762768cd 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -29,12 +29,14 @@ rustdoc-args = ["--cfg", "docsrs"] default = ["v1_api"] add_thumbnails = ["image"] psxxx_ocsp_stapling_experimental = [] -file_io = ["openssl_sign"] +file_io = ["boringssl_sign"] serialize_thumbnails = [] no_interleaved_io = ["file_io"] fetch_remote_manifests = [] -openssl = ["dep:openssl", "c2pa-crypto/openssl"] -openssl_sign = ["openssl", "c2pa-crypto/openssl"] +openssl = ["dep:openssl", "c2pa-crypto/openssl", "_anyssl"] +openssl_sign = ["openssl", "c2pa-crypto/openssl", "_anyssl_sign"] +boringssl = ["dep:boring", "dep:pkcs8", "dep:pkcs1", "c2pa-crypto/boringssl", "_anyssl"] +boringssl_sign = ["boringssl", "c2pa-crypto/boringssl", "_anyssl_sign"] json_schema = ["dep:schemars", "c2pa-crypto/json_schema"] pdf = ["dep:lopdf"] v1_api = [] @@ -44,6 +46,11 @@ unstable_api = [] # It enables some low-overhead timing features used in our development cycle. diagnostics = [] +# Internal-only. Use the `openssl` feature to enable it. +_anyssl = [] +# Internal-only. Use the `openssl_sign` feature to enable it. +_anyssl_sign = [] + [[example]] name = "client" required-features = ["file_io"] @@ -137,6 +144,9 @@ image = { version = "0.24.7", default-features = false, features = [ "png", ], optional = true } instant = "0.1.12" +boring = { version = "4.13", optional = true } +pkcs8 = { version = "0.10.2", features = ["std"], optional = true } +pkcs1 = { version = "0.7.5", features = ["pem", "std"], optional = true } openssl = { version = "0.10.61", features = ["vendored"], optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -163,7 +173,7 @@ web-sys = { version = "0.3.58", features = [ [dev-dependencies] anyhow = "1.0.40" mockall = "0.11.2" -c2pa = { path = ".", features = [ +c2pa = { path = ".", default-features = false, features = [ "unstable_api", ] } # allow integration tests to use the new API glob = "0.3.1" diff --git a/sdk/examples/client/main.rs b/sdk/examples/client/main.rs index e2ebfaadc..93cb862b2 100644 --- a/sdk/examples/client/main.rs +++ b/sdk/examples/client/main.rs @@ -15,10 +15,10 @@ use anyhow::Result; // This example is not designed to work with a wasm build // so we provide this shell to avoid testing errors -#[cfg(not(target_arch = "wasm32"))] +#[cfg(feature = "_anyssl")] mod client; fn main() -> Result<()> { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(feature = "_anyssl")] client::main()?; Ok(()) } diff --git a/sdk/examples/data_hash.rs b/sdk/examples/data_hash.rs index 98dbd4c90..a4bfb9a9c 100644 --- a/sdk/examples/data_hash.rs +++ b/sdk/examples/data_hash.rs @@ -20,13 +20,16 @@ use std::{ path::{Path, PathBuf}, }; +#[cfg(feature = "_anyssl_sign")] +use c2pa::create_signer; + #[cfg(not(target_arch = "wasm32"))] use c2pa::{ assertions::{ c2pa_action, labels::*, Action, Actions, CreativeWork, DataHash, Exif, SchemaDotOrgPerson, }, - create_signer, hash_stream_by_alg, Builder, ClaimGeneratorInfo, HashRange, Ingredient, Reader, - Relationship, Result, + hash_stream_by_alg, Builder, ClaimGeneratorInfo, HashRange, Ingredient, Reader, Relationship, + Result, }; #[cfg(not(target_arch = "wasm32"))] use c2pa_crypto::SigningAlg; @@ -34,16 +37,16 @@ use c2pa_crypto::SigningAlg; fn main() -> std::result::Result<(), Box> { println!("DataHash demo"); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] user_data_hash_with_sdk_hashing()?; println!("Done with SDK hashing1"); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] user_data_hash_with_user_hashing()?; println!("Done with SDK hashing2"); Ok(()) } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(feature = "file_io")] fn builder_from_source>(source: S) -> Result { let mut parent = Ingredient::from_file(source.as_ref())?; parent.set_relationship(Relationship::ParentOf); @@ -86,7 +89,7 @@ fn builder_from_source>(source: S) -> Result { Ok(builder) } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] fn user_data_hash_with_sdk_hashing() -> Result<()> { // You will often implement your own Signer trait to perform on device signing let signcert_path = "sdk/tests/fixtures/certs/es256.pub"; @@ -146,7 +149,7 @@ fn user_data_hash_with_sdk_hashing() -> Result<()> { Ok(()) } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] fn user_data_hash_with_user_hashing() -> Result<()> { // You will often implement your own Signer trait to perform on device signing let signcert_path = "sdk/tests/fixtures/certs/es256.pub"; diff --git a/sdk/examples/show.rs b/sdk/examples/show.rs index 876fd0b3f..3cb73704b 100644 --- a/sdk/examples/show.rs +++ b/sdk/examples/show.rs @@ -15,7 +15,7 @@ use anyhow::Result; use c2pa::Reader; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(feature = "_anyssl")] fn main() -> Result<()> { let args: Vec = std::env::args().collect(); if args.len() > 1 { diff --git a/sdk/examples/v2api.rs b/sdk/examples/v2api.rs index ac2dd503e..3964f880a 100644 --- a/sdk/examples/v2api.rs +++ b/sdk/examples/v2api.rs @@ -157,9 +157,9 @@ fn main() -> Result<()> { Ok(()) } -// #[cfg(feature = "openssl")] +// #[cfg(feature = "_anyssl")] // use openssl::{error::ErrorStack, pkey::PKey}; -// #[cfg(feature = "openssl")] +// #[cfg(feature = "_anyssl")] // fn ed_sign(data: &[u8], pkey: &[u8]) -> std::result::Result, ErrorStack> { // let pkey = PKey::private_key_from_pem(pkey)?; // let mut signer = openssl::sign::Signer::new_without_digest(&pkey)?; @@ -175,6 +175,7 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] async fn test_v2_api() -> Result<()> { main() } diff --git a/sdk/examples/v2show.rs b/sdk/examples/v2show.rs index 62c2fb909..06620fda9 100644 --- a/sdk/examples/v2show.rs +++ b/sdk/examples/v2show.rs @@ -14,12 +14,12 @@ //! Example App that generates a manifest store listing for a given file use anyhow::Result; -#[cfg(target_arch = "wasm32")] +#[cfg(any(not(feature = "openssl"), target_arch = "wasm32"))] fn main() -> Result<()> { Ok(()) } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "openssl", not(target_arch = "wasm32")))] fn main() -> Result<()> { use std::io::Read; diff --git a/sdk/src/assertions/bmff_hash.rs b/sdk/src/assertions/bmff_hash.rs index 2fe26d80f..3c2b94864 100644 --- a/sdk/src/assertions/bmff_hash.rs +++ b/sdk/src/assertions/bmff_hash.rs @@ -1258,7 +1258,7 @@ pub mod tests { //use super::*; use crate::utils::test::fixture_path; - #[cfg(not(target_arch = "wasm32"))] + #[cfg(feature = "_anyssl")] #[test] fn test_fragemented_mp4() { use crate::{ diff --git a/sdk/src/asset_handlers/bmff_io.rs b/sdk/src/asset_handlers/bmff_io.rs index a1879732c..ddda4f82f 100644 --- a/sdk/src/asset_handlers/bmff_io.rs +++ b/sdk/src/asset_handlers/bmff_io.rs @@ -1853,8 +1853,7 @@ pub mod tests { use super::*; use crate::utils::test::{fixture_path, temp_dir_path}; - #[cfg(not(target_arch = "wasm32"))] - #[cfg(feature = "file_io")] + #[cfg(all(feature = "_anyssl", feature = "file_io"))] #[test] fn test_read_mp4() { use c2pa_status_tracker::DetailedStatusTracker; diff --git a/sdk/src/builder.rs b/sdk/src/builder.rs index beff52879..6cfe2ae53 100644 --- a/sdk/src/builder.rs +++ b/sdk/src/builder.rs @@ -1261,6 +1261,7 @@ mod tests { } #[test] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl_sign")), ignore)] fn test_builder_sign() { #[derive(Serialize, Deserialize)] struct TestAssertion { @@ -1421,6 +1422,13 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + not(any( + target_arch = "wasm32", + all(feature = "file_io", feature = "_anyssl_sign") + )), + ignore + )] async fn test_builder_remote_sign() { let format = "image/jpeg"; let mut source = Cursor::new(TEST_IMAGE); @@ -1458,7 +1466,7 @@ mod tests { } #[test] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(feature = "_anyssl_sign")] fn test_builder_remote_url() { let mut source = Cursor::new(TEST_IMAGE_CLEAN); let mut dest = Cursor::new(Vec::new()); @@ -1492,6 +1500,7 @@ mod tests { } #[test] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl_sign")), ignore)] fn test_builder_data_hashed_embeddable() { const CLOUD_IMAGE: &[u8] = include_bytes!("../tests/fixtures/cloud.jpg"); let mut input_stream = Cursor::new(CLOUD_IMAGE); @@ -1552,6 +1561,10 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg(any( + target_arch = "wasm32", + all(feature = "_anyssl_sign", feature = "file_io") + ))] async fn test_builder_box_hashed_embeddable() { use crate::asset_io::{CAIWriter, HashBlockObjectType}; const BOX_HASH_IMAGE: &[u8] = include_bytes!("../tests/fixtures/boxhash.jpg"); @@ -1655,7 +1668,7 @@ mod tests { ); } - #[cfg(feature = "file_io")] + #[cfg(feature = "_anyssl_sign")] const MANIFEST_JSON: &str = r#"{ "claim_generator": "test", "claim_generator_info": [ @@ -1786,7 +1799,7 @@ mod tests { }"#; #[test] - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] /// tests and illustrates how to add assets to a non-file based manifest by using a stream fn from_json_with_stream_full_resources() { use crate::assertions::Relationship; diff --git a/sdk/src/claim.rs b/sdk/src/claim.rs index bb5e0f0eb..f866964eb 100644 --- a/sdk/src/claim.rs +++ b/sdk/src/claim.rs @@ -1980,7 +1980,7 @@ impl Claim { } } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(feature = "_anyssl")] #[cfg(test)] pub mod tests { #![allow(clippy::expect_used)] diff --git a/sdk/src/cose_sign.rs b/sdk/src/cose_sign.rs index c48692a73..bdb01356f 100644 --- a/sdk/src/cose_sign.rs +++ b/sdk/src/cose_sign.rs @@ -362,6 +362,7 @@ mod tests { use crate::{claim::Claim, utils::test::temp_signer}; #[test] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl_sign")), ignore)] fn test_sign_claim() { let mut claim = Claim::new("extern_sign_test", Some("contentauth")); claim.build().unwrap(); @@ -376,8 +377,7 @@ mod tests { assert_eq!(cose_sign1.len(), box_size); } - #[cfg(not(target_arch = "wasm32"))] - #[cfg(feature = "openssl")] + #[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] #[actix::test] async fn test_sign_claim_async() { use crate::{ @@ -445,7 +445,7 @@ mod tests { let _cose_sign1 = sign_claim(&claim_bytes, &signer, box_size); - #[cfg(feature = "openssl")] // there is no verify on sign when openssl is disabled + #[cfg(feature = "_anyssl")] // there is no verify on sign when openssl is disabled assert!(_cose_sign1.is_err()); } } diff --git a/sdk/src/cose_validator.rs b/sdk/src/cose_validator.rs index 6edfe20f2..51eb51594 100644 --- a/sdk/src/cose_validator.rs +++ b/sdk/src/cose_validator.rs @@ -35,7 +35,7 @@ use x509_parser::{ prelude::*, }; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] use crate::openssl::verify_trust; #[cfg(target_arch = "wasm32")] use crate::wasm::webpki_trust_handler::verify_trust_async; @@ -847,14 +847,14 @@ fn check_trust( // is the certificate trusted let verify_result: Result = if _sync { - #[cfg(not(feature = "openssl"))] + #[cfg(not(feature = "_anyssl"))] { Err(Error::NotImplemented( "no trust handler for this feature".to_string(), )) } - #[cfg(feature = "openssl")] + #[cfg(feature = "_anyssl")] { verify_trust(th, chain_der, cert_der, signing_time_epoc) } @@ -864,12 +864,12 @@ fn check_trust( verify_trust_async(th, chain_der, cert_der, signing_time_epoc).await } - #[cfg(feature = "openssl")] + #[cfg(feature = "_anyssl")] { verify_trust(th, chain_der, cert_der, signing_time_epoc) } - #[cfg(all(not(feature = "openssl"), not(target_arch = "wasm32")))] + #[cfg(not(any(feature = "_anyssl", target_arch = "wasm32")))] { Err(Error::NotImplemented( "no trust handler for this feature".to_string(), @@ -1346,7 +1346,7 @@ async fn validate_with_cert_async( #[allow(unused_imports)] #[allow(clippy::unwrap_used)] -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] #[cfg(test)] pub mod tests { use c2pa_status_tracker::DetailedStatusTracker; @@ -1380,7 +1380,7 @@ pub mod tests { } #[test] - #[cfg(feature = "openssl_sign")] + #[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] fn test_cert_algorithms() { let cert_dir = crate::utils::test::fixture_path("certs"); let th = crate::openssl::OpenSSLTrustHandlerConfig::new(); @@ -1443,7 +1443,7 @@ pub mod tests { assert_eq!(signing_time, None); } #[test] - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] fn test_stapled_ocsp() { let mut validation_log = DetailedStatusTracker::default(); diff --git a/sdk/src/error.rs b/sdk/src/error.rs index d2fa23bee..109cfc1e8 100644 --- a/sdk/src/error.rs +++ b/sdk/src/error.rs @@ -13,6 +13,8 @@ // #![deny(missing_docs)] (we'll turn this on once fully documented) +#[cfg(feature = "boringssl")] +use boring as openssl; use thiserror::Error; /// `Error` enumerates errors returned by most C2PA toolkit operations. @@ -281,11 +283,11 @@ pub enum Error { #[error(transparent)] CborError(#[from] serde_cbor::Error), - #[cfg(feature = "openssl")] + #[cfg(feature = "_anyssl")] #[error("could not acquire OpenSSL FFI mutex")] OpenSslMutexError, - #[cfg(feature = "openssl")] + #[cfg(feature = "_anyssl")] #[error(transparent)] OpenSslError(#[from] openssl::error::ErrorStack), @@ -308,7 +310,7 @@ pub enum Error { /// A specialized `Result` type for C2PA toolkit operations. pub type Result = std::result::Result; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] impl From for Error { fn from(_err: c2pa_crypto::openssl::OpenSslMutexUnavailable) -> Self { Self::OpenSslMutexError diff --git a/sdk/src/ingredient.rs b/sdk/src/ingredient.rs index 4702e7f26..2621446db 100644 --- a/sdk/src/ingredient.rs +++ b/sdk/src/ingredient.rs @@ -1517,6 +1517,7 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] async fn test_stream_async_jpg() { let image_bytes = include_bytes!("../tests/fixtures/CA.jpg"); let title = "Test Image"; @@ -1536,12 +1537,12 @@ mod tests { &"ingredient_from_memory_async:".into(), &ingredient.to_string().into(), ); - assert!(ingredient.validation_status().is_none()); + assert_eq!(None, ingredient.validation_status()); } - #[cfg_attr(not(target_arch = "wasm32"), test)] + #[test] + #[cfg_attr(any(target_arch = "wasm32", not(feature = "_anyssl")), ignore)] // Note this does not work from wasm32, due to validation issues - #[cfg(not(target_arch = "wasm32"))] fn test_stream_jpg() { let image_bytes = include_bytes!("../tests/fixtures/CA.jpg"); let title = "Test Image"; @@ -1554,11 +1555,12 @@ mod tests { assert_eq!(ingredient.format(), format); assert!(ingredient.manifest_data().is_some()); assert!(ingredient.metadata().is_none()); - assert!(ingredient.validation_status().is_none()); + assert_eq!(None, ingredient.validation_status()); } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] async fn test_stream_ogp() { let image_bytes = include_bytes!("../tests/fixtures/XCA.jpg"); let title = "XCA.jpg"; @@ -1583,8 +1585,11 @@ mod tests { } #[allow(dead_code)] - #[cfg_attr(not(any(target_arch = "wasm32", feature = "file_io")), actix::test)] - #[cfg(not(target_arch = "wasm32"))] + #[cfg_attr(not(target_arch = "wasm32"), actix::test)] + #[cfg_attr( + not(all(feature = "_anyssl", feature = "fetch_remote_manifests")), + ignore + )] async fn test_jpg_cloud_from_memory() { let image_bytes = include_bytes!("../tests/fixtures/cloud.jpg"); let format = "image/jpeg"; @@ -1597,7 +1602,7 @@ mod tests { assert!(ingredient.provenance().is_some()); assert!(ingredient.provenance().unwrap().starts_with("https:")); assert!(ingredient.manifest_data().is_some()); - assert!(ingredient.validation_status().is_none()); + assert_eq!(None, ingredient.validation_status()); } #[allow(dead_code)] @@ -1624,6 +1629,7 @@ mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] async fn test_jpg_cloud_from_memory_and_manifest() { let asset_bytes = include_bytes!("../tests/fixtures/cloud.jpg"); let manifest_bytes = include_bytes!("../tests/fixtures/cloud_manifest.c2pa"); @@ -1640,7 +1646,7 @@ mod tests { &"ingredient_from_memory_async:".into(), &ingredient.to_string().into(), ); - assert!(ingredient.validation_status().is_none()); + assert_eq!(None, ingredient.validation_status()); assert!(ingredient.manifest_data().is_some()); assert!(ingredient.provenance().is_some()); } @@ -1838,7 +1844,7 @@ mod tests_file_io { let ap = fixture_path("CIE-sig-CA.jpg"); let ingredient = Ingredient::from_file(ap).expect("from_file"); // println!("ingredient = {ingredient}"); - assert!(ingredient.validation_status().is_none()); + assert_eq!(None, ingredient.validation_status()); assert!(ingredient.manifest_data().is_some()); } diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 08bd59d0e..019bb4ae8 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -104,7 +104,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); // Public modules pub mod assertions; pub mod cose_sign; -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] pub mod create_signer; pub mod jumbf_io; pub mod settings; @@ -163,7 +163,7 @@ pub(crate) mod manifest; pub(crate) mod manifest_assertion; pub(crate) mod manifest_store; pub(crate) mod manifest_store_report; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] pub(crate) mod openssl; #[allow(dead_code)] // TODO: Remove this when the feature is released (used in tests only for some builds now) diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs index 774798e6f..bea446e44 100644 --- a/sdk/src/manifest.rs +++ b/sdk/src/manifest.rs @@ -1888,7 +1888,7 @@ pub(crate) mod tests { assert_eq!(action2.unwrap().actions()[0].action(), c2pa_action::EDITED); } - #[cfg(all(feature = "file_io", feature = "openssl_sign"))] + #[cfg(all(feature = "file_io", feature = "_anyssl_sign"))] #[actix::test] #[allow(deprecated)] async fn test_embed_async_sign() { @@ -1910,7 +1910,7 @@ pub(crate) mod tests { ); } - #[cfg(all(feature = "file_io", feature = "openssl_sign"))] + #[cfg(all(feature = "file_io", feature = "_anyssl_sign"))] #[actix::test] #[allow(deprecated)] async fn test_embed_remote_sign() { @@ -1983,6 +1983,13 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[allow(deprecated)] + #[cfg_attr( + not(any( + target_arch = "wasm32", + all(feature = "file_io", feature = "_anyssl_sign") + )), + ignore + )] async fn test_embed_jpeg_stream_wasm() { use crate::assertions::User; let image = include_bytes!("../tests/fixtures/earth_apollo17.jpg"); @@ -2023,6 +2030,13 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[allow(deprecated)] + #[cfg_attr( + not(any( + target_arch = "wasm32", + all(feature = "file_io", feature = "_anyssl_sign") + )), + ignore + )] async fn test_embed_png_stream_wasm() { use crate::assertions::User; let image = include_bytes!("../tests/fixtures/libpng-test.png"); @@ -2056,6 +2070,13 @@ pub(crate) mod tests { #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[allow(deprecated)] + #[cfg_attr( + not(any( + target_arch = "wasm32", + all(feature = "file_io", feature = "_anyssl_sign") + )), + ignore + )] async fn test_embed_webp_stream_wasm() { use crate::assertions::User; let image = include_bytes!("../tests/fixtures/mars.webp"); @@ -2087,6 +2108,7 @@ pub(crate) mod tests { } #[test] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl_sign")), ignore)] fn test_embed_stream() { use crate::assertions::User; let image = include_bytes!("../tests/fixtures/earth_apollo17.jpg"); @@ -2122,9 +2144,12 @@ pub(crate) mod tests { //println!("{manifest_store}");main } - #[cfg(any(target_arch = "wasm32", feature = "openssl_sign"))] - #[cfg_attr(feature = "openssl_sign", actix::test)] + #[cfg_attr(feature = "_anyssl_sign", actix::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg(any( + target_arch = "wasm32", + all(feature = "_anyssl_sign", feature = "file_io") + ))] async fn test_embed_from_memory_async() { use crate::{assertions::User, utils::test::temp_async_signer}; let image = include_bytes!("../tests/fixtures/earth_apollo17.jpg"); @@ -2252,7 +2277,7 @@ pub(crate) mod tests { assert_eq!(image.into_owned(), thumb_data); } - #[cfg(feature = "file_io")] + #[cfg(feature = "_anyssl_sign")] const MANIFEST_JSON: &str = r#"{ "claim_generator": "test", "claim_generator_info": [ @@ -2369,7 +2394,7 @@ pub(crate) mod tests { }"#; #[test] - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] /// tests and illustrates how to add assets to a non-file based manifest by using a stream fn from_json_with_stream() { use crate::assertions::Relationship; @@ -2437,7 +2462,7 @@ pub(crate) mod tests { } #[test] - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] #[allow(deprecated)] /// tests and illustrates how to add assets to a non-file based manifest by using a memory buffer fn from_json_with_memory() { @@ -2718,7 +2743,7 @@ pub(crate) mod tests { assert!(manifest_store.validation_status().is_none()); } - #[cfg(all(feature = "file_io", feature = "openssl_sign"))] + #[cfg(all(feature = "file_io", feature = "_anyssl_sign"))] #[actix::test] #[allow(deprecated)] async fn test_data_hash_embeddable_manifest_remote_signed() { diff --git a/sdk/src/manifest_store.rs b/sdk/src/manifest_store.rs index 5ac0d989f..f40b56094 100644 --- a/sdk/src/manifest_store.rs +++ b/sdk/src/manifest_store.rs @@ -580,7 +580,7 @@ impl std::fmt::Display for ManifestStore { } } -#[cfg(test)] +#[cfg(all(test, any(target_arch = "wasm32", feature = "_anyssl")))] mod tests { #![allow(clippy::expect_used)] #![allow(clippy::unwrap_used)] diff --git a/sdk/src/openssl/ec_signer.rs b/sdk/src/openssl/ec_signer.rs index 136cf328e..8244076e9 100644 --- a/sdk/src/openssl/ec_signer.rs +++ b/sdk/src/openssl/ec_signer.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use c2pa_crypto::{openssl::OpenSslMutex, SigningAlg}; use openssl::{ ec::EcKey, diff --git a/sdk/src/openssl/ed_signer.rs b/sdk/src/openssl/ed_signer.rs index 21202eebf..e8e836216 100644 --- a/sdk/src/openssl/ed_signer.rs +++ b/sdk/src/openssl/ed_signer.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use c2pa_crypto::{openssl::OpenSslMutex, SigningAlg}; use openssl::{ pkey::{PKey, Private}, diff --git a/sdk/src/openssl/mod.rs b/sdk/src/openssl/mod.rs index 13dbaeb83..008fde15a 100644 --- a/sdk/src/openssl/mod.rs +++ b/sdk/src/openssl/mod.rs @@ -11,42 +11,44 @@ // specific language governing permissions and limitations under // each license. -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] mod rsa_signer; -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] pub(crate) use rsa_signer::RsaSigner; -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] mod ec_signer; -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] pub(crate) use ec_signer::EcSigner; -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] mod ed_signer; -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] pub(crate) use ed_signer::EdSigner; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] mod openssl_trust_handler; #[cfg(test)] pub(crate) mod temp_signer; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] pub(crate) use openssl_trust_handler::verify_trust; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] pub(crate) use openssl_trust_handler::OpenSSLTrustHandlerConfig; #[cfg(test)] pub(crate) mod temp_signer_async; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] +#[cfg(feature = "boringssl")] +use boring as openssl; use openssl::x509::X509; #[cfg(test)] #[allow(unused_imports)] -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl_sign")] pub(crate) use temp_signer_async::AsyncSignerAdapter; -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] fn check_chain_order(certs: &[X509]) -> bool { // IMPORTANT: ffi_mutex::acquire() should have been called by calling fn. Please // don't make this pub or pub(crate) without finding a way to ensure that @@ -65,6 +67,11 @@ fn check_chain_order(certs: &[X509]) -> bool { return false; } } else { + if cfg!(all(test, feature = "boringssl")) { + // public_key() will fail on RSA-PSS in Boring. + // It's OK to skip this function, it's only a config sanity check. + continue; + } return false; } } @@ -74,12 +81,12 @@ fn check_chain_order(certs: &[X509]) -> bool { } } -#[cfg(not(feature = "openssl"))] +#[cfg(not(feature = "_anyssl"))] fn check_chain_order(certs: &[X509]) -> bool { true } -#[cfg(feature = "openssl")] +#[cfg(feature = "_anyssl")] #[allow(dead_code)] fn check_chain_order_der(cert_ders: &[Vec]) -> bool { // IMPORTANT: ffi_mutex::acquire() should have been called by calling fn. Please @@ -98,7 +105,7 @@ fn check_chain_order_der(cert_ders: &[Vec]) -> bool { check_chain_order(&certs) } -#[cfg(not(feature = "openssl"))] +#[cfg(not(feature = "_anyssl"))] fn check_chain_order_der(cert_ders: &[Vec]) -> bool { true } diff --git a/sdk/src/openssl/openssl_trust_handler.rs b/sdk/src/openssl/openssl_trust_handler.rs index d41c5ab14..6f41c50f8 100644 --- a/sdk/src/openssl/openssl_trust_handler.rs +++ b/sdk/src/openssl/openssl_trust_handler.rs @@ -11,6 +11,8 @@ // specific language governing permissions and limitations under // each license. +#[cfg(feature = "boringssl")] +use boring as openssl; use std::{ collections::HashSet, io::{BufRead, BufReader, Cursor, Read}, @@ -267,6 +269,7 @@ pub(crate) fn verify_trust( if let Some(st) = signing_time_epoc { verify_param.set_time(st); } else { + #[cfg(feature = "openssl")] verify_param .set_flags(X509VerifyFlags::NO_CHECK_TIME) .map_err(Error::OpenSslError)?; @@ -295,6 +298,7 @@ pub(crate) fn verify_trust( } #[cfg(test)] +#[cfg(feature = "file_io")] pub mod tests { #![allow(clippy::expect_used)] #![allow(clippy::panic)] diff --git a/sdk/src/openssl/rsa_signer.rs b/sdk/src/openssl/rsa_signer.rs index 2ffe14933..3b8f2bd76 100644 --- a/sdk/src/openssl/rsa_signer.rs +++ b/sdk/src/openssl/rsa_signer.rs @@ -13,6 +13,8 @@ use std::cell::Cell; +#[cfg(feature = "boringssl")] +use boring as openssl; use c2pa_crypto::{ocsp::OcspResponse, openssl::OpenSslMutex, SigningAlg}; use openssl::{ hash::MessageDigest, @@ -100,7 +102,51 @@ impl ConfigurableSigner for RsaSigner { let _openssl = OpenSslMutex::acquire()?; let signcerts = X509::stack_from_pem(signcert).map_err(wrap_openssl_err)?; - let rsa = Rsa::private_key_from_pem(pkey).map_err(wrap_openssl_err)?; + + let rsa: Rsa<_> = match Rsa::private_key_from_pem(pkey).map_err(wrap_openssl_err) { + Ok(rsa) => rsa, + #[cfg(all(test, feature = "boringssl"))] + Err(err @ Error::OpenSslError(_)) => { + use boring::bn::BigNum; + use pkcs8::der::Decode; + + // BoringSSL can't parse RSA-PSS parameters. This doesn't matter, because + // OpenSSL can't parse them either, and the C2PA SDK throws away + // "incompatible values" anyway. + + // This signer is used only in tests. + + let der = pem::parse(pkey) + .ok() + .filter(|der| der.tag() == "PRIVATE KEY"); + + let pk = der + .as_ref() + .and_then(|der| pkcs8::PrivateKeyInfo::from_der(der.contents()).ok()) + .filter(|pk| { + // RSASSA-PSS ASN.1 + pk.algorithm.oid + == pkcs8::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10") + }) + .and_then(|pk| pkcs1::RsaPrivateKey::try_from(pk.private_key).ok()) + .ok_or(err)?; + + let n = BigNum::from_slice(pk.modulus.as_bytes())?; + let e = BigNum::from_slice(pk.public_exponent.as_bytes())?; + let d = BigNum::from_slice(pk.private_exponent.as_bytes())?; + let p = BigNum::from_slice(pk.prime1.as_bytes())?; + let q = BigNum::from_slice(pk.prime2.as_bytes())?; + let dmp1 = BigNum::from_slice(pk.exponent1.as_bytes())?; + let dmq1 = BigNum::from_slice(pk.exponent2.as_bytes())?; + let iqmp = BigNum::from_slice(pk.coefficient.as_bytes())?; + + RsaPrivateKeyBuilder::new(n, e, d)? + .set_factors(p, q)? + .set_crt_params(dmp1, dmq1, iqmp)? + .build() + } + Err(err) => return Err(err), + }; // make sure cert chains are in order if !check_chain_order(&signcerts) { diff --git a/sdk/src/openssl/temp_signer_async.rs b/sdk/src/openssl/temp_signer_async.rs index 4dc81fa2a..35dacec31 100644 --- a/sdk/src/openssl/temp_signer_async.rs +++ b/sdk/src/openssl/temp_signer_async.rs @@ -19,10 +19,10 @@ //! the asynchronous signing of claims. //! This module should be used only for testing purposes. -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] use c2pa_crypto::SigningAlg; -#[cfg(feature = "openssl_sign")] +#[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] fn get_local_signer(alg: SigningAlg) -> Box { let cert_dir = crate::utils::test::fixture_path("certs"); @@ -42,7 +42,7 @@ fn get_local_signer(alg: SigningAlg) -> Box { } } -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] pub struct AsyncSignerAdapter { alg: SigningAlg, certs: Vec>, @@ -51,7 +51,7 @@ pub struct AsyncSignerAdapter { ocsp_val: Option>, } -#[cfg(feature = "openssl_sign")] +#[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] impl AsyncSignerAdapter { pub fn new(alg: SigningAlg) -> Self { let signer = get_local_signer(alg); @@ -67,7 +67,7 @@ impl AsyncSignerAdapter { } #[cfg(test)] -#[cfg(feature = "openssl_sign")] +#[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] #[async_trait::async_trait] impl crate::AsyncSigner for AsyncSignerAdapter { async fn sign(&self, data: Vec) -> crate::error::Result> { diff --git a/sdk/src/resource_store.rs b/sdk/src/resource_store.rs index 6d6eff8f4..a0766de8f 100644 --- a/sdk/src/resource_store.rs +++ b/sdk/src/resource_store.rs @@ -397,7 +397,7 @@ pub fn mime_from_uri(uri: &str) -> String { } #[cfg(test)] -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] mod tests { #![allow(clippy::expect_used)] #![allow(clippy::unwrap_used)] @@ -408,7 +408,7 @@ mod tests { use crate::{utils::test::temp_signer, Builder, Reader}; #[test] - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] fn resource_store() { let mut c = ResourceStore::new(); let value = b"my value"; diff --git a/sdk/src/salt.rs b/sdk/src/salt.rs index c84508d5f..a5ff8661c 100644 --- a/sdk/src/salt.rs +++ b/sdk/src/salt.rs @@ -55,20 +55,23 @@ impl Default for DefaultSalt { impl SaltGenerator for DefaultSalt { fn generate_salt(&self) -> Option> { - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] { + #[cfg(feature = "boringssl")] + use boring as openssl; + let mut salt = vec![0u8; self.salt_len]; openssl::rand::rand_bytes(&mut salt).ok()?; Some(salt) } - #[cfg(all(not(feature = "openssl_sign"), target_arch = "wasm32"))] + #[cfg(all(not(feature = "_anyssl_sign"), target_arch = "wasm32"))] { let salt = crate::wasm::util::get_random_values(self.salt_len).ok()?; Some(salt) } - #[cfg(all(not(feature = "openssl_sign"), not(target_arch = "wasm32")))] + #[cfg(all(not(feature = "_anyssl_sign"), not(target_arch = "wasm32")))] { use rand::prelude::*; diff --git a/sdk/src/signer.rs b/sdk/src/signer.rs index d96e6ecae..08b8216e8 100644 --- a/sdk/src/signer.rs +++ b/sdk/src/signer.rs @@ -56,7 +56,7 @@ pub trait Signer { /// /// The default implementation will send the request to the URL /// provided by [`Self::time_authority_url()`], if any. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(feature = "_anyssl")] fn send_timestamp_request(&self, message: &[u8]) -> Option>> { if let Some(url) = self.time_authority_url() { if let Ok(body) = self.timestamp_request_body(message) { @@ -68,7 +68,7 @@ pub trait Signer { } None } - #[cfg(target_arch = "wasm32")] + #[cfg(not(feature = "_anyssl"))] fn send_timestamp_request(&self, _message: &[u8]) -> Option>> { None } diff --git a/sdk/src/store.rs b/sdk/src/store.rs index 29084246d..1cacfd9af 100644 --- a/sdk/src/store.rs +++ b/sdk/src/store.rs @@ -128,11 +128,11 @@ impl Store { manifest_box_hash_cache: HashMap::new(), claims: Vec::new(), label: label.to_string(), - #[cfg(feature = "openssl")] + #[cfg(feature = "_anyssl")] trust_handler: Box::new(crate::openssl::OpenSSLTrustHandlerConfig::new()), - #[cfg(all(not(feature = "openssl"), target_arch = "wasm32"))] + #[cfg(target_arch = "wasm32")] trust_handler: Box::new(crate::wasm::WebTrustHandlerConfig::new()), - #[cfg(all(not(feature = "openssl"), not(target_arch = "wasm32")))] + #[cfg(not(any(feature = "_anyssl", target_arch = "wasm32")))] trust_handler: Box::new(crate::trust_handler::TrustPassThrough::new()), provenance_path: None, //dynamic_assertions: Vec::new(), @@ -5920,7 +5920,7 @@ pub mod tests { } #[actix::test] - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] async fn test_dynamic_assertions() { use async_trait::async_trait; diff --git a/sdk/src/time_stamp.rs b/sdk/src/time_stamp.rs index 9a2c47e0c..ea75befde 100644 --- a/sdk/src/time_stamp.rs +++ b/sdk/src/time_stamp.rs @@ -539,10 +539,10 @@ pub(crate) fn verify_timestamp(ts: &[u8], data: &[u8]) -> Result { .write_encoded(bcder::Mode::Der, &mut signing_key_der)?; // Verify signature of timestamp signature. - #[cfg(feature = "openssl")] + #[cfg(feature = "_anyssl")] validate_timestamp_sig(sig_alg, hash_alg, sig_val, &tbs, &signing_key_der)?; - #[cfg(not(feature = "openssl"))] + #[cfg(not(feature = "_anyssl"))] { #[cfg(target_arch = "wasm32")] { diff --git a/sdk/src/utils/test.rs b/sdk/src/utils/test.rs index 626c01c66..52734680d 100644 --- a/sdk/src/utils/test.rs +++ b/sdk/src/utils/test.rs @@ -35,7 +35,7 @@ use crate::{ store::Store, RemoteSigner, Result, Signer, }; -#[cfg(feature = "openssl_sign")] +#[cfg(feature = "_anyssl_sign")] use crate::{ openssl::{AsyncSignerAdapter, RsaSigner}, signer::ConfigurableSigner, @@ -342,7 +342,7 @@ impl crate::AsyncSigner for AsyncTestGoodSigner { /// Returns a boxed [`Signer`] instance. #[cfg(test)] pub(crate) fn temp_signer() -> Box { - #[cfg(feature = "openssl_sign")] + #[cfg(feature = "_anyssl_sign")] { #![allow(clippy::expect_used)] let sign_cert = include_bytes!("../../tests/fixtures/certs/ps256.pub").to_vec(); @@ -356,15 +356,18 @@ pub(crate) fn temp_signer() -> Box { } // todo: the will be a RustTLS signer shortly - #[cfg(not(feature = "openssl_sign"))] + #[cfg(not(feature = "_anyssl_sign"))] { Box::new(TestGoodSigner {}) } } -#[cfg(any(target_arch = "wasm32", feature = "openssl_sign"))] +#[cfg(any( + target_arch = "wasm32", + all(feature = "_anyssl_sign", feature = "file_io") +))] pub fn temp_async_signer() -> Box { - #[cfg(feature = "openssl_sign")] + #[cfg(not(target_arch = "wasm32"))] { Box::new(AsyncSignerAdapter::new(SigningAlg::Es256)) } @@ -410,7 +413,7 @@ struct TempRemoteSigner {} #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] impl crate::signer::RemoteSigner for TempRemoteSigner { async fn sign_remote(&self, claim_bytes: &[u8]) -> crate::error::Result> { - #[cfg(feature = "openssl_sign")] + #[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] { let signer = crate::openssl::temp_signer_async::AsyncSignerAdapter::new(SigningAlg::Ps256); @@ -418,7 +421,10 @@ impl crate::signer::RemoteSigner for TempRemoteSigner { // this would happen on some remote server crate::cose_sign::cose_sign_async(&signer, claim_bytes, self.reserve_size()).await } - #[cfg(all(not(feature = "openssl"), not(target_arch = "wasm32")))] + #[cfg(not(any( + target_arch = "wasm32", + all(feature = "_anyssl_sign", feature = "file_io") + )))] { use std::io::{Seek, Write}; @@ -561,7 +567,7 @@ struct TempAsyncRemoteSigner { impl crate::signer::AsyncSigner for TempAsyncRemoteSigner { // this will not be called but requires an implementation async fn sign(&self, claim_bytes: Vec) -> Result> { - #[cfg(feature = "openssl_sign")] + #[cfg(all(feature = "_anyssl_sign", feature = "file_io"))] { let signer = crate::openssl::temp_signer_async::AsyncSignerAdapter::new(SigningAlg::Ps256); @@ -575,7 +581,10 @@ impl crate::signer::AsyncSigner for TempAsyncRemoteSigner { crate::cose_sign::cose_sign_async(&signer, &claim_bytes, self.reserve_size()).await } - #[cfg(all(not(feature = "openssl"), not(target_arch = "wasm32")))] + #[cfg(not(any( + target_arch = "wasm32", + all(feature = "_anyssl_sign", feature = "file_io") + )))] { use std::io::{Seek, Write}; diff --git a/sdk/tests/test_builder.rs b/sdk/tests/test_builder.rs index c866573cd..7afe96cdd 100644 --- a/sdk/tests/test_builder.rs +++ b/sdk/tests/test_builder.rs @@ -19,6 +19,7 @@ mod common; use common::{compare_stream_to_known_good, fixtures_path, test_signer}; #[test] +#[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] fn test_builder_ca_jpg() -> Result<()> { let manifest_def = std::fs::read_to_string(fixtures_path("simple_manifest.json"))?; let mut builder = Builder::from_json(&manifest_def)?; @@ -42,6 +43,7 @@ fn test_builder_ca_jpg() -> Result<()> { // Source: https://github.com/contentauth/c2pa-rs/issues/530 #[test] +#[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] fn test_builder_riff() -> Result<()> { let manifest_def = include_str!("fixtures/simple_manifest.json"); let mut source = Cursor::new(include_bytes!("fixtures/sample1.wav")); @@ -119,6 +121,7 @@ fn test_builder_fragmented() -> Result<()> { } #[test] +#[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] fn test_builder_remote_url_no_embed() -> Result<()> { let manifest_def = std::fs::read_to_string(fixtures_path("simple_manifest.json"))?; let mut builder = Builder::from_json(&manifest_def)?; diff --git a/sdk/tests/test_reader.rs b/sdk/tests/test_reader.rs index c654b227d..998965013 100644 --- a/sdk/tests/test_reader.rs +++ b/sdk/tests/test_reader.rs @@ -32,6 +32,7 @@ fn test_reader_no_jumbf() -> Result<()> { } #[test] +#[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] fn test_reader_ca_jpg() -> Result<()> { let (format, mut stream) = fixture_stream("CA.jpg")?; let reader = Reader::from_stream(&format, &mut stream)?; @@ -39,6 +40,7 @@ fn test_reader_ca_jpg() -> Result<()> { } #[test] +#[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] fn test_reader_c_jpg() -> Result<()> { let (format, mut stream) = fixture_stream("C.jpg")?; let reader = Reader::from_stream(&format, &mut stream)?; @@ -46,6 +48,7 @@ fn test_reader_c_jpg() -> Result<()> { } #[test] +#[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] fn test_reader_xca_jpg() -> Result<()> { let (format, mut stream) = fixture_stream("XCA.jpg")?; let reader = Reader::from_stream(&format, &mut stream)?; diff --git a/sdk/tests/v2_api_integration.rs b/sdk/tests/v2_api_integration.rs index cbeebd0cc..576db55e8 100644 --- a/sdk/tests/v2_api_integration.rs +++ b/sdk/tests/v2_api_integration.rs @@ -108,6 +108,7 @@ mod integration_v2 { } #[test] + #[cfg_attr(not(any(target_arch = "wasm32", feature = "_anyssl")), ignore)] fn test_v2_integration() -> Result<()> { let title = "CA.jpg"; let format = "image/jpeg";