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

cose_validator.rs (54600B)


      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 std::io::Cursor;
     15 
     16 use asn1_rs::{Any, Class, Header, Tag};
     17 use async_generic::async_generic;
     18 use ciborium::value::Value;
     19 use conv::*;
     20 use coset::{
     21     iana::{self, EnumI64},
     22     sig_structure_data, Label, TaggedCborSerializable,
     23 };
     24 use x509_parser::{
     25     der_parser::{ber::parse_ber_sequence, oid},
     26     num_bigint::BigUint,
     27     oid_registry::Oid,
     28     prelude::*,
     29 };
     30 
     31 #[cfg(feature = "openssl")]
     32 use crate::openssl::verify_trust;
     33 #[cfg(not(target_arch = "wasm32"))]
     34 use crate::validator::{get_validator, CoseValidator};
     35 use crate::{
     36     asn1::rfc3161::TstInfo,
     37     error::{Error, Result},
     38     ocsp_utils::{check_ocsp_response, OcspData},
     39     settings::get_settings_value,
     40     status_tracker::{log_item, StatusTracker},
     41     time_stamp::gt_to_datetime,
     42     trust_handler::{has_allowed_oid, TrustHandlerConfig},
     43     validation_status,
     44     validator::ValidationInfo,
     45     SigningAlg,
     46 };
     47 #[cfg(target_arch = "wasm32")]
     48 use crate::{
     49     wasm::webcrypto_validator::validate_async, wasm::webpki_trust_handler::verify_trust_async,
     50 };
     51 
     52 pub(crate) const RSA_OID: Oid<'static> = oid!(1.2.840 .113549 .1 .1 .1);
     53 pub(crate) const EC_PUBLICKEY_OID: Oid<'static> = oid!(1.2.840 .10045 .2 .1);
     54 pub(crate) const ECDSA_WITH_SHA256_OID: Oid<'static> = oid!(1.2.840 .10045 .4 .3 .2);
     55 pub(crate) const ECDSA_WITH_SHA384_OID: Oid<'static> = oid!(1.2.840 .10045 .4 .3 .3);
     56 pub(crate) const ECDSA_WITH_SHA512_OID: Oid<'static> = oid!(1.2.840 .10045 .4 .3 .4);
     57 pub(crate) const RSASSA_PSS_OID: Oid<'static> = oid!(1.2.840 .113549 .1 .1 .10);
     58 pub(crate) const SHA256_WITH_RSAENCRYPTION_OID: Oid<'static> = oid!(1.2.840 .113549 .1 .1 .11);
     59 pub(crate) const SHA384_WITH_RSAENCRYPTION_OID: Oid<'static> = oid!(1.2.840 .113549 .1 .1 .12);
     60 pub(crate) const SHA512_WITH_RSAENCRYPTION_OID: Oid<'static> = oid!(1.2.840 .113549 .1 .1 .13);
     61 pub(crate) const ED25519_OID: Oid<'static> = oid!(1.3.101 .112);
     62 pub(crate) const SHA256_OID: Oid<'static> = oid!(2.16.840 .1 .101 .3 .4 .2 .1);
     63 pub(crate) const SHA384_OID: Oid<'static> = oid!(2.16.840 .1 .101 .3 .4 .2 .2);
     64 pub(crate) const SHA512_OID: Oid<'static> = oid!(2.16.840 .1 .101 .3 .4 .2 .3);
     65 pub(crate) const SECP521R1_OID: Oid<'static> = oid!(1.3.132 .0 .35);
     66 pub(crate) const SECP384R1_OID: Oid<'static> = oid!(1.3.132 .0 .34);
     67 pub(crate) const PRIME256V1_OID: Oid<'static> = oid!(1.2.840 .10045 .3 .1 .7);
     68 
     69 /********************** Supported Validators ***************************************
     70     RS256	RSASSA-PKCS1-v1_5 using SHA-256 - not recommended
     71     RS384	RSASSA-PKCS1-v1_5 using SHA-384 - not recommended
     72     RS512	RSASSA-PKCS1-v1_5 using SHA-512 - not recommended
     73     PS256	RSASSA-PSS using SHA-256 and MGF1 with SHA-256
     74     PS384	RSASSA-PSS using SHA-384 and MGF1 with SHA-384
     75     PS512	RSASSA-PSS using SHA-512 and MGF1 with SHA-512
     76     ES256	ECDSA using P-256 and SHA-256
     77     ES384	ECDSA using P-384 and SHA-384
     78     ES512	ECDSA using P-521 and SHA-512
     79     ED25519 Edwards Curve 25519
     80 **********************************************************************************/
     81 
     82 fn get_cose_sign1(
     83     cose_bytes: &[u8],
     84     data: &[u8],
     85     validation_log: &mut impl StatusTracker,
     86 ) -> Result<coset::CoseSign1> {
     87     match <coset::CoseSign1 as TaggedCborSerializable>::from_tagged_slice(cose_bytes) {
     88         Ok(mut sign1) => {
     89             sign1.payload = Some(data.to_vec()); // restore payload for verification check
     90 
     91             Ok(sign1)
     92         }
     93         Err(coset_error) => {
     94             let log_item = log_item!(
     95                 "Cose_Sign1",
     96                 "could not deserialize signature",
     97                 "get_cose_sign1"
     98             )
     99             .error(Error::InvalidCoseSignature { coset_error })
    100             .validation_status(validation_status::CLAIM_SIGNATURE_MISMATCH);
    101 
    102             validation_log.log_silent(log_item);
    103 
    104             Err(Error::CoseSignature)
    105         }
    106     }
    107 }
    108 
    109 pub(crate) fn check_cert(
    110     ca_der_bytes: &[u8],
    111     th: &dyn TrustHandlerConfig,
    112     validation_log: &mut impl StatusTracker,
    113     _tst_info_opt: Option<&TstInfo>,
    114 ) -> Result<()> {
    115     // get the cert in der format
    116     let (_rem, signcert) = X509Certificate::from_der(ca_der_bytes).map_err(|_err| {
    117         let log_item = log_item!(
    118             "Cose_Sign1",
    119             "certificate could not be parsed",
    120             "check_cert_alg"
    121         )
    122         .error(Error::CoseInvalidCert)
    123         .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    124         validation_log.log_silent(log_item);
    125         Error::CoseInvalidCert
    126     })?;
    127 
    128     // cert version must be 3
    129     if signcert.version() != X509Version::V3 {
    130         let log_item = log_item!(
    131             "Cose_Sign1",
    132             "certificate version incorrect",
    133             "check_cert_alg"
    134         )
    135         .error(Error::CoseInvalidCert)
    136         .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    137         validation_log.log_silent(log_item);
    138 
    139         return Err(Error::CoseInvalidCert);
    140     }
    141 
    142     // check for cert expiration
    143     if let Some(tst_info) = _tst_info_opt {
    144         // was there a time stamp association with this signature, is verify against that time
    145         let signing_time = gt_to_datetime(tst_info.gen_time.clone());
    146         if !signcert.validity().is_valid_at(
    147             x509_parser::time::ASN1Time::from_timestamp(signing_time.timestamp())
    148                 .map_err(|_| Error::CoseInvalidCert)?,
    149         ) {
    150             let log_item = log_item!("Cose_Sign1", "certificate expired", "check_cert_alg")
    151                 .error(Error::CoseCertExpiration)
    152                 .validation_status(validation_status::SIGNING_CREDENTIAL_EXPIRED);
    153             validation_log.log_silent(log_item);
    154 
    155             return Err(Error::CoseCertExpiration);
    156         }
    157     } else {
    158         // no timestamp so check against current time
    159         // use instant to avoid wasm issues
    160         let now_f64 = instant::now() / 1000.0;
    161         let now: i64 = now_f64
    162             .approx_as::<i64>()
    163             .map_err(|_e| Error::BadParam("system time invalid".to_string()))?;
    164 
    165         if !signcert.validity().is_valid_at(
    166             x509_parser::time::ASN1Time::from_timestamp(now).map_err(|_| Error::CoseInvalidCert)?,
    167         ) {
    168             let log_item = log_item!("Cose_Sign1", "certificate expired", "check_cert_alg")
    169                 .error(Error::CoseCertExpiration)
    170                 .validation_status(validation_status::SIGNING_CREDENTIAL_EXPIRED);
    171             validation_log.log_silent(log_item);
    172 
    173             return Err(Error::CoseCertExpiration);
    174         }
    175     }
    176 
    177     let cert_alg = signcert.signature_algorithm.algorithm.clone();
    178 
    179     // check algorithm needed from cert
    180 
    181     // cert must be signed with one the following algorithm
    182     if !(cert_alg == SHA256_WITH_RSAENCRYPTION_OID
    183         || cert_alg == SHA384_WITH_RSAENCRYPTION_OID
    184         || cert_alg == SHA512_WITH_RSAENCRYPTION_OID
    185         || cert_alg == ECDSA_WITH_SHA256_OID
    186         || cert_alg == ECDSA_WITH_SHA384_OID
    187         || cert_alg == ECDSA_WITH_SHA512_OID
    188         || cert_alg == RSASSA_PSS_OID
    189         || cert_alg == ED25519_OID)
    190     {
    191         let log_item = log_item!(
    192             "Cose_Sign1",
    193             "certificate algorithm not supported",
    194             "check_cert_alg"
    195         )
    196         .error(Error::CoseInvalidCert)
    197         .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    198         validation_log.log_silent(log_item);
    199 
    200         return Err(Error::CoseInvalidCert);
    201     }
    202 
    203     // verify rsassa_pss parameters
    204     if cert_alg == RSASSA_PSS_OID {
    205         if let Some(parameters) = &signcert.signature_algorithm.parameters {
    206             let seq = parameters
    207                 .as_sequence()
    208                 .map_err(|_err| Error::CoseInvalidCert)?;
    209 
    210             let (_i, (ha_alg, mgf_ai)) = seq
    211                 .parse(|i| {
    212                     let (i, h) = Header::from_der(i)?;
    213                     if h.class() != Class::ContextSpecific || h.tag() != Tag(0) {
    214                         return Err(nom::Err::Error(asn1_rs::Error::BerValueError));
    215                     }
    216 
    217                     let (i, ha_alg) = AlgorithmIdentifier::from_der(i)
    218                         .map_err(|_| nom::Err::Error(asn1_rs::Error::BerValueError))?;
    219 
    220                     let (i, h) = Header::from_der(i)?;
    221                     if h.class() != Class::ContextSpecific || h.tag() != Tag(1) {
    222                         return Err(nom::Err::Error(asn1_rs::Error::BerValueError));
    223                     }
    224 
    225                     let (i, mgf_ai) = AlgorithmIdentifier::from_der(i)
    226                         .map_err(|_| nom::Err::Error(asn1_rs::Error::BerValueError))?;
    227 
    228                     // Ignore anything that follows these two parameters.
    229 
    230                     Ok((i, (ha_alg, mgf_ai)))
    231                 })
    232                 .map_err(|_| Error::CoseInvalidCert)?;
    233 
    234             let mgf_ai_parameters = mgf_ai.parameters.ok_or(Error::CoseInvalidCert)?;
    235             let mgf_ai_parameters = mgf_ai_parameters
    236                 .as_sequence()
    237                 .map_err(|_| Error::CoseInvalidCert)?;
    238 
    239             let (_i, mgf_ai_params_algorithm) =
    240                 Any::from_der(&mgf_ai_parameters.content).map_err(|_| Error::CoseInvalidCert)?;
    241 
    242             let mgf_ai_params_algorithm = mgf_ai_params_algorithm
    243                 .as_oid()
    244                 .map_err(|_| Error::CoseInvalidCert)?;
    245 
    246             // must be the same
    247             if ha_alg.algorithm != mgf_ai_params_algorithm {
    248                 let log_item = log_item!(
    249                     "Cose_Sign1",
    250                     "certificate algorithm error",
    251                     "check_cert_alg"
    252                 )
    253                 .error(Error::CoseInvalidCert)
    254                 .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    255                 validation_log.log_silent(log_item);
    256 
    257                 return Err(Error::CoseInvalidCert);
    258             }
    259 
    260             // check for one of the mandatory types
    261             if !(ha_alg.algorithm == SHA256_OID
    262                 || ha_alg.algorithm == SHA384_OID
    263                 || ha_alg.algorithm == SHA512_OID)
    264             {
    265                 let log_item = log_item!(
    266                     "Cose_Sign1",
    267                     "certificate hash algorithm not supported",
    268                     "check_cert_alg"
    269                 )
    270                 .error(Error::CoseInvalidCert)
    271                 .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    272                 validation_log.log_silent(log_item);
    273 
    274                 return Err(Error::CoseInvalidCert);
    275             }
    276         } else {
    277             let log_item = log_item!(
    278                 "Cose_Sign1",
    279                 "certificate missing algorithm parameters",
    280                 "check_cert_alg"
    281             )
    282             .error(Error::CoseInvalidCert)
    283             .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    284             validation_log.log_silent(log_item);
    285 
    286             return Err(Error::CoseInvalidCert);
    287         }
    288     }
    289 
    290     // check curves for SPKI EC algorithms
    291     let pk = signcert.public_key();
    292     let skpi_alg = &pk.algorithm;
    293 
    294     if skpi_alg.algorithm == EC_PUBLICKEY_OID {
    295         if let Some(parameters) = &skpi_alg.parameters {
    296             let named_curve_oid = parameters.as_oid().map_err(|_err| Error::CoseInvalidCert)?;
    297 
    298             // must be one of these named curves
    299             if !(named_curve_oid == PRIME256V1_OID
    300                 || named_curve_oid == SECP384R1_OID
    301                 || named_curve_oid == SECP521R1_OID)
    302             {
    303                 let log_item = log_item!(
    304                     "Cose_Sign1",
    305                     "certificate unsupported EC curve",
    306                     "check_cert_alg"
    307                 )
    308                 .error(Error::CoseInvalidCert)
    309                 .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    310                 validation_log.log_silent(log_item);
    311 
    312                 return Err(Error::CoseInvalidCert);
    313             }
    314         } else {
    315             return Err(Error::CoseInvalidCert);
    316         }
    317     }
    318 
    319     // check modulus minimum length (for RSA & PSS algorithms)
    320     if skpi_alg.algorithm == RSA_OID || skpi_alg.algorithm == RSASSA_PSS_OID {
    321         let (_, skpi_ber) = parse_ber_sequence(&pk.subject_public_key.data)
    322             .map_err(|_err| Error::CoseInvalidCert)?;
    323 
    324         let seq = skpi_ber
    325             .as_sequence()
    326             .map_err(|_err| Error::CoseInvalidCert)?;
    327         if seq.len() < 2 {
    328             return Err(Error::CoseInvalidCert);
    329         }
    330 
    331         let modulus = seq[0].as_bigint().map_err(|_| Error::CoseInvalidCert)?;
    332 
    333         if modulus.bits() < 2048 {
    334             let log_item = log_item!(
    335                 "Cose_Sign1",
    336                 "certificate key length too short",
    337                 "check_cert_alg"
    338             )
    339             .error(Error::CoseInvalidCert)
    340             .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    341             validation_log.log_silent(log_item);
    342 
    343             return Err(Error::CoseInvalidCert);
    344         }
    345     }
    346 
    347     // check cert values
    348     let tbscert = &signcert.tbs_certificate;
    349 
    350     let is_self_signed = tbscert.is_ca() && tbscert.issuer_uid == tbscert.subject_uid;
    351 
    352     // self signed certs are disallowed
    353     if is_self_signed {
    354         let log_item = log_item!(
    355             "Cose_Sign1",
    356             "certificate issuer and subject cannot be the same {self-signed disallowed}",
    357             "check_cert_alg"
    358         )
    359         .error(Error::CoseInvalidCert)
    360         .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    361         validation_log.log_silent(log_item);
    362 
    363         return Err(Error::CoseInvalidCert);
    364     }
    365 
    366     // unique ids are not allowed
    367     if signcert.issuer_uid.is_some() || signcert.subject_uid.is_some() {
    368         let log_item = log_item!(
    369             "Cose_Sign1",
    370             "certificate issuer/subject unique ids are not allowed",
    371             "check_cert_alg"
    372         )
    373         .error(Error::CoseInvalidCert)
    374         .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    375         validation_log.log_silent(log_item);
    376 
    377         return Err(Error::CoseInvalidCert);
    378     }
    379 
    380     let mut aki_good = false;
    381     let mut ski_good = false;
    382     let mut key_usage_good = false;
    383     let mut handled_all_critical = true;
    384     let extended_key_usage_good = match tbscert
    385         .extended_key_usage()
    386         .map_err(|_| Error::CoseInvalidCert)?
    387     {
    388         Some(BasicExtension { value: eku, .. }) => {
    389             if eku.any {
    390                 let log_item = log_item!(
    391                     "Cose_Sign1",
    392                     "certificate 'any' EKU not allowed",
    393                     "check_cert_alg"
    394                 )
    395                 .error(Error::CoseInvalidCert)
    396                 .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    397                 validation_log.log_silent(log_item);
    398 
    399                 return Err(Error::CoseInvalidCert);
    400             }
    401 
    402             if has_allowed_oid(eku, &th.get_auxillary_ekus()).is_none() {
    403                 let log_item = log_item!(
    404                     "Cose_Sign1",
    405                     "certificate missing required EKU",
    406                     "check_cert_alg"
    407                 )
    408                 .error(Error::CoseInvalidCert)
    409                 .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    410                 validation_log.log_silent(log_item);
    411 
    412                 return Err(Error::CoseInvalidCert);
    413             }
    414 
    415             // one or the other || either of these two, and no others field
    416             if (eku.ocsp_signing && eku.time_stamping)
    417                 || ((eku.ocsp_signing ^ eku.time_stamping)
    418                     && (eku.client_auth
    419                         | eku.code_signing
    420                         | eku.email_protection
    421                         | eku.server_auth
    422                         | !eku.other.is_empty()))
    423             {
    424                 let log_item = log_item!(
    425                     "Cose_Sign1",
    426                     "certificate invalid set of EKUs",
    427                     "check_cert_alg"
    428                 )
    429                 .error(Error::CoseInvalidCert)
    430                 .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    431                 validation_log.log_silent(log_item);
    432 
    433                 return Err(Error::CoseInvalidCert);
    434             }
    435 
    436             true
    437         }
    438         None => tbscert.is_ca(), // if is not ca it must be present
    439     };
    440 
    441     // populate needed extension info
    442     for e in signcert.extensions() {
    443         match e.parsed_extension() {
    444             ParsedExtension::AuthorityKeyIdentifier(_aki) => {
    445                 aki_good = true;
    446             }
    447             ParsedExtension::SubjectKeyIdentifier(_spki) => {
    448                 ski_good = true;
    449             }
    450             ParsedExtension::KeyUsage(ku) => {
    451                 if ku.digital_signature() {
    452                     if ku.key_cert_sign() && !tbscert.is_ca() {
    453                         let log_item = log_item!(
    454                             "Cose_Sign1",
    455                             "certificate missing digitalSignature EKU",
    456                             "check_cert_alg"
    457                         )
    458                         .error(Error::CoseInvalidCert)
    459                         .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    460                         validation_log.log_silent(log_item);
    461 
    462                         return Err(Error::CoseInvalidCert);
    463                     }
    464                     key_usage_good = true;
    465                 }
    466                 if ku.key_cert_sign() || ku.non_repudiation() {
    467                     key_usage_good = true;
    468                 }
    469                 // todo: warn if not marked critical
    470                 // if !e.critical { // warn here somehow}
    471             }
    472             ParsedExtension::CertificatePolicies(_) => (),
    473             ParsedExtension::PolicyMappings(_) => (),
    474             ParsedExtension::SubjectAlternativeName(_) => (),
    475             ParsedExtension::BasicConstraints(_) => (),
    476             ParsedExtension::NameConstraints(_) => (),
    477             ParsedExtension::PolicyConstraints(_) => (),
    478             ParsedExtension::ExtendedKeyUsage(_) => (),
    479             ParsedExtension::CRLDistributionPoints(_) => (),
    480             ParsedExtension::InhibitAnyPolicy(_) => (),
    481             ParsedExtension::AuthorityInfoAccess(_) => (),
    482             ParsedExtension::NSCertType(_) => (),
    483             ParsedExtension::CRLNumber(_) => (),
    484             ParsedExtension::ReasonCode(_) => (),
    485             ParsedExtension::InvalidityDate(_) => (),
    486             ParsedExtension::Unparsed => {
    487                 if e.critical {
    488                     // unhandled critical extension
    489                     handled_all_critical = false;
    490                 }
    491             }
    492             _ => {
    493                 if e.critical {
    494                     // unhandled critical extension
    495                     handled_all_critical = false;
    496                 }
    497             }
    498         }
    499     }
    500 
    501     // if cert is a CA must have valid SubjectKeyIdentifier
    502     ski_good = if tbscert.is_ca() { ski_good } else { true };
    503 
    504     // check all flags
    505     if aki_good && ski_good && key_usage_good && extended_key_usage_good && handled_all_critical {
    506         Ok(())
    507     } else {
    508         let log_item = log_item!(
    509             "Cose_Sign1",
    510             "certificate params incorrect",
    511             "check_cert_alg"
    512         )
    513         .error(Error::CoseInvalidCert)
    514         .validation_status(validation_status::SIGNING_CREDENTIAL_INVALID);
    515         validation_log.log_silent(log_item);
    516 
    517         Err(Error::CoseInvalidCert)
    518     }
    519 }
    520 
    521 pub(crate) fn get_signing_alg(cs1: &coset::CoseSign1) -> Result<SigningAlg> {
    522     // find the supported handler for the algorithm
    523     match cs1.protected.header.alg {
    524         Some(ref alg) => match alg {
    525             coset::RegisteredLabelWithPrivate::PrivateUse(a) => match a {
    526                 -39 => Ok(SigningAlg::Ps512),
    527                 -38 => Ok(SigningAlg::Ps384),
    528                 -37 => Ok(SigningAlg::Ps256),
    529                 -36 => Ok(SigningAlg::Es512),
    530                 -35 => Ok(SigningAlg::Es384),
    531                 -7 => Ok(SigningAlg::Es256),
    532                 -8 => Ok(SigningAlg::Ed25519),
    533                 _ => Err(Error::CoseSignatureAlgorithmNotSupported),
    534             },
    535             coset::RegisteredLabelWithPrivate::Assigned(a) => match a {
    536                 coset::iana::Algorithm::PS512 => Ok(SigningAlg::Ps512),
    537                 coset::iana::Algorithm::PS384 => Ok(SigningAlg::Ps384),
    538                 coset::iana::Algorithm::PS256 => Ok(SigningAlg::Ps256),
    539                 coset::iana::Algorithm::ES512 => Ok(SigningAlg::Es512),
    540                 coset::iana::Algorithm::ES384 => Ok(SigningAlg::Es384),
    541                 coset::iana::Algorithm::ES256 => Ok(SigningAlg::Es256),
    542                 coset::iana::Algorithm::EdDSA => Ok(SigningAlg::Ed25519),
    543                 _ => Err(Error::CoseSignatureAlgorithmNotSupported),
    544             },
    545             coset::RegisteredLabelWithPrivate::Text(a) => a
    546                 .parse()
    547                 .map_err(|_| Error::CoseSignatureAlgorithmNotSupported),
    548         },
    549         None => Err(Error::CoseSignatureAlgorithmNotSupported),
    550     }
    551 }
    552 
    553 fn get_sign_cert(sign1: &coset::CoseSign1) -> Result<Vec<u8>> {
    554     // element 0 is the signing cert
    555     let certs = get_sign_certs(sign1)?;
    556     Ok(certs[0].clone())
    557 }
    558 
    559 fn get_unprotected_header_certs(sign1: &coset::CoseSign1) -> Result<Vec<Vec<u8>>> {
    560     if let Some(der) = sign1
    561         .unprotected
    562         .rest
    563         .iter()
    564         .find_map(|x: &(Label, Value)| {
    565             if x.0 == Label::Text("x5chain".to_string()) {
    566                 Some(x.1.clone())
    567             } else {
    568                 None
    569             }
    570         })
    571     {
    572         let mut certs: Vec<Vec<u8>> = Vec::new();
    573 
    574         match der {
    575             Value::Array(cert_chain) => {
    576                 // handle array of certs
    577                 for c in cert_chain {
    578                     if let Value::Bytes(der_bytes) = c {
    579                         certs.push(der_bytes.clone());
    580                     }
    581                 }
    582 
    583                 if certs.is_empty() {
    584                     Err(Error::CoseMissingKey)
    585                 } else {
    586                     Ok(certs)
    587                 }
    588             }
    589             Value::Bytes(ref der_bytes) => {
    590                 // handle single cert case
    591                 certs.push(der_bytes.clone());
    592                 Ok(certs)
    593             }
    594             _ => Err(Error::CoseX5ChainMissing),
    595         }
    596     } else {
    597         Err(Error::CoseX5ChainMissing)
    598     }
    599 }
    600 // get the public key der
    601 fn get_sign_certs(sign1: &coset::CoseSign1) -> Result<Vec<Vec<u8>>> {
    602     // check for protected header int, then protected header x5chain,
    603     // then the legacy unprotected x5chain to get the public key der
    604 
    605     // check the protected header
    606     if let Some(der) = sign1
    607         .protected
    608         .header
    609         .rest
    610         .iter()
    611         .find_map(|x: &(Label, Value)| {
    612             if x.0 == Label::Text("x5chain".to_string())
    613                 || x.0 == Label::Int(iana::HeaderParameter::X5Chain.to_i64())
    614             {
    615                 Some(x.1.clone())
    616             } else {
    617                 None
    618             }
    619         })
    620     {
    621         // make sure there are no certs in the legacy unprotected header, certs
    622         // are only allowing in protect OR unprotected header
    623         if get_unprotected_header_certs(sign1).is_ok() {
    624             return Err(Error::CoseVerifier);
    625         }
    626 
    627         let mut certs: Vec<Vec<u8>> = Vec::new();
    628 
    629         match der {
    630             Value::Array(cert_chain) => {
    631                 // handle array of certs
    632                 for c in cert_chain {
    633                     if let Value::Bytes(der_bytes) = c {
    634                         certs.push(der_bytes.clone());
    635                     }
    636                 }
    637 
    638                 if certs.is_empty() {
    639                     return Err(Error::CoseX5ChainMissing);
    640                 } else {
    641                     return Ok(certs);
    642                 }
    643             }
    644             Value::Bytes(ref der_bytes) => {
    645                 // handle single cert case
    646                 certs.push(der_bytes.clone());
    647                 return Ok(certs);
    648             }
    649             _ => return Err(Error::CoseX5ChainMissing),
    650         }
    651     }
    652 
    653     // check the unprotected header if necessary
    654     get_unprotected_header_certs(sign1)
    655 }
    656 
    657 // get OCSP der
    658 fn get_ocsp_der(sign1: &coset::CoseSign1) -> Option<Vec<u8>> {
    659     if let Some(der) = sign1
    660         .unprotected
    661         .rest
    662         .iter()
    663         .find_map(|x: &(Label, Value)| {
    664             if x.0 == Label::Text("rVals".to_string()) {
    665                 Some(x.1.clone())
    666             } else {
    667                 None
    668             }
    669         })
    670     {
    671         match der {
    672             Value::Map(rvals_map) => {
    673                 // find OCSP value if available
    674                 rvals_map.iter().find_map(|x: &(Value, Value)| {
    675                     if x.0 == Value::Text("ocspVals".to_string()) {
    676                         x.1.as_array()
    677                             .and_then(|ocsp_rsp_val| ocsp_rsp_val.first())
    678                             .and_then(Value::as_bytes)
    679                             .cloned()
    680                     } else {
    681                         None
    682                     }
    683                 })
    684             }
    685             _ => None,
    686         }
    687     } else {
    688         None
    689     }
    690 }
    691 
    692 pub(crate) fn check_ocsp_status(
    693     cose_bytes: &[u8],
    694     data: &[u8],
    695     th: &dyn TrustHandlerConfig,
    696     validation_log: &mut impl StatusTracker,
    697 ) -> Result<OcspData> {
    698     let sign1 = get_cose_sign1(cose_bytes, data, validation_log)?;
    699 
    700     let time_stamp_info = get_timestamp_info(&sign1, data);
    701 
    702     let mut result = Ok(OcspData::default());
    703 
    704     if let Some(ocsp_response_der) = get_ocsp_der(&sign1) {
    705         // check stapled OCSP response, must have timestamp
    706         if let Ok(tst_info) = &time_stamp_info {
    707             let signing_time = gt_to_datetime(tst_info.gen_time.clone());
    708 
    709             // Check the OCSP response, only use if not malformed.  Revocation errors are reported in the validation log
    710             if let Ok(ocsp_data) =
    711                 check_ocsp_response(&ocsp_response_der, Some(signing_time), validation_log)
    712             {
    713                 // if we get a valid response validate the certs
    714                 if ocsp_data.revoked_at.is_none() {
    715                     if let Some(ocsp_certs) = &ocsp_data.ocsp_certs {
    716                         check_cert(&ocsp_certs[0], th, validation_log, Some(tst_info))?;
    717                     }
    718                 }
    719                 result = Ok(ocsp_data);
    720             }
    721         }
    722     } else {
    723         #[cfg(not(target_arch = "wasm32"))]
    724         {
    725             // only support fetching with the enabled
    726             if let Ok(ocsp_fetch) = get_settings_value::<bool>("verify.ocsp_fetch") {
    727                 if ocsp_fetch {
    728                     // get the cert chain
    729                     let certs = get_sign_certs(&sign1)?;
    730 
    731                     if let Some(ocsp_der) = crate::ocsp_utils::fetch_ocsp_response(&certs) {
    732                         // fetch_ocsp_response(&certs) {
    733                         let ocsp_response_der = ocsp_der;
    734 
    735                         let signing_time = match &time_stamp_info {
    736                             Ok(tst_info) => {
    737                                 let signing_time = gt_to_datetime(tst_info.gen_time.clone());
    738                                 Some(signing_time)
    739                             }
    740                             Err(_) => None,
    741                         };
    742 
    743                         // Check the OCSP response, only use if not malformed.  Revocation errors are reported in the validation log
    744                         if let Ok(ocsp_data) =
    745                             check_ocsp_response(&ocsp_response_der, signing_time, validation_log)
    746                         {
    747                             // if we get a valid response validate the certs
    748                             if ocsp_data.revoked_at.is_none() {
    749                                 if let Some(ocsp_certs) = &ocsp_data.ocsp_certs {
    750                                     check_cert(&ocsp_certs[0], th, validation_log, None)?;
    751                                 }
    752                             }
    753                             result = Ok(ocsp_data);
    754                         }
    755                     }
    756                 }
    757             }
    758         }
    759     }
    760 
    761     result
    762 }
    763 
    764 // internal util function to dump the cert chain in PEM format
    765 fn dump_cert_chain(certs: &[Vec<u8>]) -> Result<Vec<u8>> {
    766     let mut out_buf: Vec<u8> = Vec::new();
    767     let mut writer = Cursor::new(out_buf);
    768 
    769     for der_bytes in certs {
    770         let c = x509_certificate::X509Certificate::from_der(der_bytes)
    771             .map_err(|_e| Error::UnsupportedType)?;
    772         c.write_pem(&mut writer)?;
    773     }
    774     out_buf = writer.into_inner();
    775     Ok(out_buf)
    776 }
    777 
    778 // Note: this function is only used to get the display string and not for cert validation.
    779 fn get_signing_time(
    780     sign1: &coset::CoseSign1,
    781     data: &[u8],
    782 ) -> Option<chrono::DateTime<chrono::Utc>> {
    783     // get timestamp info if available
    784 
    785     if let Ok(tst_info) = get_timestamp_info(sign1, data) {
    786         Some(gt_to_datetime(tst_info.gen_time))
    787     } else {
    788         None
    789     }
    790 }
    791 
    792 // return appropriate TstInfo if available
    793 fn get_timestamp_info(sign1: &coset::CoseSign1, data: &[u8]) -> Result<TstInfo> {
    794     // parse the temp timestamp
    795     if let Some(t) = &sign1
    796         .unprotected
    797         .rest
    798         .iter()
    799         .find_map(|x: &(Label, Value)| {
    800             if x.0 == Label::Text("sigTst".to_string()) {
    801                 Some(x.1.clone())
    802             } else {
    803                 None
    804             }
    805         })
    806     {
    807         let time_cbor = serde_cbor::to_vec(t)?;
    808         let tst_infos =
    809             crate::time_stamp::cose_sigtst_to_tstinfos(&time_cbor, data, &sign1.protected)?;
    810 
    811         // there should only be one but consider handling more in the future since it is technically ok
    812         if !tst_infos.is_empty() {
    813             return Ok(tst_infos[0].clone());
    814         }
    815     }
    816     Err(Error::NotFound)
    817 }
    818 
    819 #[async_generic(async_signature( th: &dyn TrustHandlerConfig, chain_der: &[Vec<u8>], cert_der: &[u8], validation_log: &mut impl StatusTracker))]
    820 #[allow(unused)]
    821 fn check_trust(
    822     th: &dyn TrustHandlerConfig,
    823     chain_der: &[Vec<u8>],
    824     cert_der: &[u8],
    825     validation_log: &mut impl StatusTracker,
    826 ) -> Result<()> {
    827     // just return is trust checks are disabled or misconfigured
    828     match get_settings_value::<bool>("verify.verify_trust") {
    829         Ok(verify_trust) => {
    830             if !verify_trust {
    831                 return Ok(());
    832             }
    833         }
    834         Err(e) => return Err(e),
    835     }
    836 
    837     // is the certificate trusted
    838 
    839     let verify_result: Result<bool> = if _sync {
    840         #[cfg(not(feature = "openssl"))]
    841         {
    842             Err(Error::NotImplemented(
    843                 "no trust handler for this feature".to_string(),
    844             ))
    845         }
    846 
    847         #[cfg(feature = "openssl")]
    848         {
    849             verify_trust(th, chain_der, cert_der)
    850         }
    851     } else {
    852         #[cfg(target_arch = "wasm32")]
    853         {
    854             verify_trust_async(th, chain_der, cert_der).await
    855         }
    856 
    857         #[cfg(feature = "openssl")]
    858         {
    859             verify_trust(th, chain_der, cert_der)
    860         }
    861 
    862         #[cfg(all(not(feature = "openssl"), not(target_arch = "wasm32")))]
    863         {
    864             Err(Error::NotImplemented(
    865                 "no trust handler for this feature".to_string(),
    866             ))
    867         }
    868     };
    869 
    870     match verify_result {
    871         Ok(trusted) => {
    872             if trusted {
    873                 let log_item =
    874                     log_item!("Cose_Sign1", "signing certificate trusted", "verify_cose")
    875                         .validation_status(validation_status::SIGNING_CREDENTIAL_TRUSTED);
    876                 validation_log.log_silent(log_item);
    877                 Ok(())
    878             } else {
    879                 let log_item =
    880                     log_item!("Cose_Sign1", "signing certificate untrusted", "verify_cose")
    881                         .error(Error::CoseCertUntrusted)
    882                         .validation_status(validation_status::SIGNING_CREDENTIAL_UNTRUSTED);
    883                 validation_log.log(log_item, Some(Error::CoseCertUntrusted))?;
    884                 Err(Error::CoseCertUntrusted)
    885             }
    886         }
    887         Err(e) => {
    888             let log_item = log_item!("Cose_Sign1", "signing certificate untrusted", "verify_cose")
    889                 .error(Error::CoseCertUntrusted)
    890                 .validation_status(validation_status::SIGNING_CREDENTIAL_UNTRUSTED)
    891                 .set_error(&e);
    892 
    893             validation_log.log(log_item, Some(Error::CoseCertUntrusted))?;
    894             Err(e)
    895         }
    896     }
    897 }
    898 
    899 /// A wrapper containing information of the signing cert.
    900 pub(crate) struct CertInfo {
    901     /// The name of the identity the certificate is issued to.
    902     pub subject: String,
    903     /// The serial number of the cert. Will be unique to the CA.
    904     pub serial_number: BigUint,
    905 }
    906 
    907 fn extract_subject_from_cert(cert: &X509Certificate) -> Result<String> {
    908     cert.subject()
    909         .iter_organization()
    910         .map(|attr| attr.as_str())
    911         .last()
    912         .ok_or(Error::CoseX5ChainMissing)?
    913         .map(|attr| attr.to_string())
    914         .map_err(|_e| Error::CoseX5ChainMissing)
    915 }
    916 
    917 /// Returns the unique serial number from the provided cert.
    918 fn extract_serial_from_cert(cert: &X509Certificate) -> BigUint {
    919     cert.serial.clone()
    920 }
    921 
    922 /// Asynchronously validate a COSE_SIGN1 byte vector and verify against expected data
    923 /// cose_bytes - byte array containing the raw COSE_SIGN1 data
    924 /// data:  data that was used to create the cose_bytes, these must match
    925 /// addition_data: additional optional data that may have been used during signing
    926 /// returns - Ok on success
    927 pub(crate) async fn verify_cose_async(
    928     cose_bytes: Vec<u8>,
    929     data: Vec<u8>,
    930     additional_data: Vec<u8>,
    931     signature_only: bool,
    932     th: &dyn TrustHandlerConfig,
    933     validation_log: &mut impl StatusTracker,
    934 ) -> Result<ValidationInfo> {
    935     let mut sign1 = get_cose_sign1(&cose_bytes, &data, validation_log)?;
    936 
    937     let alg = match get_signing_alg(&sign1) {
    938         Ok(a) => a,
    939         Err(_) => {
    940             let log_item = log_item!(
    941                 "Cose_Sign1",
    942                 "unsupported or missing Cose algorithm",
    943                 "verify_cose_async"
    944             )
    945             .error(Error::CoseSignatureAlgorithmNotSupported)
    946             .validation_status(validation_status::ALGORITHM_UNSUPPORTED);
    947             validation_log.log(log_item, Some(Error::CoseSignatureAlgorithmNotSupported))?;
    948 
    949             // one of these must exist
    950             return Err(Error::CoseSignatureAlgorithmNotSupported);
    951         }
    952     };
    953 
    954     // build result structure
    955     let mut result = ValidationInfo::default();
    956 
    957     // get the cert chain
    958     let certs = get_sign_certs(&sign1)?;
    959 
    960     // get the public key der
    961     let der_bytes = &certs[0];
    962 
    963     // verify cert matches requested algorithm
    964     if !signature_only {
    965         // verify certs
    966         match get_timestamp_info(&sign1, &data) {
    967             Ok(tst_info) => check_cert(der_bytes, th, validation_log, Some(&tst_info))?,
    968             Err(e) => {
    969                 // log timestamp errors
    970                 match e {
    971                     Error::NotFound => check_cert(der_bytes, th, validation_log, None)?,
    972                     Error::CoseTimeStampMismatch => {
    973                         let log_item = log_item!(
    974                             "Cose_Sign1",
    975                             "timestamp message imprint did not match",
    976                             "verify_cose"
    977                         )
    978                         .error(Error::CoseTimeStampMismatch)
    979                         .validation_status(validation_status::TIMESTAMP_MISMATCH);
    980                         validation_log.log(log_item, Some(Error::CoseTimeStampMismatch))?;
    981                     }
    982                     Error::CoseTimeStampValidity => {
    983                         let log_item =
    984                             log_item!("Cose_Sign1", "timestamp outside of validity", "verify_cose")
    985                                 .error(Error::CoseTimeStampValidity)
    986                                 .validation_status(validation_status::TIMESTAMP_OUTSIDE_VALIDITY);
    987                         validation_log.log(log_item, Some(Error::CoseTimeStampValidity))?;
    988                     }
    989                     _ => {
    990                         let log_item =
    991                             log_item!("Cose_Sign1", "error parsing timestamp", "verify_cose")
    992                                 .error(Error::CoseInvalidTimeStamp);
    993                         validation_log.log(log_item, Some(Error::CoseInvalidTimeStamp))?;
    994 
    995                         return Err(Error::CoseInvalidTimeStamp);
    996                     }
    997                 }
    998             }
    999         }
   1000 
   1001         // is the certificate trusted
   1002         #[cfg(target_arch = "wasm32")]
   1003         check_trust_async(th, &certs[1..], der_bytes, validation_log).await?;
   1004 
   1005         #[cfg(not(target_arch = "wasm32"))]
   1006         check_trust(th, &certs[1..], der_bytes, validation_log)?;
   1007 
   1008         // check certificate revocation
   1009         check_ocsp_status(&cose_bytes, &data, th, validation_log)?;
   1010 
   1011         // todo: check TSA certs against trust list
   1012     }
   1013 
   1014     // Check the signature, which needs to have the same `additional_data` provided, by
   1015     // providing a closure that can do the verify operation.
   1016     sign1.payload = Some(data.clone()); // restore payload
   1017 
   1018     let p_header = sign1.protected.clone();
   1019 
   1020     let tbs = sig_structure_data(
   1021         coset::SignatureContext::CoseSign1,
   1022         p_header,
   1023         None,
   1024         &additional_data,
   1025         sign1.payload.as_ref().unwrap_or(&vec![]),
   1026     ); // get "to be signed" bytes
   1027 
   1028     if let Ok(CertInfo {
   1029         subject,
   1030         serial_number,
   1031     }) = validate_with_cert_async(alg, &sign1.signature, &tbs, der_bytes).await
   1032     {
   1033         result.issuer_org = Some(subject);
   1034         result.cert_serial_number = Some(serial_number);
   1035         result.validated = true;
   1036         result.alg = Some(alg);
   1037 
   1038         // parse the temp time for now util we have TA
   1039         result.date = get_signing_time(&sign1, &data);
   1040 
   1041         // return cert chain
   1042         result.cert_chain = dump_cert_chain(&get_sign_certs(&sign1)?)?;
   1043     }
   1044 
   1045     Ok(result)
   1046 }
   1047 
   1048 #[allow(unused_variables)]
   1049 pub(crate) fn get_signing_info(
   1050     cose_bytes: &[u8],
   1051     data: &[u8],
   1052     validation_log: &mut impl StatusTracker,
   1053 ) -> ValidationInfo {
   1054     let mut date = None;
   1055     let mut issuer_org = None;
   1056     let mut alg: Option<SigningAlg> = None;
   1057     let mut cert_serial_number = None;
   1058 
   1059     let sign1 = get_cose_sign1(cose_bytes, data, validation_log).and_then(|sign1| {
   1060         // get the public key der
   1061         let der_bytes = get_sign_cert(&sign1)?;
   1062 
   1063         let _ = X509Certificate::from_der(&der_bytes).map(|(_rem, signcert)| {
   1064             date = get_signing_time(&sign1, data);
   1065             issuer_org = extract_subject_from_cert(&signcert).ok();
   1066             cert_serial_number = Some(extract_serial_from_cert(&signcert));
   1067             if let Ok(a) = get_signing_alg(&sign1) {
   1068                 alg = Some(a);
   1069             }
   1070 
   1071             (_rem, signcert)
   1072         });
   1073 
   1074         Ok(sign1)
   1075     });
   1076 
   1077     let certs = match sign1 {
   1078         Ok(s) => match get_sign_certs(&s) {
   1079             Ok(c) => dump_cert_chain(&c).unwrap_or_default(),
   1080             Err(_) => Vec::new(),
   1081         },
   1082         Err(_e) => Vec::new(),
   1083     };
   1084 
   1085     ValidationInfo {
   1086         issuer_org,
   1087         date,
   1088         alg,
   1089         validated: false,
   1090         cert_chain: certs,
   1091         cert_serial_number,
   1092         revocation_status: None,
   1093     }
   1094 }
   1095 
   1096 /// Validate a COSE_SIGN1 byte vector and verify against expected data
   1097 /// cose_bytes - byte array containing the raw COSE_SIGN1 data
   1098 /// data:  data that was used to create the cose_bytes, these must match
   1099 /// addition_data: additional optional data that may have been used during signing
   1100 /// returns - Ok on success
   1101 #[cfg(not(target_arch = "wasm32"))]
   1102 pub(crate) fn verify_cose(
   1103     cose_bytes: &[u8],
   1104     data: &[u8],
   1105     additional_data: &[u8],
   1106     signature_only: bool,
   1107     th: &dyn TrustHandlerConfig,
   1108     validation_log: &mut impl StatusTracker,
   1109 ) -> Result<ValidationInfo> {
   1110     let sign1 = get_cose_sign1(cose_bytes, data, validation_log)?;
   1111 
   1112     let alg = match get_signing_alg(&sign1) {
   1113         Ok(a) => a,
   1114         Err(_) => {
   1115             let log_item = log_item!(
   1116                 "Cose_Sign1",
   1117                 "unsupported or missing Cose algorithm",
   1118                 "verify_cose"
   1119             )
   1120             .error(Error::CoseSignatureAlgorithmNotSupported)
   1121             .validation_status(validation_status::ALGORITHM_UNSUPPORTED);
   1122 
   1123             validation_log.log(log_item, Some(Error::CoseSignatureAlgorithmNotSupported))?;
   1124 
   1125             return Err(Error::CoseSignatureAlgorithmNotSupported);
   1126         }
   1127     };
   1128 
   1129     let validator = get_validator(alg);
   1130 
   1131     // build result structure
   1132     let mut result = ValidationInfo::default();
   1133 
   1134     // get the cert chain
   1135     let certs = get_sign_certs(&sign1)?;
   1136 
   1137     // get the public key der
   1138     let der_bytes = &certs[0];
   1139 
   1140     let time_stamp_info = get_timestamp_info(&sign1, data);
   1141 
   1142     if !signature_only {
   1143         // verify certs
   1144         match &time_stamp_info {
   1145             Ok(tst_info) => check_cert(der_bytes, th, validation_log, Some(tst_info))?,
   1146             Err(e) => {
   1147                 // log timestamp errors
   1148                 match e {
   1149                     Error::NotFound => check_cert(der_bytes, th, validation_log, None)?,
   1150                     Error::CoseTimeStampMismatch => {
   1151                         let log_item = log_item!(
   1152                             "Cose_Sign1",
   1153                             "timestamp message imprint did not match",
   1154                             "verify_cose"
   1155                         )
   1156                         .error(Error::CoseTimeStampMismatch)
   1157                         .validation_status(validation_status::TIMESTAMP_MISMATCH);
   1158                         validation_log.log(log_item, Some(Error::CoseTimeStampMismatch))?;
   1159                     }
   1160                     Error::CoseTimeStampValidity => {
   1161                         let log_item =
   1162                             log_item!("Cose_Sign1", "timestamp outside of validity", "verify_cose")
   1163                                 .error(Error::CoseTimeStampValidity)
   1164                                 .validation_status(validation_status::TIMESTAMP_OUTSIDE_VALIDITY);
   1165                         validation_log.log(log_item, Some(Error::CoseTimeStampValidity))?;
   1166                     }
   1167                     _ => {
   1168                         let log_item =
   1169                             log_item!("Cose_Sign1", "error parsing timestamp", "verify_cose")
   1170                                 .error(Error::CoseInvalidTimeStamp);
   1171                         validation_log.log(log_item, Some(Error::CoseInvalidTimeStamp))?;
   1172                     }
   1173                 }
   1174             }
   1175         }
   1176 
   1177         // is the certificate trusted
   1178         check_trust(th, &certs[1..], der_bytes, validation_log)?;
   1179 
   1180         // check certificate revocation
   1181         check_ocsp_status(cose_bytes, data, th, validation_log)?;
   1182 
   1183         // todo: check TSA certs against trust list
   1184     }
   1185 
   1186     // Check the signature, which needs to have the same `additional_data` provided, by
   1187     // providing a closure that can do the verify operation.
   1188     sign1.verify_signature(additional_data, |sig, verify_data| -> Result<()> {
   1189         if let Ok(CertInfo {
   1190             subject,
   1191             serial_number,
   1192         }) = validate_with_cert(validator, sig, verify_data, der_bytes)
   1193         {
   1194             result.issuer_org = Some(subject);
   1195             result.cert_serial_number = Some(serial_number);
   1196             result.validated = true;
   1197             result.alg = Some(alg);
   1198 
   1199             // parse the temp time for now util we have TA
   1200             result.date = get_signing_time(&sign1, data);
   1201 
   1202             // return cert chain
   1203             result.cert_chain = dump_cert_chain(&certs)?;
   1204 
   1205             result.revocation_status = Some(true);
   1206         }
   1207         // Note: not adding validation_log entry here since caller will supply claim specific info to log
   1208         Ok(())
   1209     })?;
   1210 
   1211     Ok(result)
   1212 }
   1213 
   1214 #[cfg(target_arch = "wasm32")]
   1215 pub(crate) fn verify_cose(
   1216     _cose_bytes: &[u8],
   1217     _data: &[u8],
   1218     _additional_data: &[u8],
   1219     _signature_only: bool,
   1220     _th: &dyn TrustHandlerConfig,
   1221     _validation_log: &mut impl StatusTracker,
   1222 ) -> Result<ValidationInfo> {
   1223     Err(Error::CoseVerifier)
   1224 }
   1225 
   1226 #[cfg(not(target_arch = "wasm32"))]
   1227 fn validate_with_cert(
   1228     validator: Box<dyn CoseValidator>,
   1229     sig: &[u8],
   1230     data: &[u8],
   1231     der_bytes: &[u8],
   1232 ) -> Result<CertInfo> {
   1233     // get the cert in der format
   1234     let (_rem, signcert) =
   1235         X509Certificate::from_der(der_bytes).map_err(|_err| Error::CoseInvalidCert)?;
   1236     let pk = signcert.public_key();
   1237     let pk_der = pk.raw;
   1238 
   1239     if validator.validate(sig, data, pk_der)? {
   1240         Ok(CertInfo {
   1241             subject: extract_subject_from_cert(&signcert).unwrap_or_default(),
   1242             serial_number: extract_serial_from_cert(&signcert),
   1243         })
   1244     } else {
   1245         Err(Error::CoseSignature)
   1246     }
   1247 }
   1248 
   1249 #[cfg(target_arch = "wasm32")]
   1250 async fn validate_with_cert_async(
   1251     signing_alg: SigningAlg,
   1252     sig: &[u8],
   1253     data: &[u8],
   1254     der_bytes: &[u8],
   1255 ) -> Result<CertInfo> {
   1256     let (_rem, signcert) =
   1257         X509Certificate::from_der(der_bytes).map_err(|_err| Error::CoseMissingKey)?;
   1258     let pk = signcert.public_key();
   1259     let pk_der = pk.raw;
   1260 
   1261     if validate_async(signing_alg, sig, data, pk_der).await? {
   1262         Ok(CertInfo {
   1263             subject: extract_subject_from_cert(&signcert).unwrap_or_default(),
   1264             serial_number: extract_serial_from_cert(&signcert),
   1265         })
   1266     } else {
   1267         Err(Error::CoseSignature)
   1268     }
   1269 }
   1270 
   1271 #[cfg(not(target_arch = "wasm32"))]
   1272 async fn validate_with_cert_async(
   1273     signing_alg: SigningAlg,
   1274     sig: &[u8],
   1275     data: &[u8],
   1276     der_bytes: &[u8],
   1277 ) -> Result<CertInfo> {
   1278     // get the cert in der format
   1279     let (_rem, signcert) =
   1280         X509Certificate::from_der(der_bytes).map_err(|_err| Error::CoseInvalidCert)?;
   1281     let pk = signcert.public_key();
   1282     let pk_der = pk.raw;
   1283 
   1284     let validator = get_validator(signing_alg);
   1285 
   1286     if validator.validate(sig, data, pk_der)? {
   1287         Ok(CertInfo {
   1288             subject: extract_subject_from_cert(&signcert).unwrap_or_default(),
   1289             serial_number: extract_serial_from_cert(&signcert),
   1290         })
   1291     } else {
   1292         Err(Error::CoseSignature)
   1293     }
   1294 }
   1295 #[allow(unused_imports)]
   1296 #[allow(clippy::unwrap_used)]
   1297 #[cfg(feature = "openssl_sign")]
   1298 #[cfg(test)]
   1299 pub mod tests {
   1300 
   1301     use sha2::digest::generic_array::sequence::Shorten;
   1302 
   1303     use super::*;
   1304     use crate::{
   1305         openssl::temp_signer, signer::ConfigurableSigner, status_tracker::DetailedStatusTracker,
   1306         Signer, SigningAlg,
   1307     };
   1308 
   1309     #[test]
   1310     #[cfg(feature = "file_io")]
   1311     fn test_expired_cert() {
   1312         let mut validation_log = DetailedStatusTracker::new();
   1313         let th = crate::openssl::OpenSSLTrustHandlerConfig::new();
   1314 
   1315         let mut cert_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
   1316         cert_path.push("tests/fixtures/rsa-pss256_key-expired.pub");
   1317 
   1318         let expired_cert = std::fs::read(&cert_path).unwrap();
   1319 
   1320         if let Ok(signcert) = openssl::x509::X509::from_pem(&expired_cert) {
   1321             let der_bytes = signcert.to_der().unwrap();
   1322             assert!(check_cert(&der_bytes, &th, &mut validation_log, None).is_err());
   1323 
   1324             assert!(!validation_log.get_log().is_empty());
   1325 
   1326             assert_eq!(
   1327                 validation_log.get_log()[0].validation_status,
   1328                 Some(validation_status::SIGNING_CREDENTIAL_EXPIRED.to_string())
   1329             );
   1330         }
   1331     }
   1332 
   1333     #[test]
   1334     fn test_verify_cose_good() {
   1335         let validator = get_validator(SigningAlg::Ps256);
   1336 
   1337         let sig_bytes = include_bytes!("../tests/fixtures/sig_ps256.data");
   1338         let data_bytes = include_bytes!("../tests/fixtures/data_ps256.data");
   1339         let key_bytes = include_bytes!("../tests/fixtures/key_ps256.data");
   1340 
   1341         assert!(validator
   1342             .validate(sig_bytes, data_bytes, key_bytes)
   1343             .unwrap());
   1344     }
   1345 
   1346     #[test]
   1347     fn test_verify_ec_good() {
   1348         // EC signatures
   1349         let mut validator = get_validator(SigningAlg::Es384);
   1350 
   1351         let sig_es384_bytes = include_bytes!("../tests/fixtures/sig_es384.data");
   1352         let data_es384_bytes = include_bytes!("../tests/fixtures/data_es384.data");
   1353         let key_es384_bytes = include_bytes!("../tests/fixtures/key_es384.data");
   1354 
   1355         assert!(validator
   1356             .validate(sig_es384_bytes, data_es384_bytes, key_es384_bytes)
   1357             .unwrap());
   1358 
   1359         validator = get_validator(SigningAlg::Es512);
   1360 
   1361         let sig_es512_bytes = include_bytes!("../tests/fixtures/sig_es512.data");
   1362         let data_es512_bytes = include_bytes!("../tests/fixtures/data_es512.data");
   1363         let key_es512_bytes = include_bytes!("../tests/fixtures/key_es512.data");
   1364 
   1365         assert!(validator
   1366             .validate(sig_es512_bytes, data_es512_bytes, key_es512_bytes)
   1367             .unwrap());
   1368     }
   1369 
   1370     #[test]
   1371     fn test_verify_cose_bad() {
   1372         let validator = get_validator(SigningAlg::Ps256);
   1373 
   1374         let sig_bytes = include_bytes!("../tests/fixtures/sig_ps256.data");
   1375         let data_bytes = include_bytes!("../tests/fixtures/data_ps256.data");
   1376         let key_bytes = include_bytes!("../tests/fixtures/key_ps256.data");
   1377 
   1378         let mut bad_bytes = data_bytes.to_vec();
   1379         bad_bytes[0] = b'c';
   1380         bad_bytes[1] = b'2';
   1381         bad_bytes[2] = b'p';
   1382         bad_bytes[3] = b'a';
   1383 
   1384         assert!(!validator
   1385             .validate(sig_bytes, &bad_bytes, key_bytes)
   1386             .unwrap());
   1387     }
   1388 
   1389     #[test]
   1390     #[cfg(feature = "openssl_sign")]
   1391     fn test_cert_algorithms() {
   1392         let cert_dir = crate::utils::test::fixture_path("certs");
   1393         let th = crate::openssl::OpenSSLTrustHandlerConfig::new();
   1394 
   1395         let mut validation_log = DetailedStatusTracker::new();
   1396 
   1397         let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es256, None);
   1398         let es256_cert = std::fs::read(cert_path).unwrap();
   1399 
   1400         let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es384, None);
   1401         let es384_cert = std::fs::read(cert_path).unwrap();
   1402 
   1403         let (_, cert_path) = temp_signer::get_ec_signer(&cert_dir, SigningAlg::Es512, None);
   1404         let es512_cert = std::fs::read(cert_path).unwrap();
   1405 
   1406         let (_, cert_path) = temp_signer::get_rsa_signer(&cert_dir, SigningAlg::Ps256, None);
   1407         let rsa_pss256_cert = std::fs::read(cert_path).unwrap();
   1408 
   1409         if let Ok(signcert) = openssl::x509::X509::from_pem(&es256_cert) {
   1410             let der_bytes = signcert.to_der().unwrap();
   1411             assert!(check_cert(&der_bytes, &th, &mut validation_log, None).is_ok());
   1412         }
   1413 
   1414         if let Ok(signcert) = openssl::x509::X509::from_pem(&es384_cert) {
   1415             let der_bytes = signcert.to_der().unwrap();
   1416             assert!(check_cert(&der_bytes, &th, &mut validation_log, None).is_ok());
   1417         }
   1418 
   1419         if let Ok(signcert) = openssl::x509::X509::from_pem(&es512_cert) {
   1420             let der_bytes = signcert.to_der().unwrap();
   1421             assert!(check_cert(&der_bytes, &th, &mut validation_log, None).is_ok());
   1422         }
   1423 
   1424         if let Ok(signcert) = openssl::x509::X509::from_pem(&rsa_pss256_cert) {
   1425             let der_bytes = signcert.to_der().unwrap();
   1426             assert!(check_cert(&der_bytes, &th, &mut validation_log, None).is_ok());
   1427         }
   1428     }
   1429 
   1430     #[test]
   1431     fn test_no_timestamp() {
   1432         let mut validation_log = DetailedStatusTracker::new();
   1433 
   1434         let mut claim = crate::claim::Claim::new("extern_sign_test", Some("contentauth"));
   1435         claim.build().unwrap();
   1436 
   1437         let claim_bytes = claim.data().unwrap();
   1438 
   1439         let box_size = 10000;
   1440 
   1441         let signer = crate::utils::test::temp_signer();
   1442 
   1443         let cose_bytes =
   1444             crate::cose_sign::sign_claim(&claim_bytes, signer.as_ref(), box_size).unwrap();
   1445 
   1446         let cose_sign1 = get_cose_sign1(&cose_bytes, &claim_bytes, &mut validation_log).unwrap();
   1447 
   1448         let signing_time = get_signing_time(&cose_sign1, &claim_bytes);
   1449 
   1450         assert_eq!(signing_time, None);
   1451     }
   1452     #[test]
   1453     #[cfg(feature = "openssl_sign")]
   1454     fn test_stapled_ocsp() {
   1455         let mut validation_log = DetailedStatusTracker::new();
   1456 
   1457         let mut claim = crate::claim::Claim::new("ocsp_sign_test", Some("contentauth"));
   1458         claim.build().unwrap();
   1459 
   1460         let claim_bytes = claim.data().unwrap();
   1461 
   1462         let sign_cert = include_bytes!("../tests/fixtures/certs/ps256.pub").to_vec();
   1463         let pem_key = include_bytes!("../tests/fixtures/certs/ps256.pem").to_vec();
   1464         let ocsp_rsp_data = include_bytes!("../tests/fixtures/ocsp_good.data");
   1465 
   1466         let signer = crate::openssl::RsaSigner::from_signcert_and_pkey(
   1467             &sign_cert,
   1468             &pem_key,
   1469             SigningAlg::Ps256,
   1470             None,
   1471         )
   1472         .unwrap();
   1473 
   1474         // create a test signer that supports stapling
   1475         struct OcspSigner {
   1476             pub signer: Box<dyn crate::Signer>,
   1477             pub ocsp_rsp: Vec<u8>,
   1478         }
   1479         impl crate::Signer for OcspSigner {
   1480             fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
   1481                 self.signer.sign(data)
   1482             }
   1483 
   1484             fn alg(&self) -> SigningAlg {
   1485                 SigningAlg::Ps256
   1486             }
   1487 
   1488             fn certs(&self) -> Result<Vec<Vec<u8>>> {
   1489                 self.signer.certs()
   1490             }
   1491 
   1492             fn reserve_size(&self) -> usize {
   1493                 self.signer.reserve_size()
   1494             }
   1495 
   1496             fn ocsp_val(&self) -> Option<Vec<u8>> {
   1497                 Some(self.ocsp_rsp.clone())
   1498             }
   1499         }
   1500 
   1501         let ocsp_signer = OcspSigner {
   1502             signer: Box::new(signer),
   1503             ocsp_rsp: ocsp_rsp_data.to_vec(),
   1504         };
   1505 
   1506         // sign and staple
   1507         let cose_bytes =
   1508             crate::cose_sign::sign_claim(&claim_bytes, &ocsp_signer, ocsp_signer.reserve_size())
   1509                 .unwrap();
   1510 
   1511         let cose_sign1 = get_cose_sign1(&cose_bytes, &claim_bytes, &mut validation_log).unwrap();
   1512         let ocsp_stapled = get_ocsp_der(&cose_sign1).unwrap();
   1513 
   1514         assert_eq!(ocsp_rsp_data, ocsp_stapled.as_slice());
   1515     }
   1516 }