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

ec_validator.rs (7184B)


      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::{ec::EcKey, hash::MessageDigest, pkey::PKey};
     15 
     16 use crate::{validator::CoseValidator, Error, Result, SigningAlg};
     17 
     18 pub struct EcValidator {
     19     alg: SigningAlg,
     20 }
     21 
     22 impl EcValidator {
     23     pub const fn new(alg: SigningAlg) -> Self {
     24         EcValidator { alg }
     25     }
     26 }
     27 
     28 impl CoseValidator for EcValidator {
     29     fn validate(&self, sig: &[u8], data: &[u8], pkey: &[u8]) -> Result<bool> {
     30         let public_key = EcKey::public_key_from_der(pkey).map_err(|_err| Error::CoseSignature)?;
     31         let key = PKey::from_ec_key(public_key).map_err(wrap_openssl_err)?;
     32 
     33         let mut verifier = match self.alg {
     34             SigningAlg::Es256 => openssl::sign::Verifier::new(MessageDigest::sha256(), &key)?,
     35             SigningAlg::Es384 => openssl::sign::Verifier::new(MessageDigest::sha384(), &key)?,
     36             SigningAlg::Es512 => openssl::sign::Verifier::new(MessageDigest::sha512(), &key)?,
     37             _ => return Err(Error::UnsupportedType),
     38         };
     39 
     40         // is this an expected P1363 sig size
     41         let sig_der = if sig.len() == 64 || sig.len() == 96 || sig.len() == 132 {
     42             if sig.len()
     43                 != match self.alg {
     44                     SigningAlg::Es256 => 64,
     45                     SigningAlg::Es384 => 96,
     46                     SigningAlg::Es512 => 132,
     47                     _ => return Err(Error::UnsupportedType),
     48                 }
     49             {
     50                 return Err(Error::CoseSignature);
     51             }
     52 
     53             // convert P1363 sig to DER sig
     54             let sig_len = sig.len() / 2;
     55             let r = openssl::bn::BigNum::from_slice(&sig[0..sig_len])
     56                 .map_err(|_err| Error::CoseSignature)?;
     57             let s = openssl::bn::BigNum::from_slice(&sig[sig_len..])
     58                 .map_err(|_err| Error::CoseSignature)?;
     59 
     60             let ecdsa_sig = openssl::ecdsa::EcdsaSig::from_private_components(r, s)
     61                 .map_err(|_err| Error::CoseSignature)?;
     62 
     63             ecdsa_sig.to_der().map_err(|_err| Error::CoseSignature)?
     64         } else {
     65             sig.to_vec()
     66         };
     67 
     68         verifier.update(data).map_err(wrap_openssl_err)?;
     69         verifier
     70             .verify(&sig_der)
     71             .map_err(|_err| Error::CoseSignature)
     72     }
     73 }
     74 
     75 const fn wrap_openssl_err(err: openssl::error::ErrorStack) -> Error {
     76     Error::OpenSslError(err)
     77 }
     78 
     79 #[cfg(test)]
     80 #[cfg(feature = "file_io")]
     81 mod tests {
     82     #![allow(clippy::unwrap_used)]
     83     use super::*;
     84     use crate::{openssl::temp_signer, utils::test::fixture_path, Signer};
     85 
     86     #[test]
     87     fn sign_and_validate_es256() {
     88         let cert_dir = fixture_path("certs");
     89 
     90         let (signer, cert_path) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es256, None);
     91 
     92         let data = b"some sample content to sign";
     93         println!("data len = {}", data.len());
     94 
     95         let signature = signer.sign(data).unwrap();
     96         println!("signature.len = {}", signature.len());
     97         assert!(signature.len() >= 64);
     98         assert!(signature.len() <= signer.reserve_size());
     99 
    100         let cert_bytes = std::fs::read(cert_path).unwrap();
    101 
    102         let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
    103         let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
    104 
    105         let validator = EcValidator::new(SigningAlg::Es256);
    106         assert!(validator.validate(&signature, data, &pub_key).unwrap());
    107     }
    108 
    109     #[test]
    110     fn sign_and_validate_es384() {
    111         let cert_dir = fixture_path("certs");
    112 
    113         let (signer, cert_path) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es384, 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         let cert_bytes = std::fs::read(cert_path).unwrap();
    124 
    125         let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
    126         let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
    127 
    128         let validator = EcValidator::new(SigningAlg::Es384);
    129         assert!(validator.validate(&signature, data, &pub_key).unwrap());
    130     }
    131 
    132     #[test]
    133     fn sign_and_validate_es512() {
    134         let cert_dir = fixture_path("certs");
    135 
    136         let (signer, cert_path) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es512, None);
    137 
    138         let data = b"some sample content to sign";
    139         println!("data len = {}", data.len());
    140 
    141         let signature = signer.sign(data).unwrap();
    142         println!("signature.len = {}", signature.len());
    143         assert!(signature.len() >= 64);
    144         assert!(signature.len() <= signer.reserve_size());
    145 
    146         let cert_bytes = std::fs::read(cert_path).unwrap();
    147 
    148         let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
    149         let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
    150 
    151         let validator = EcValidator::new(SigningAlg::Es512);
    152         assert!(validator.validate(&signature, data, &pub_key).unwrap());
    153     }
    154 
    155     #[test]
    156     fn bad_sig_es256() {
    157         let cert_dir = fixture_path("certs");
    158 
    159         let (signer, cert_path) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es256, None);
    160 
    161         let data = b"some sample content to sign";
    162         println!("data len = {}", data.len());
    163         let mut signature = signer.sign(data).unwrap();
    164 
    165         signature.push(10);
    166 
    167         let cert_bytes = std::fs::read(cert_path).unwrap();
    168         let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
    169         let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
    170 
    171         let validator = EcValidator::new(SigningAlg::Es256);
    172         let validated = validator.validate(&signature, data, &pub_key);
    173         assert!(validated.is_err());
    174     }
    175 
    176     #[test]
    177     fn bad_data_es256() {
    178         let cert_dir = fixture_path("certs");
    179 
    180         let (signer, cert_path) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es256, None);
    181 
    182         let mut data = b"some sample content to sign".to_vec();
    183         println!("data len = {}", data.len());
    184         let signature = signer.sign(&data).unwrap();
    185 
    186         data[5] = 10;
    187         data[6] = 11;
    188 
    189         let cert_bytes = std::fs::read(cert_path).unwrap();
    190         let signcert = openssl::x509::X509::from_pem(&cert_bytes).unwrap();
    191         let pub_key = signcert.public_key().unwrap().public_key_to_der().unwrap();
    192 
    193         let validator = EcValidator::new(SigningAlg::Es256);
    194         assert!(!validator.validate(&signature, &data, &pub_key).unwrap());
    195     }
    196 }