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

ed_signer.rs (3593B)


      1 // Copyright 2022 Adobe. All rights reserved.
      2 // This file is licensed to you under the Apache License,
      3 // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
      4 // or the MIT license (http://opensource.org/licenses/MIT),
      5 // at your option.
      6 
      7 // Unless required by applicable law or agreed to in writing,
      8 // this software is distributed on an "AS IS" BASIS, WITHOUT
      9 // WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
     10 // implied. See the LICENSE-MIT and LICENSE-APACHE files for the
     11 // specific language governing permissions and limitations under
     12 // each license.
     13 
     14 use openssl::{
     15     pkey::{PKey, Private},
     16     x509::X509,
     17 };
     18 
     19 use super::check_chain_order;
     20 use crate::{signer::ConfigurableSigner, Error, Result, Signer, SigningAlg};
     21 
     22 /// Implements `Signer` trait using OpenSSL's implementation of
     23 /// Edwards Curve encryption.
     24 pub struct EdSigner {
     25     signcerts: Vec<X509>,
     26     pkey: PKey<Private>,
     27 
     28     certs_size: usize,
     29     timestamp_size: usize,
     30 
     31     alg: SigningAlg,
     32     tsa_url: Option<String>,
     33 }
     34 
     35 impl ConfigurableSigner for EdSigner {
     36     fn from_signcert_and_pkey(
     37         signcert: &[u8],
     38         pkey: &[u8],
     39         alg: SigningAlg,
     40         tsa_url: Option<String>,
     41     ) -> Result<Self> {
     42         let certs_size = signcert.len();
     43         let signcerts = X509::stack_from_pem(signcert).map_err(Error::OpenSslError)?;
     44         let pkey = PKey::private_key_from_pem(pkey).map_err(Error::OpenSslError)?;
     45 
     46         if alg != SigningAlg::Ed25519 {
     47             return Err(Error::UnsupportedType); // only ed25519 is supported by C2PA
     48         }
     49 
     50         // make sure cert chains are in order
     51         if !check_chain_order(&signcerts) {
     52             return Err(Error::BadParam(
     53                 "certificate chain is not in correct order".to_string(),
     54             ));
     55         }
     56 
     57         Ok(EdSigner {
     58             signcerts,
     59             pkey,
     60             certs_size,
     61             timestamp_size: 10000, /* todo: call out to TSA to get actual timestamp and use that size */
     62             alg,
     63             tsa_url,
     64         })
     65     }
     66 }
     67 
     68 impl Signer for EdSigner {
     69     fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
     70         let mut signer =
     71             openssl::sign::Signer::new_without_digest(&self.pkey).map_err(Error::OpenSslError)?;
     72 
     73         let signed_data = signer.sign_oneshot_to_vec(data)?;
     74 
     75         Ok(signed_data)
     76     }
     77 
     78     fn alg(&self) -> SigningAlg {
     79         self.alg
     80     }
     81 
     82     fn certs(&self) -> Result<Vec<Vec<u8>>> {
     83         let mut certs: Vec<Vec<u8>> = Vec::new();
     84 
     85         for c in &self.signcerts {
     86             let cert = c.to_der().map_err(Error::OpenSslError)?;
     87             certs.push(cert);
     88         }
     89 
     90         Ok(certs)
     91     }
     92 
     93     fn time_authority_url(&self) -> Option<String> {
     94         self.tsa_url.clone()
     95     }
     96 
     97     fn reserve_size(&self) -> usize {
     98         1024 + self.certs_size + self.timestamp_size // the Cose_Sign1 contains complete certs and timestamps so account for size
     99     }
    100 }
    101 
    102 #[cfg(test)]
    103 #[cfg(feature = "file_io")]
    104 mod tests {
    105     #![allow(clippy::unwrap_used)]
    106     use super::*;
    107     use crate::{openssl::temp_signer, utils::test::fixture_path};
    108 
    109     #[test]
    110     fn ed25519_signer() {
    111         let cert_dir = fixture_path("certs");
    112 
    113         let (signer, _) = temp_signer::get_ed_signer(cert_dir, SigningAlg::Ed25519, None);
    114 
    115         let data = b"some sample content to sign";
    116         println!("data len = {}", data.len());
    117 
    118         let signature = signer.sign(data).unwrap();
    119         println!("signature.len = {}", signature.len());
    120         assert!(signature.len() >= 64);
    121         assert!(signature.len() <= signer.reserve_size());
    122     }
    123 }