diff --git a/Cargo.lock b/Cargo.lock index 4a095aa4f..e5d7b5502 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -800,6 +800,7 @@ dependencies = [ "assert_cmd", "atree", "c2pa", + "c2pa-crypto", "clap", "env_logger", "glob", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d4b1c1066..4a9b6f8db 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,6 +27,7 @@ c2pa = { path = "../sdk", version = "0.40.0", features = [ "pdf", "unstable_api", ] } +c2pa-crypto = { path = "../internal/crypto", version = "0.2.0" } clap = { version = "4.5.10", features = ["derive", "env"] } env_logger = "0.11.4" glob = "0.3.1" diff --git a/cli/src/callback_signer.rs b/cli/src/callback_signer.rs index 6f4928b9e..b07ef6290 100644 --- a/cli/src/callback_signer.rs +++ b/cli/src/callback_signer.rs @@ -18,6 +18,10 @@ use std::{ use anyhow::{bail, Context}; use c2pa::{Error, Signer, SigningAlg}; +use c2pa_crypto::{ + raw_signature::{RawSigner, RawSignerError}, + time_stamp::TimeStampProvider, +}; use crate::signer::SignConfig; @@ -183,6 +187,53 @@ impl Signer for CallbackSigner<'_> { fn time_authority_url(&self) -> Option { self.config.tsa_url.clone() } + + fn raw_signer(&self) -> Box<&dyn RawSigner> { + Box::new(self) + } +} + +impl RawSigner for CallbackSigner<'_> { + fn sign(&self, data: &[u8]) -> Result, RawSignerError> { + self.callback.sign(data).map_err(|e| { + eprintln!("Unable to embed signature into asset. {}", e); + RawSignerError::InternalError(e.to_string()) + }) + } + + fn alg(&self) -> SigningAlg { + self.config.alg + } + + fn cert_chain(&self) -> Result>, RawSignerError> { + let cert_contents = std::fs::read(&self.config.sign_cert_path)?; + + let mut pems = pem::parse_many(cert_contents).map_err(|_| Error::CoseInvalidCert)?; + // [pem::parse_many] returns an empty vector if you supply invalid contents, like json, for example. + // Check here if the pems vector is empty. + if pems.is_empty() { + return Err(RawSignerError::InvalidSigningCredentials( + "no certificates provided".to_string(), + )); + } + + let sign_cert = pems + .drain(..) + .map(|p| p.into_contents()) + .collect::>>(); + + Ok(sign_cert) + } + + fn reserve_size(&self) -> usize { + self.config.reserve_size + } +} + +impl TimeStampProvider for CallbackSigner<'_> { + fn time_stamp_service_url(&self) -> Option { + self.config.tsa_url.clone() + } } #[cfg(test)] @@ -214,7 +265,7 @@ mod test { let callback = Box::new(mock_callback_signer); let signer = CallbackSigner::new(callback, config); - assert_eq!(signer.sign(&[]).unwrap(), expected); + assert_eq!(Signer::sign(&signer, &[]).unwrap(), expected); } #[test] @@ -237,7 +288,10 @@ mod test { let callback = Box::new(mock_callback_signer); let signer = CallbackSigner::new(callback, config); - assert!(matches!(signer.sign(&[]), Err(Error::EmbeddingError))); + assert!(matches!( + Signer::sign(&signer, &[]), + Err(Error::EmbeddingError) + )); } #[test] @@ -291,8 +345,8 @@ mod test { let callback = Box::::default(); let signer = CallbackSigner::new(callback, esc); - assert_eq!(signer.alg(), expected_alg); - assert_eq!(signer.reserve_size(), expected_reserve_size); + assert_eq!(Signer::alg(&signer), expected_alg); + assert_eq!(Signer::reserve_size(&signer), expected_reserve_size); } #[test] diff --git a/internal/crypto/src/asn1/rfc3161.rs b/internal/crypto/src/asn1/rfc3161.rs index 03b89ffc3..789ee7c6e 100644 --- a/internal/crypto/src/asn1/rfc3161.rs +++ b/internal/crypto/src/asn1/rfc3161.rs @@ -24,11 +24,6 @@ use crate::asn1::{rfc4210::PkiFreeText, rfc5652::ContentInfo}; /// 1.2.840.113549.1.9.16.1.4 pub const OID_CONTENT_TYPE_TST_INFO: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 16, 1, 4]); -/// id-aa-timeStampToken -/// -/// 1.2.840.113549.1.9.16.2.14 -pub const OID_TIME_STAMP_TOKEN: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 16, 2, 14]); - /// A time-stamp request. /// /// ```ASN.1 @@ -53,6 +48,7 @@ pub struct TimeStampReq { } impl TimeStampReq { + #[allow(dead_code)] // not used on all platforms pub fn take_from(cons: &mut Constructed) -> Result> { cons.take_sequence(|cons| { let version = Integer::take_from(cons)?; @@ -149,17 +145,6 @@ impl TimeStampResp { }) }) } - - pub fn encode_ref(&self) -> impl Values + '_ { - encode::sequence(( - self.status.encode_ref(), - if let Some(time_stamp_token) = &self.time_stamp_token { - Some(time_stamp_token) - } else { - None - }, - )) - } } /// PKI status info @@ -191,16 +176,6 @@ impl PkiStatusInfo { }) }) } - - pub fn encode_ref(&self) -> impl Values + '_ { - encode::sequence(( - self.status.encode(), - self.status_string - .as_ref() - .map(|status_string| status_string.encode_ref()), - self.fail_info.as_ref().map(|fail_info| fail_info.encode()), - )) - } } /// PKI status. diff --git a/internal/crypto/src/asn1/rfc3281.rs b/internal/crypto/src/asn1/rfc3281.rs index 8b0505cb8..180088b27 100644 --- a/internal/crypto/src/asn1/rfc3281.rs +++ b/internal/crypto/src/asn1/rfc3281.rs @@ -79,6 +79,7 @@ impl AttributeCertificateInfo { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[allow(unused)] pub enum AttCertVersion { V2 = 1, } @@ -104,6 +105,7 @@ pub struct Holder { } #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(unused)] pub enum DigestedObjectType { PublicKey = 0, PublicKeyCert = 1, @@ -142,6 +144,7 @@ pub struct ObjectDigestInfo { /// } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(unused)] pub enum AttCertIssuer { V1Form(GeneralNames), V2Form(Box), diff --git a/internal/crypto/src/asn1/rfc4210.rs b/internal/crypto/src/asn1/rfc4210.rs index 39022baaa..93dc3719d 100644 --- a/internal/crypto/src/asn1/rfc4210.rs +++ b/internal/crypto/src/asn1/rfc4210.rs @@ -8,7 +8,6 @@ use bcder::{ decode::{Constructed, DecodeError, Source}, - encode::{self, Values}, Tag, Utf8String, }; @@ -27,10 +26,6 @@ impl PkiFreeText { cons.take_opt_sequence(|cons| Self::from_sequence(cons)) } - pub fn take_from(cons: &mut Constructed) -> Result> { - cons.take_sequence(|cons| Self::from_sequence(cons)) - } - pub fn from_sequence( cons: &mut Constructed, ) -> Result> { @@ -44,8 +39,4 @@ impl PkiFreeText { Ok(Self(res)) } - - pub fn encode_ref(&self) -> impl Values + '_ { - encode::sequence(encode::slice(&self.0, |x| x.clone().encode())) - } } diff --git a/internal/crypto/src/asn1/rfc5652.rs b/internal/crypto/src/asn1/rfc5652.rs index 5032f15e8..ba8883d1b 100644 --- a/internal/crypto/src/asn1/rfc5652.rs +++ b/internal/crypto/src/asn1/rfc5652.rs @@ -29,43 +29,11 @@ use x509_certificate::{asn1time::*, rfc3280::*, rfc5280::*, rfc5652::*}; use crate::asn1::rfc3281::AttributeCertificate; -/// The data content type. -/// -/// `id-data` in the specification. -/// -/// 1.2.840.113549.1.7.1 -pub const OID_ID_DATA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 7, 1]); - /// The signed-data content type. /// /// 1.2.840.113549.1.7.2 pub const OID_ID_SIGNED_DATA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 7, 2]); -/// Enveloped data content type. -/// -/// 1.2.840.113549.1.7.3 -pub const OID_ENVELOPE_DATA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 7, 3]); - -/// Digested-data content type. -/// -/// 1.2.840.113549.1.7.5 -pub const OID_DIGESTED_DATA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 7, 5]); - -/// Encrypted-data content type. -/// -/// 1.2.840.113549.1.7.6 -pub const OID_ENCRYPTED_DATA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 7, 6]); - -/// Authenticated-data content type. -/// -/// 1.2.840.113549.1.9.16.1.2 -pub const OID_AUTHENTICATED_DATA: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 16, 1, 2]); - -/// Identifies the content-type attribute. -/// -/// 1.2.840.113549.1.9.3 -pub const OID_CONTENT_TYPE: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 3]); - /// Identifies the message-digest attribute. /// /// 1.2.840.113549.1.9.4 @@ -76,11 +44,6 @@ pub const OID_MESSAGE_DIGEST: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, /// 1.2.840.113549.1.9.5 pub const OID_SIGNING_TIME: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 5]); -/// Identifies the countersignature attribute. -/// -/// 1.2.840.113549.1.9.6 -pub const OID_COUNTER_SIGNATURE: ConstOid = Oid(&[42, 134, 72, 134, 247, 13, 1, 9, 6]); - /// Content info. /// /// ```ASN.1 @@ -158,23 +121,6 @@ pub struct SignedData { } impl SignedData { - /// Attempt to decode BER encoded bytes to a parsed data structure. - pub fn decode_ber(data: &[u8]) -> Result> { - Constructed::decode(data, bcder::Mode::Ber, Self::decode) - } - - pub fn decode(cons: &mut Constructed) -> Result> { - cons.take_sequence(|cons| { - let oid = Oid::take_from(cons)?; - - if oid != OID_ID_SIGNED_DATA { - return Err(cons.content_err("expected signed data OID")); - } - - cons.take_constructed_if(Tag::CTX_0, Self::take_from) - }) - } - pub fn take_from(cons: &mut Constructed) -> Result> { cons.take_sequence(|cons| { let version = CmsVersion::take_from(cons)?; @@ -197,25 +143,6 @@ impl SignedData { }) }) } - - pub fn encode_ref(&self) -> impl Values + '_ { - encode::sequence(( - OID_ID_SIGNED_DATA.encode_ref(), - encode::sequence_as( - Tag::CTX_0, - encode::sequence(( - self.version.encode(), - self.digest_algorithms.encode_ref(), - self.content_info.encode_ref(), - self.certificates - .as_ref() - .map(|certs| certs.encode_ref_as(Tag::CTX_0)), - // TODO crls. - self.signer_infos.encode_ref(), - )), - ), - )) - } } /// Digest algorithm identifiers. @@ -252,10 +179,6 @@ impl DigestAlgorithmIdentifiers { Ok(Self(identifiers)) }) } - - pub fn encode_ref(&self) -> impl Values + '_ { - encode::set(&self.0) - } } pub type DigestAlgorithmIdentifier = AlgorithmIdentifier; @@ -294,10 +217,6 @@ impl SignerInfos { Ok(Self(infos)) }) } - - pub fn encode_ref(&self) -> impl Values + '_ { - encode::set(&self.0) - } } /// Encapsulated content info. @@ -343,15 +262,6 @@ impl EncapsulatedContentInfo { }) }) } - - pub fn encode_ref(&self) -> impl Values + '_ { - encode::sequence(( - self.content_type.encode_ref(), - self.content - .as_ref() - .map(|content| encode::sequence_as(Tag::CTX_0, content.encode_ref())), - )) - } } /// Per-signer information. @@ -647,10 +557,6 @@ impl DerefMut for SignedAttributes { } impl SignedAttributes { - pub fn take_from(cons: &mut Constructed) -> Result> { - cons.take_set(|cons| Self::take_from_set(cons)) - } - pub fn take_from_set( cons: &mut Constructed, ) -> Result> { @@ -759,10 +665,6 @@ impl DerefMut for UnsignedAttributes { } impl UnsignedAttributes { - pub fn take_from(cons: &mut Constructed) -> Result> { - cons.take_set(|cons| Self::take_from_set(cons)) - } - pub fn take_from_set( cons: &mut Constructed, ) -> Result> { @@ -846,6 +748,8 @@ pub type UnprotectedAttributes = Vec; /// ori [4] OtherRecipientInfo } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(unused)] +#[allow(clippy::enum_variant_names)] pub enum RecipientInfo { KeyTransRecipientInfo(KeyTransRecipientInfo), KeyAgreeRecipientInfo(KeyAgreeRecipientInfo), @@ -881,6 +785,7 @@ pub struct KeyTransRecipientInfo { /// subjectKeyIdentifier [0] SubjectKeyIdentifier } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(unused)] pub enum RecipientIdentifier { IssuerAndSerialNumber(IssuerAndSerialNumber), SubjectKeyIdentifier(SubjectKeyIdentifier), @@ -914,6 +819,7 @@ pub struct KeyAgreeRecipientInfo { /// originatorKey [1] OriginatorPublicKey } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(unused)] pub enum OriginatorIdentifierOrKey { IssuerAndSerialNumber(IssuerAndSerialNumber), SubjectKeyIdentifier(SubjectKeyIdentifier), @@ -957,6 +863,7 @@ pub struct RecipientEncryptedKey { /// rKeyId [0] IMPLICIT RecipientKeyIdentifier } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(unused)] pub enum KeyAgreeRecipientIdentifier { IssuerAndSerialNumber(IssuerAndSerialNumber), RKeyId(RecipientKeyIdentifier), @@ -1135,6 +1042,7 @@ impl RevocationInfoChoices { /// other [1] IMPLICIT OtherRevocationInfoFormat } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(unused)] pub enum RevocationInfoChoice { Crl(Box), Other(OtherRevocationInfoFormat), @@ -1268,10 +1176,6 @@ impl CertificateSet { Ok(Self(certs)) } - - pub fn encode_ref_as(&self, tag: Tag) -> impl Values + '_ { - encode::set_as(tag, &self.0) - } } /// Issuer and serial number. @@ -1372,10 +1276,6 @@ pub struct OtherKeyAttribute { pub type ContentType = Oid; -pub type MessageDigest = OctetString; - -pub type SigningTime = Time; - /// Time variant. /// /// ```ASN.1 @@ -1416,6 +1316,4 @@ impl From