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

trust_handler.rs (6406B)


      1 // Copyright 2023 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 std::{
     15     collections::HashSet,
     16     io::{read_to_string, Cursor, Read},
     17     panic::{RefUnwindSafe, UnwindSafe},
     18     str::FromStr,
     19 };
     20 
     21 use asn1_rs::{oid, Oid};
     22 
     23 use crate::{hash_utils::hash_sha256, utils::base64, Error, Result};
     24 
     25 pub(crate) static EMAIL_PROTECTION_OID: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .3 .4);
     26 pub(crate) static TIMESTAMPING_OID: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .3 .8);
     27 pub(crate) static OCSP_SIGNING_OID: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .3 .9);
     28 pub(crate) static DOCUMENT_SIGNING_OID: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .3 .36);
     29 
     30 // Trait for supply configuration and handling of trust lists and EKU configuration store
     31 //
     32 // `RefUnwindSafe` + `UnwindSafe` were added to ensure `Store` is unwind safe and to preserve
     33 // backwards compatbility.
     34 pub(crate) trait TrustHandlerConfig: RefUnwindSafe + UnwindSafe + Sync + Send {
     35     fn new() -> Self
     36     where
     37         Self: Sized;
     38 
     39     // add trust anchors
     40     fn load_trust_anchors_from_data(&mut self, trust_data: &mut dyn Read) -> Result<()>;
     41 
     42     // add allowed list
     43     fn load_allowed_list(&mut self, allowed_list: &mut dyn Read) -> Result<()>;
     44 
     45     // append private trust anchors
     46     fn append_private_trust_data(&mut self, private_anchors_data: &mut dyn Read) -> Result<()>;
     47 
     48     // clear all entries in trust handler list
     49     fn clear(&mut self);
     50 
     51     // load EKU configuration
     52     fn load_configuration(&mut self, config_data: &mut dyn Read) -> Result<()>;
     53 
     54     // list off auxillary allowed EKU Oid
     55     fn get_auxillary_ekus(&self) -> Vec<Oid>;
     56 
     57     // list of all anchors
     58     #[allow(dead_code)] // Only used in calls with allow dead_code
     59     fn get_anchors(&self) -> Vec<Vec<u8>>;
     60 
     61     // set of allowed cert hashes
     62     #[allow(dead_code)] // Only used in calls with allow dead_code
     63     fn get_allowed_list(&self) -> &HashSet<String>;
     64 }
     65 
     66 impl std::fmt::Debug for dyn TrustHandlerConfig {
     67     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     68         write!(f, "TrustHandler Installed")
     69     }
     70 }
     71 
     72 pub(crate) fn has_allowed_oid<'a>(
     73     eku: &x509_parser::extensions::ExtendedKeyUsage,
     74     allowed_ekus: &'a [Oid],
     75 ) -> Option<&'a Oid<'a>> {
     76     if eku.email_protection {
     77         return Some(&EMAIL_PROTECTION_OID);
     78     }
     79 
     80     if eku.time_stamping {
     81         return Some(&TIMESTAMPING_OID);
     82     }
     83 
     84     if eku.ocsp_signing {
     85         return Some(&OCSP_SIGNING_OID);
     86     }
     87 
     88     let mut last_oid = None;
     89     if eku.other.iter().any(|v| {
     90         allowed_ekus.iter().any(|oid| {
     91             if oid == v {
     92                 last_oid = Some(oid);
     93                 true
     94             } else {
     95                 false
     96             }
     97         })
     98     }) {
     99         return last_oid;
    100     }
    101     None
    102 }
    103 
    104 // load set of validation EKUs, ignoring unrecognized Oid lines
    105 #[allow(dead_code)]
    106 pub(crate) fn load_eku_configuration(config_data: &mut dyn Read) -> Result<Vec<String>> {
    107     let mut oid_vec = Vec::new();
    108 
    109     for line in read_to_string(config_data)?.lines() {
    110         if Oid::from_str(line).is_ok() {
    111             oid_vec.push(line.to_owned());
    112         }
    113     }
    114     Ok(oid_vec)
    115 }
    116 
    117 pub(crate) fn load_trust_from_data(trust_data: &[u8]) -> Result<Vec<Vec<u8>>> {
    118     let mut certs = Vec::new();
    119 
    120     for pem_result in x509_parser::pem::Pem::iter_from_buffer(trust_data) {
    121         let pem = pem_result.map_err(|_e| Error::CoseInvalidCert)?;
    122         certs.push(pem.contents);
    123     }
    124     Ok(certs)
    125 }
    126 
    127 // Pass through trust for the case of claim signer usage since it has known trust with context
    128 // configured to all email protection, timestamping, ocsp signing and document signing
    129 #[derive(Debug)]
    130 pub(crate) struct TrustPassThrough {
    131     allowed_cert_set: HashSet<String>,
    132     config_store: Vec<u8>,
    133 }
    134 
    135 impl TrustHandlerConfig for TrustPassThrough {
    136     fn new() -> Self
    137     where
    138         Self: Sized,
    139     {
    140         TrustPassThrough {
    141             allowed_cert_set: HashSet::new(),
    142             config_store: Vec::new(),
    143         }
    144     }
    145 
    146     fn load_trust_anchors_from_data(&mut self, _trust_data: &mut dyn std::io::Read) -> Result<()> {
    147         Ok(())
    148     }
    149 
    150     fn append_private_trust_data(
    151         &mut self,
    152         _private_anchors_data: &mut dyn std::io::Read,
    153     ) -> Result<()> {
    154         Ok(())
    155     }
    156 
    157     fn clear(&mut self) {}
    158 
    159     fn load_configuration(&mut self, config_data: &mut dyn Read) -> Result<()> {
    160         config_data.read_to_end(&mut self.config_store)?;
    161         Ok(())
    162     }
    163 
    164     // list off auxillary allowed EKU Oid
    165     fn get_auxillary_ekus(&self) -> Vec<Oid> {
    166         let mut oids = Vec::new();
    167         if let Ok(oid_strings) = load_eku_configuration(&mut Cursor::new(&self.config_store)) {
    168             for oid_str in &oid_strings {
    169                 if let Ok(oid) = Oid::from_str(oid_str) {
    170                     oids.push(oid);
    171                 }
    172             }
    173         }
    174         if oids.is_empty() {
    175             // return default
    176             vec![
    177                 EMAIL_PROTECTION_OID.to_owned(),
    178                 TIMESTAMPING_OID.to_owned(),
    179                 OCSP_SIGNING_OID.to_owned(),
    180                 DOCUMENT_SIGNING_OID.to_owned(),
    181             ]
    182         } else {
    183             oids
    184         }
    185     }
    186 
    187     fn get_anchors(&self) -> Vec<Vec<u8>> {
    188         Vec::new()
    189     }
    190 
    191     fn load_allowed_list(&mut self, allowed_list: &mut dyn std::io::prelude::Read) -> Result<()> {
    192         let mut buffer = Vec::new();
    193         allowed_list.read_to_end(&mut buffer)?;
    194 
    195         if let Ok(cert_list) = load_trust_from_data(&buffer) {
    196             for cert_der in &cert_list {
    197                 let cert_sha256 = hash_sha256(cert_der);
    198                 let cert_hash_base64 = base64::encode(&cert_sha256);
    199 
    200                 self.allowed_cert_set.insert(cert_hash_base64);
    201             }
    202         }
    203         Ok(())
    204     }
    205 
    206     fn get_allowed_list(&self) -> &std::collections::HashSet<String> {
    207         &self.allowed_cert_set
    208     }
    209 }