c2pa-rs

A fork of https://github.com/contentauth/c2pa-rs/
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/c2pa-rs.git
Log | Files | Refs | README

commit aeb4a32d2928d32bf63332346e2a7f713e839f42
parent 3aa77b991763b4bcc5d0271497f60a39c7149743
Author: Gavin  Peacock <gpeacock@adobe.com>
Date:   Mon,  6 Jun 2022 14:00:45 -0700

Export top level signing functions, hide other signature details (#32)

* New public interface for signing
Adds get_signer and get_singer_from_files
get_temp_signer and get_temp_signer_with_alg
Hides other info
* Remove AsyncPlaceholder
Diffstat:
Mmake_test_images/src/make_test_images.rs | 7+++----
Msdk/examples/client/client.rs | 5++---
Msdk/src/asset_handlers/c2pa_io.rs | 4++--
Msdk/src/lib.rs | 23++++++++++++++---------
Msdk/src/manifest.rs | 8++++----
Msdk/src/manifest_store_report.rs | 2+-
Msdk/src/openssl/mod.rs | 13+++++++------
Msdk/src/openssl/rsa_signer.rs | 4++--
Asdk/src/openssl/signer.rs | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msdk/src/openssl/temp_signer.rs | 4++--
Msdk/src/signer.rs | 48+-----------------------------------------------
Msdk/src/store.rs | 10+++++-----
Msdk/tests/integration.rs | 5++---
13 files changed, 143 insertions(+), 88 deletions(-)

diff --git a/make_test_images/src/make_test_images.rs b/make_test_images/src/make_test_images.rs @@ -15,9 +15,8 @@ //! use c2pa::{ assertions::{c2pa_action, Action, Actions, CreativeWork, SchemaDotOrgPerson}, - jumbf_io, - openssl::temp_signer::get_signer_by_alg, - Error, Ingredient, IngredientOptions, Manifest, ManifestStore, + get_temp_signer_by_alg, jumbf_io, Error, Ingredient, IngredientOptions, Manifest, + ManifestStore, }; use anyhow::{Context, Result}; @@ -262,7 +261,7 @@ impl MakeTestImages { // now create store; sign claim and embed in target let temp_dir = tempdir()?; let (signer, _) = - get_signer_by_alg(&temp_dir.path(), &self.config.alg, self.config.ta.clone()); + get_temp_signer_by_alg(&temp_dir.path(), &self.config.alg, self.config.ta.clone()); manifest.embed(&dst_path, &dst_path, signer.as_ref())?; diff --git a/sdk/examples/client/client.rs b/sdk/examples/client/client.rs @@ -17,8 +17,7 @@ use anyhow::Result; use c2pa::{ assertions::{c2pa_action, labels, Action, Actions, CreativeWork}, - openssl::temp_signer::get_signer, - Ingredient, Manifest, ManifestStore, + get_temp_signer, Ingredient, Manifest, ManifestStore, }; use std::path::PathBuf; use tempfile::tempdir; @@ -111,7 +110,7 @@ pub fn main() -> Result<()> { // sign and embed into the target file let temp_dir = tempdir()?; - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); manifest.embed(&source, &dest, &signer)?; let manifest_store = ManifestStore::from_file(&dest)?; diff --git a/sdk/src/asset_handlers/c2pa_io.rs b/sdk/src/asset_handlers/c2pa_io.rs @@ -66,7 +66,7 @@ pub mod tests { use tempfile::tempdir; use crate::{ - openssl::temp_signer::get_signer, + openssl::temp_signer::get_temp_signer, status_tracker::OneShotStatusTracker, store::Store, utils::test::{fixture_path, temp_dir_path}, @@ -88,7 +88,7 @@ pub mod tests { let store = Store::load_from_asset(&temp_path, false, &mut OneShotStatusTracker::new()) .expect("loading store"); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); let manifest2 = store.to_jumbf(&signer).expect("to_jumbf"); assert_eq!(&manifest, &manifest2); diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs @@ -44,9 +44,9 @@ //! ``` //! # use c2pa::Result; //! use c2pa::{ -//! Manifest, -//! openssl::temp_signer::get_signer, -//! assertions::User +//! assertions::User, +//! get_temp_signer, +//! Manifest //! }; //! //! use std::path::PathBuf; @@ -60,7 +60,7 @@ //! let dir = tempdir()?; //! let dest = dir.path().join("test_file.jpg"); //! -//! let (signer, _) = get_signer(&dir.path()); +//! let (signer, _) = get_temp_signer(&dir.path()); //! manifest.embed(&source, &dest, &signer)?; //! # Ok(()) //! # } @@ -89,11 +89,18 @@ pub use manifest_store_report::ManifestStoreReport; #[cfg(feature = "file_io")] pub(crate) mod ocsp_utils; #[cfg(feature = "file_io")] -pub mod openssl; +mod openssl; #[cfg(feature = "file_io")] -pub mod signer; +pub use crate::openssl::{ + signer::{get_signer, get_signer_from_files}, + temp_signer::{get_temp_signer, get_temp_signer_by_alg}, +}; +#[cfg(feature = "file_io")] +mod signer; #[cfg(feature = "async_signer")] -pub use signer::{AsyncPlaceholder, AsyncSigner}; +pub use signer::AsyncSigner; +#[cfg(feature = "file_io")] +pub use signer::Signer; /// crate private declarations #[allow(dead_code, clippy::enum_variant_names)] pub(crate) mod asn1; @@ -114,8 +121,6 @@ pub(crate) mod hashed_uri; #[allow(dead_code)] pub(crate) mod jumbf; pub(crate) mod salt; -#[cfg(feature = "file_io")] -pub(crate) use signer::Signer; pub(crate) mod status_tracker; pub(crate) mod store; pub(crate) mod time_stamp; diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs @@ -570,7 +570,7 @@ pub(crate) mod tests { use crate::{ assertions::{c2pa_action, Action, Actions}, - openssl::temp_signer::get_signer, + openssl::temp_signer::get_temp_signer, status_tracker::{DetailedStatusTracker, StatusTracker}, utils::test::{fixture_path, temp_dir_path, temp_fixture_path, TEST_SMALL_JPEG, TEST_VC}, }; @@ -642,7 +642,7 @@ pub(crate) mod tests { let test_output = dir.path().join("wc_embed_test.jpg"); //embed a claim generated from this manifest - let (signer, _) = get_signer(&dir.path()); + let (signer, _) = get_temp_signer(&dir.path()); let _store = manifest .embed(&source_path, &test_output, &signer) @@ -747,7 +747,7 @@ pub(crate) mod tests { ) .expect("add_assertion"); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); let store1 = manifest.embed(&output, &output, &signer).expect("embed"); let claim1_label = store1.provenance_label().unwrap(); @@ -772,7 +772,7 @@ pub(crate) mod tests { let temp_dir = tempdir().expect("temp dir"); //embed a claim in output2 - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); let _store2 = manifest2.embed(&output2, &output2, &signer).expect("embed"); diff --git a/sdk/src/manifest_store_report.rs b/sdk/src/manifest_store_report.rs @@ -52,7 +52,7 @@ impl ManifestStoreReport { } /// Creates a ManifestStoreReport from an existing Store and a validation log - pub fn from_store_with_log( + pub(crate) fn from_store_with_log( store: &Store, validation_log: &mut impl StatusTracker, ) -> Result<Self> { diff --git a/sdk/src/openssl/mod.rs b/sdk/src/openssl/mod.rs @@ -12,23 +12,24 @@ // each license. mod rsa_signer; -pub use rsa_signer::RsaSigner; +pub(crate) use rsa_signer::RsaSigner; mod rsa_validator; -pub use rsa_validator::RsaValidator; +pub(crate) use rsa_validator::RsaValidator; mod ec_signer; -pub use ec_signer::EcSigner; +pub(crate) use ec_signer::EcSigner; mod ec_validator; -pub use ec_validator::EcValidator; +pub(crate) use ec_validator::EcValidator; mod ed_signer; -pub use ed_signer::EdSigner; +pub(crate) use ed_signer::EdSigner; mod ed_validator; -pub use ed_validator::EdValidator; +pub(crate) use ed_validator::EdValidator; +pub mod signer; pub mod temp_signer; use openssl::x509::X509; diff --git a/sdk/src/openssl/rsa_signer.rs b/sdk/src/openssl/rsa_signer.rs @@ -214,13 +214,13 @@ mod tests { use tempfile::tempdir; - use crate::{openssl::temp_signer::get_signer, Signer}; + use crate::{openssl::temp_signer::get_temp_signer, Signer}; #[test] fn signer_from_files() { let temp_dir = tempdir().unwrap(); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); let data = b"some sample content to sign"; let signature = signer.sign(data).unwrap(); diff --git a/sdk/src/openssl/signer.rs b/sdk/src/openssl/signer.rs @@ -0,0 +1,98 @@ +use std::path::Path; + +use crate::{ + error::{Error, Result}, + openssl::{EcSigner, EdSigner, RsaSigner}, + signer::ConfigurableSigner, + Signer, +}; + +/// Creates a signer using signcert and public key +/// +/// Can generate a [`Signer`] instance for all supported formats. +/// +/// # Arguments +/// +/// * `signcert` - A buffer containing a signcert +/// * `pkey` - A buffer containing a public key file +/// * `alg` - A format for signing. Must be one of (`rs256`, `rs384`, `rs512`, +/// `ps256`, `ps384`, `ps512`, `es256`, `es384`, `es512`, or `ed25519`). +/// * `tsa_url` - Optional URL for a timestamp authority. +/// +/// # Returns +/// +/// Returns a [`Signer`] instance or Error + +pub fn get_signer( + signcert: &[u8], + pkey: &[u8], + alg: &str, + tsa_url: Option<String>, +) -> Result<Box<dyn Signer>> { + Ok(match alg { + "ps256" | "ps384" | "ps512" => Box::new(RsaSigner::from_signcert_and_pkey( + signcert, + pkey, + alg.to_owned(), + tsa_url, + )?), + "es256" | "es384" | "es512" => Box::new(EcSigner::from_signcert_and_pkey( + signcert, + pkey, + alg.to_owned(), + tsa_url, + )?), + "ed25519" => Box::new(EdSigner::from_signcert_and_pkey( + signcert, + pkey, + alg.to_owned(), + tsa_url, + )?), + _ => return Err(Error::BadParam(alg.to_owned())), + }) +} + +/// Creates a signer using signcert and public key files +/// +/// Can generate a [`Signer`] instance for all supported formats. +/// +/// # Arguments +/// +/// * `signcert_path` - A path to the signing cert file +/// * `pkey_path` - A path to the public key file +/// * `alg` - A format for signing. Must be one of (`rs256`, `rs384`, `rs512`, +/// `ps256`, `ps384`, `ps512`, `es256`, `es384`, `es512`, or `ed25519`). +/// * `tsa_url` - Optional URL for a timestamp authority. +/// +/// # Returns +/// +/// Returns a [`Signer`] instance or Error + +pub fn get_signer_from_files<P: AsRef<Path>>( + signcert_path: P, + pkey_path: P, + alg: &str, + tsa_url: Option<String>, +) -> Result<Box<dyn Signer>> { + Ok(match alg { + "ps256" | "ps384" | "ps512" => Box::new(RsaSigner::from_files( + &signcert_path, + &pkey_path, + alg.to_owned(), + tsa_url, + )?), + "es256" | "es384" | "es512" => Box::new(EcSigner::from_files( + &signcert_path, + &pkey_path, + alg.to_owned(), + tsa_url, + )?), + "ed25519" => Box::new(EdSigner::from_files( + &signcert_path, + &pkey_path, + alg.to_owned(), + tsa_url, + )?), + _ => return Err(Error::BadParam(alg.to_owned())), + }) +} diff --git a/sdk/src/openssl/temp_signer.rs b/sdk/src/openssl/temp_signer.rs @@ -62,7 +62,7 @@ use crate::{ /// # Panics /// /// Can panic if unable to invoke OpenSSL executable properly. -pub fn get_signer<P: AsRef<Path>>(path: P) -> (RsaSigner, PathBuf) { +pub fn get_temp_signer<P: AsRef<Path>>(path: P) -> (RsaSigner, PathBuf) { let (sign_cert_path, pem_key_path) = make_key_path_pair(path, "temp_key"); create_x509_key_pair( @@ -262,7 +262,7 @@ pub fn get_rsa_signer<P: AsRef<Path>>( /// # Panics /// /// Can panic if unable to invoke OpenSSL executable properly. -pub fn get_signer_by_alg<P: AsRef<Path>>( +pub fn get_temp_signer_by_alg<P: AsRef<Path>>( path: P, alg: &str, tsa_url: Option<String>, diff --git a/sdk/src/signer.rs b/sdk/src/signer.rs @@ -46,7 +46,7 @@ pub trait Signer { } /// Trait to allow loading of signing credential from external sources -pub trait ConfigurableSigner: Signer + Sized { +pub(crate) trait ConfigurableSigner: Signer + Sized { /// Create signer form credential files fn from_files<P: AsRef<std::path::Path>>( signcert_path: P, @@ -64,33 +64,6 @@ pub trait ConfigurableSigner: Signer + Sized { ) -> Result<Self>; } -/// The `Placeholder` implementation provides a placeholder "signer" for use -/// in testing and development contexts where a valid signature is not required. -/// To state the obvious, claims signed using this implementation will not verify. -pub struct Placeholder {} - -impl Signer for Placeholder { - // sign the provided bytes - fn sign(&self, _data: &[u8]) -> Result<Vec<u8>> { - Ok(b"invalid signature".to_vec()) - } - - // algoritim iddentifer string for this Signer - fn alg(&self) -> Option<String> { - None - } - - // list of certificates in der format, with last being cert that signed the claim - fn certs(&self) -> Result<Vec<Vec<u8>>> { - Ok(Vec::new()) - } - - // bytes to reserve for a fully signed claim - fn reserve_size(&self) -> usize { - 128 - } -} - #[cfg(feature = "async_signer")] use async_trait::async_trait; @@ -110,22 +83,3 @@ pub trait AsyncSigner: Sync { /// than this value. fn reserve_size(&self) -> usize; } - -/// The `AsyncPlaceholder` implementation provides a placeholder "async signer" -/// for use in testing and development contexts where a valid signature is not -/// required. To state the obvious, claims signed using this implementation -/// will not verify. -#[cfg(feature = "async_signer")] -pub struct AsyncPlaceholder {} - -#[cfg(feature = "async_signer")] -#[async_trait] -impl AsyncSigner for AsyncPlaceholder { - async fn sign(&self, _data: &[u8]) -> Result<Vec<u8>> { - Ok(b"invalid signature".to_vec()) - } - - fn reserve_size(&self) -> usize { - 128 - } -} diff --git a/sdk/src/store.rs b/sdk/src/store.rs @@ -1695,7 +1695,7 @@ pub mod tests { use crate::{ claim::AssertionStoreJsonFormat, jumbf_io::update_file_jumbf, - openssl::temp_signer::get_signer, utils::patch::patch_file, + openssl::temp_signer::get_temp_signer, utils::patch::patch_file, }; fn create_editing_claim(claim: &mut Claim) -> Result<&mut Claim> { @@ -1747,7 +1747,7 @@ pub mod tests { // Do we generate JUMBF? let temp_dir = tempdir().unwrap(); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); // Test generate JUMBF // Get labels for label test @@ -2040,7 +2040,7 @@ pub mod tests { // Do we generate JUMBF? let temp_dir = tempdir().unwrap(); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); // Move the claim to claims list. Note this is not real, the claims would have to be signed in between commmits store.commit_claim(claim1).unwrap(); @@ -2196,7 +2196,7 @@ pub mod tests { use crate::utils::test::create_test_store; let temp_dir = tempdir().unwrap(); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); // test adding to actual image let ap = fixture_path("earth_apollo17.jpg"); @@ -2249,7 +2249,7 @@ pub mod tests { use crate::{hashed_uri::HashedUri, utils::test::create_test_store}; let temp_dir = tempdir().unwrap(); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); // test adding to actual image let ap = fixture_path("earth_apollo17.jpg"); diff --git a/sdk/tests/integration.rs b/sdk/tests/integration.rs @@ -18,8 +18,7 @@ mod integration_1 { use c2pa::{ assertions::{c2pa_action, Action, Actions}, - openssl::temp_signer::get_signer, - Ingredient, Manifest, ManifestStore, Result, + get_temp_signer, Ingredient, Manifest, ManifestStore, Result, }; use std::path::PathBuf; use tempfile::tempdir; @@ -93,7 +92,7 @@ mod integration_1 { // sign and embed into the target file let temp_dir = tempdir().unwrap(); - let (signer, _) = get_signer(&temp_dir.path()); + let (signer, _) = get_temp_signer(&temp_dir.path()); manifest.embed(&output_path, &output_path, &signer)?;