ec_signer.rs (7067B)
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 ec::EcKey, 16 hash::MessageDigest, 17 pkey::{PKey, Private}, 18 x509::X509, 19 }; 20 use x509_parser::der_parser::{ 21 self, 22 der::{parse_der_integer, parse_der_sequence_defined_g}, 23 }; 24 25 use super::check_chain_order; 26 use crate::{ 27 error::{Error, Result}, 28 signer::ConfigurableSigner, 29 Signer, SigningAlg, 30 }; 31 32 /// Implements `Signer` trait using OpenSSL's implementation of 33 /// ECDSA encryption. 34 pub struct EcSigner { 35 signcerts: Vec<X509>, 36 pkey: EcKey<Private>, 37 38 certs_size: usize, 39 timestamp_size: usize, 40 41 alg: SigningAlg, 42 tsa_url: Option<String>, 43 } 44 45 impl ConfigurableSigner for EcSigner { 46 fn from_signcert_and_pkey( 47 signcert: &[u8], 48 pkey: &[u8], 49 alg: SigningAlg, 50 tsa_url: Option<String>, 51 ) -> Result<Self> { 52 let certs_size = signcert.len(); 53 let pkey = EcKey::private_key_from_pem(pkey).map_err(Error::OpenSslError)?; 54 let signcerts = X509::stack_from_pem(signcert).map_err(Error::OpenSslError)?; 55 56 // make sure cert chains are in order 57 if !check_chain_order(&signcerts) { 58 return Err(Error::BadParam( 59 "certificate chain is not in correct order".to_string(), 60 )); 61 } 62 63 Ok(EcSigner { 64 signcerts, 65 pkey, 66 certs_size, 67 timestamp_size: 10000, /* todo: call out to TSA to get actual timestamp and use that size */ 68 alg, 69 tsa_url, 70 }) 71 } 72 } 73 74 impl Signer for EcSigner { 75 fn sign(&self, data: &[u8]) -> Result<Vec<u8>> { 76 let key = PKey::from_ec_key(self.pkey.clone()).map_err(Error::OpenSslError)?; 77 78 let mut signer = match self.alg { 79 SigningAlg::Es256 => openssl::sign::Signer::new(MessageDigest::sha256(), &key)?, 80 SigningAlg::Es384 => openssl::sign::Signer::new(MessageDigest::sha384(), &key)?, 81 SigningAlg::Es512 => openssl::sign::Signer::new(MessageDigest::sha512(), &key)?, 82 _ => return Err(Error::UnsupportedType), 83 }; 84 85 signer.update(data).map_err(Error::OpenSslError)?; 86 let der_sig = signer.sign_to_vec().map_err(Error::OpenSslError)?; 87 88 der_to_p1363(&der_sig, self.alg) 89 } 90 91 fn alg(&self) -> SigningAlg { 92 self.alg 93 } 94 95 fn certs(&self) -> Result<Vec<Vec<u8>>> { 96 let mut certs: Vec<Vec<u8>> = Vec::new(); 97 98 for c in &self.signcerts { 99 let cert = c.to_der().map_err(Error::OpenSslError)?; 100 certs.push(cert); 101 } 102 103 Ok(certs) 104 } 105 106 fn time_authority_url(&self) -> Option<String> { 107 self.tsa_url.clone() 108 } 109 110 fn reserve_size(&self) -> usize { 111 1024 + self.certs_size + self.timestamp_size // the Cose_Sign1 contains complete certs and timestamps so account for size 112 } 113 } 114 115 // C2PA use P1363 format for EC signatures so we must 116 // convert from ASN.1 DER to IEEE P1363 format to verify. 117 struct ECSigComps<'a> { 118 r: &'a [u8], 119 s: &'a [u8], 120 } 121 122 fn parse_ec_sig(data: &[u8]) -> der_parser::error::BerResult<ECSigComps> { 123 parse_der_sequence_defined_g(|content: &[u8], _| { 124 let (rem1, r) = parse_der_integer(content)?; 125 let (_rem2, s) = parse_der_integer(rem1)?; 126 127 Ok(( 128 data, 129 ECSigComps { 130 r: r.as_slice()?, 131 s: s.as_slice()?, 132 }, 133 )) 134 })(data) 135 } 136 137 fn der_to_p1363(data: &[u8], alg: SigningAlg) -> Result<Vec<u8>> { 138 // P1363 format: r | s 139 140 let (_, p) = parse_ec_sig(data).map_err(|_err| Error::InvalidEcdsaSignature)?; 141 142 let mut r = extfmt::Hexlify(p.r).to_string(); 143 let mut s = extfmt::Hexlify(p.s).to_string(); 144 145 let sig_len: usize = match alg { 146 SigningAlg::Es256 => 64, 147 SigningAlg::Es384 => 96, 148 SigningAlg::Es512 => 132, 149 _ => return Err(Error::UnsupportedType), 150 }; 151 152 // pad or truncate as needed 153 let rp = if r.len() > sig_len { 154 // truncate 155 let offset = r.len() - sig_len; 156 &r[offset..r.len()] 157 } else { 158 // pad 159 while r.len() != sig_len { 160 r.insert(0, '0'); 161 } 162 r.as_ref() 163 }; 164 165 let sp = if s.len() > sig_len { 166 // truncate 167 let offset = s.len() - sig_len; 168 &s[offset..s.len()] 169 } else { 170 // pad 171 while s.len() != sig_len { 172 s.insert(0, '0'); 173 } 174 s.as_ref() 175 }; 176 177 if rp.len() != sig_len || rp.len() != sp.len() { 178 return Err(Error::InvalidEcdsaSignature); 179 } 180 181 // merge r and s strings 182 let mut new_sig = rp.to_string(); 183 new_sig.push_str(sp); 184 185 // convert back from hex string to byte array 186 (0..new_sig.len()) 187 .step_by(2) 188 .map(|i| { 189 u8::from_str_radix(&new_sig[i..i + 2], 16).map_err(|_err| Error::InvalidEcdsaSignature) 190 }) 191 .collect() 192 } 193 194 #[cfg(test)] 195 #[cfg(feature = "file_io")] 196 mod tests { 197 #![allow(clippy::unwrap_used)] 198 199 use super::*; 200 use crate::{openssl::temp_signer, utils::test::fixture_path}; 201 202 #[test] 203 fn es256_signer() { 204 let cert_dir = fixture_path("certs"); 205 206 let (signer, _) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es256, None); 207 208 let data = b"some sample content to sign"; 209 println!("data len = {}", data.len()); 210 211 let signature = signer.sign(data).unwrap(); 212 println!("signature.len = {}", signature.len()); 213 assert!(signature.len() >= 64); 214 assert!(signature.len() <= signer.reserve_size()); 215 } 216 217 #[test] 218 fn es384_signer() { 219 let cert_dir = fixture_path("certs"); 220 221 let (signer, _) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es384, None); 222 223 let data = b"some sample content to sign"; 224 println!("data len = {}", data.len()); 225 226 let signature = signer.sign(data).unwrap(); 227 println!("signature.len = {}", signature.len()); 228 assert!(signature.len() >= 64); 229 assert!(signature.len() <= signer.reserve_size()); 230 } 231 232 #[test] 233 fn es512_signer() { 234 let cert_dir = fixture_path("certs"); 235 236 let (signer, _) = temp_signer::get_ec_signer(cert_dir, SigningAlg::Es512, None); 237 238 let data = b"some sample content to sign"; 239 println!("data len = {}", data.len()); 240 241 let signature = signer.sign(data).unwrap(); 242 println!("signature.len = {}", signature.len()); 243 assert!(signature.len() >= 64); 244 assert!(signature.len() <= signer.reserve_size()); 245 } 246 }