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 }