webpki-0.21.0/Cargo.toml.orig000064400000000000000000000041151351327620100141310ustar0000000000000000# Copyright 2015 Brian Smith. # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. [package] authors = ["Brian Smith "] categories = ["cryptography", "no-std"] description = "Web PKI X.509 Certificate Verification." documentation = "https://briansmith.org/rustdoc/webpki/" edition = "2018" license-file = "LICENSE" name = "webpki" readme = "README.md" repository = "https://github.com/briansmith/webpki" version = "0.21.0" include = [ "Cargo.toml", "LICENSE", "README.md", "src/calendar.rs", "src/cert.rs", "src/der.rs", "src/name.rs", "src/error.rs", "src/signed_data.rs", "src/time.rs", "src/trust_anchor_util.rs", "src/verify_cert.rs", "src/webpki.rs", "src/data/**/*", "tests/dns_name_tests.rs", "tests/integration.rs", "tests/misc/serial_neg.der", "tests/misc/serial_zero.der", "tests/netflix/ca.der", "tests/netflix/ee.der", "tests/netflix/inter.der", "third-party/chromium/**/*", ] [lib] name = "webpki" path = "src/webpki.rs" [features] default = ["std", "trust_anchor_util"] trust_anchor_util = ["std"] std = [] [dependencies] ring = "0.16.0" untrusted = "0.7.0" [dev-dependencies] base64 = "0.9.1" [profile.bench] opt-level = 3 debug = false rpath = false lto = true debug-assertions = false codegen-units = 1 [profile.release] opt-level = 3 debug = false rpath = false lto = true debug-assertions = false codegen-units = 1 webpki-0.21.0/Cargo.toml0000644000000034560000000000000104420ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "webpki" version = "0.21.0" authors = ["Brian Smith "] include = ["Cargo.toml", "LICENSE", "README.md", "src/calendar.rs", "src/cert.rs", "src/der.rs", "src/name.rs", "src/error.rs", "src/signed_data.rs", "src/time.rs", "src/trust_anchor_util.rs", "src/verify_cert.rs", "src/webpki.rs", "src/data/**/*", "tests/dns_name_tests.rs", "tests/integration.rs", "tests/misc/serial_neg.der", "tests/misc/serial_zero.der", "tests/netflix/ca.der", "tests/netflix/ee.der", "tests/netflix/inter.der", "third-party/chromium/**/*"] description = "Web PKI X.509 Certificate Verification." documentation = "https://briansmith.org/rustdoc/webpki/" readme = "README.md" categories = ["cryptography", "no-std"] license-file = "LICENSE" repository = "https://github.com/briansmith/webpki" [profile.bench] opt-level = 3 lto = true codegen-units = 1 debug = false debug-assertions = false rpath = false [profile.release] opt-level = 3 lto = true codegen-units = 1 debug = false debug-assertions = false rpath = false [lib] name = "webpki" path = "src/webpki.rs" [dependencies.ring] version = "0.16.0" [dependencies.untrusted] version = "0.7.0" [dev-dependencies.base64] version = "0.9.1" [features] default = ["std", "trust_anchor_util"] std = [] trust_anchor_util = ["std"] webpki-0.21.0/LICENSE000064400000000000000000000016241263164014500122530ustar0000000000000000Except as otherwise noted, this project is licensed under the following (ISC-style) terms: Copyright 2015 Brian Smith. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The files under third-party/chromium are licensed as described in third-party/chromium/LICENSE. webpki-0.21.0/README.md000064400000000000000000000071111336742241600125300ustar0000000000000000THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. What is webpki? ================== webpki is a library that validates Web PKI (TLS/SSL) certificates. webpki is designed to provide a **full** implementation of the client side of the **Web PKI** to a diverse range of applications and devices, including embedded (IoT) applications, mobile apps, desktop applications, and server infrastructure. webpki is intended to not only be the best implementation of the Web PKI, but to also *precisely define* what the Web PKI is. webpki is written in [Rust](https://www.rust-lang.org/) and uses [*ring*](https://github.com/briansmith/ring) for signature verification. webpki is strongly influenced by [mozilla::pkix](https://github.com/briansmith/mozillapkix). You can read a little about the ideas underlying both mozilla::pkix and webpki in [insanity::pkix: A New Certificate Path Building & Validation Library](https://briansmith.org/insanity-pkix.html). The Rust compiler statically guarantees there are no buffer overflows, uses-after-free, double-frees, data races, etc. in webpki. webpki takes advantage of Rust's borrow checker to ensure that its **zero-copy parsing** strategy is safe and efficient. webpki *never* allocates memory on the heap, and it maintains a tight bound on the amount of stack memory it uses. webpki avoids all superfluous PKIX features in order to keep its object code size small. Further reducing the code size of webpki is an important goal. This release is the very first prototype. Lots of improvements are planned, including: * An extensive automated test suite. * Key pinning. * Certificate Transparency support. * Short-lived certificate, OCSP stapling, and CRLSet support. * Customization of the supported algorithms, key sizes, and elliptic curves allowed during a validation. * A C language wrapper interface to allow using webpki in non-Rust applications. * A specification of precisely what the Web PKI is. Demo ==== See https://github.com/ctz/rustls#example-code for an example of using webpki. License ======= See [LICENSE](LICENSE). This project happily accepts pull requests without any formal copyright/contributor license agreement. Pull requests must explicitly indicate who owns the copyright to the code being contributed and that the code is being licensed under the same terms as the existing webpki code. Bug Reporting ============= Please report bugs either as pull requests or as issues in [the issue tracker](https://github.com/briansmith/webpki/issues). webpki has a **full disclosure** vulnerability policy. **Please do NOT attempt to report any security vulnerability in this code privately to anybody.** Online Automated Testing ======================== Travis CI is used for Linux and Mac OS X. Appveyor is used for Windows.
OSArch.Status
Linux x86, x64 Build Status
Mac OS X x64 x86, x64
Windows (-msvc) x86, x64 Build Status
webpki-0.21.0/src/calendar.rs000064400000000000000000000125571351327476500141760ustar0000000000000000// Copyright 2015-2016 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use super::{time::Time, Error}; pub fn time_from_ymdhms_utc( year: u64, month: u64, day_of_month: u64, hours: u64, minutes: u64, seconds: u64, ) -> Result { let days_before_year_since_unix_epoch = days_before_year_since_unix_epoch(year)?; const JAN: u64 = 31; let feb = days_in_feb(year); const MAR: u64 = 31; const APR: u64 = 30; const MAY: u64 = 31; const JUN: u64 = 30; const JUL: u64 = 31; const AUG: u64 = 31; const SEP: u64 = 30; const OCT: u64 = 31; const NOV: u64 = 30; let days_before_month_in_year = match month { 1 => 0, 2 => JAN, 3 => JAN + feb, 4 => JAN + feb + MAR, 5 => JAN + feb + MAR + APR, 6 => JAN + feb + MAR + APR + MAY, 7 => JAN + feb + MAR + APR + MAY + JUN, 8 => JAN + feb + MAR + APR + MAY + JUN + JUL, 9 => JAN + feb + MAR + APR + MAY + JUN + JUL + AUG, 10 => JAN + feb + MAR + APR + MAY + JUN + JUL + AUG + SEP, 11 => JAN + feb + MAR + APR + MAY + JUN + JUL + AUG + SEP + OCT, 12 => JAN + feb + MAR + APR + MAY + JUN + JUL + AUG + SEP + OCT + NOV, _ => unreachable!(), // `read_two_digits` already bounds-checked it. }; let days_before = days_before_year_since_unix_epoch + days_before_month_in_year + day_of_month - 1; let seconds_since_unix_epoch = (days_before * 24 * 60 * 60) + (hours * 60 * 60) + (minutes * 60) + seconds; Ok(Time::from_seconds_since_unix_epoch( seconds_since_unix_epoch, )) } fn days_before_year_since_unix_epoch(year: u64) -> Result { // We don't support dates before January 1, 1970 because that is the // Unix epoch. It is likely that other software won't deal well with // certificates that have dates before the epoch. if year < 1970 { return Err(Error::BadDERTime); } let days_before_year_ad = days_before_year_ad(year); debug_assert!(days_before_year_ad >= DAYS_BEFORE_UNIX_EPOCH_AD); Ok(days_before_year_ad - DAYS_BEFORE_UNIX_EPOCH_AD) } fn days_before_year_ad(year: u64) -> u64 { ((year - 1) * 365) + ((year - 1) / 4) // leap years are every 4 years, - ((year - 1) / 100) // except years divisible by 100, + ((year - 1) / 400) // except years divisible by 400. } pub fn days_in_month(year: u64, month: u64) -> u64 { match month { 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, 4 | 6 | 9 | 11 => 30, 2 => days_in_feb(year), _ => unreachable!(), // `read_two_digits` already bounds-checked it. } } fn days_in_feb(year: u64) -> u64 { if (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) { 29 } else { 28 } } const DAYS_BEFORE_UNIX_EPOCH_AD: u64 = 719162; #[cfg(test)] mod tests { #[test] fn test_days_before_unix_epoch() { use super::{days_before_year_ad, DAYS_BEFORE_UNIX_EPOCH_AD}; assert_eq!(DAYS_BEFORE_UNIX_EPOCH_AD, days_before_year_ad(1970)); } #[test] fn test_days_in_month() { use super::days_in_month; assert_eq!(days_in_month(2017, 1), 31); assert_eq!(days_in_month(2017, 2), 28); assert_eq!(days_in_month(2017, 3), 31); assert_eq!(days_in_month(2017, 4), 30); assert_eq!(days_in_month(2017, 5), 31); assert_eq!(days_in_month(2017, 6), 30); assert_eq!(days_in_month(2017, 7), 31); assert_eq!(days_in_month(2017, 8), 31); assert_eq!(days_in_month(2017, 9), 30); assert_eq!(days_in_month(2017, 10), 31); assert_eq!(days_in_month(2017, 11), 30); assert_eq!(days_in_month(2017, 12), 31); // leap cases assert_eq!(days_in_month(2000, 2), 29); assert_eq!(days_in_month(2004, 2), 29); assert_eq!(days_in_month(2016, 2), 29); assert_eq!(days_in_month(2100, 2), 28); } #[test] fn test_time_from_ymdhms_utc() { use super::{time_from_ymdhms_utc, Time}; // year boundary assert_eq!( Time::from_seconds_since_unix_epoch(1483228799), time_from_ymdhms_utc(2016, 12, 31, 23, 59, 59).unwrap() ); assert_eq!( Time::from_seconds_since_unix_epoch(1483228800), time_from_ymdhms_utc(2017, 1, 1, 0, 0, 0).unwrap() ); // not a leap year assert_eq!( Time::from_seconds_since_unix_epoch(1492449162), time_from_ymdhms_utc(2017, 4, 17, 17, 12, 42).unwrap() ); // leap year, post-feb assert_eq!( Time::from_seconds_since_unix_epoch(1460913162), time_from_ymdhms_utc(2016, 4, 17, 17, 12, 42).unwrap() ); } } webpki-0.21.0/src/cert.rs000064400000000000000000000174341351327572700133600ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use crate::{der, signed_data, Error}; pub enum EndEntityOrCA<'a> { EndEntity, CA(&'a Cert<'a>), } pub struct Cert<'a> { pub ee_or_ca: EndEntityOrCA<'a>, pub signed_data: signed_data::SignedData<'a>, pub issuer: untrusted::Input<'a>, pub validity: untrusted::Input<'a>, pub subject: untrusted::Input<'a>, pub spki: untrusted::Input<'a>, pub basic_constraints: Option>, pub eku: Option>, pub name_constraints: Option>, pub subject_alt_name: Option>, } pub fn parse_cert<'a>( cert_der: untrusted::Input<'a>, ee_or_ca: EndEntityOrCA<'a>, ) -> Result, Error> { parse_cert_internal(cert_der, ee_or_ca, certificate_serial_number) } /// Used by `parse_cert` for regular certificates (end-entity and intermediate) /// and by `cert_der_as_trust_anchor` for trust anchors encoded as /// certificates. pub(crate) fn parse_cert_internal<'a>( cert_der: untrusted::Input<'a>, ee_or_ca: EndEntityOrCA<'a>, serial_number: fn(input: &mut untrusted::Reader<'_>) -> Result<(), Error>, ) -> Result, Error> { let (tbs, signed_data) = cert_der.read_all(Error::BadDER, |cert_der| { der::nested( cert_der, der::Tag::Sequence, Error::BadDER, signed_data::parse_signed_data, ) })?; tbs.read_all(Error::BadDER, |tbs| { version3(tbs)?; serial_number(tbs)?; let signature = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?; // TODO: In mozilla::pkix, the comparison is done based on the // normalized value (ignoring whether or not there is an optional NULL // parameter for RSA-based algorithms), so this may be too strict. if signature != signed_data.algorithm { return Err(Error::SignatureAlgorithmMismatch); } let issuer = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?; let validity = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?; let subject = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?; let spki = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?; // In theory there could be fields [1] issuerUniqueID and [2] // subjectUniqueID, but in practice there never are, and to keep the // code small and simple we don't accept any certificates that do // contain them. let mut cert = Cert { ee_or_ca, signed_data, issuer, validity, subject, spki, basic_constraints: None, eku: None, name_constraints: None, subject_alt_name: None, }; // mozilla::pkix allows the extensions to be omitted. However, since // the subjectAltName extension is mandatory, the extensions are // mandatory too, and we enforce that. Also, mozilla::pkix includes // special logic for handling critical Netscape Cert Type extensions. // That has been intentionally omitted. der::nested_mut( tbs, der::Tag::ContextSpecificConstructed3, Error::BadDER, |tagged| { der::nested_of_mut( tagged, der::Tag::Sequence, der::Tag::Sequence, Error::BadDER, |extension| { let extn_id = der::expect_tag_and_get_value(extension, der::Tag::OID)?; let critical = der::optional_boolean(extension)?; let extn_value = der::expect_tag_and_get_value(extension, der::Tag::OctetString)?; match remember_extension(&mut cert, extn_id, extn_value)? { Understood::No if critical => Err(Error::UnsupportedCriticalExtension), _ => Ok(()), } }, ) }, )?; Ok(cert) }) } // mozilla::pkix supports v1, v2, v3, and v4, including both the implicit // (correct) and explicit (incorrect) encoding of v1. We allow only v3. fn version3(input: &mut untrusted::Reader) -> Result<(), Error> { der::nested( input, der::Tag::ContextSpecificConstructed0, Error::BadDER, |input| { let version = der::small_nonnegative_integer(input)?; if version != 2 { // v3 return Err(Error::UnsupportedCertVersion); } Ok(()) }, ) } pub fn certificate_serial_number(input: &mut untrusted::Reader) -> Result<(), Error> { // https://tools.ietf.org/html/rfc5280#section-4.1.2.2: // * Conforming CAs MUST NOT use serialNumber values longer than 20 octets." // * "The serial number MUST be a positive integer [...]" let value = der::positive_integer(input)?; if value.big_endian_without_leading_zero().len() > 20 { return Err(Error::BadDER); } Ok(()) } enum Understood { Yes, No, } fn remember_extension<'a>( cert: &mut Cert<'a>, extn_id: untrusted::Input, value: untrusted::Input<'a>, ) -> Result { // We don't do anything with certificate policies so we can safely ignore // all policy-related stuff. We assume that the policy-related extensions // are not marked critical. // id-ce 2.5.29 static ID_CE: [u8; 2] = oid![2, 5, 29]; if extn_id.len() != ID_CE.len() + 1 || !extn_id.as_slice_less_safe().starts_with(&ID_CE) { return Ok(Understood::No); } let out = match *extn_id.as_slice_less_safe().last().unwrap() { // id-ce-keyUsage 2.5.29.15. We ignore the KeyUsage extension. For CA // certificates, BasicConstraints.cA makes KeyUsage redundant. Firefox // and other common browsers do not check KeyUsage for end-entities, // though it would be kind of nice to ensure that a KeyUsage without // the keyEncipherment bit could not be used for RSA key exchange. 15 => { return Ok(Understood::Yes); }, // id-ce-subjectAltName 2.5.29.17 17 => &mut cert.subject_alt_name, // id-ce-basicConstraints 2.5.29.19 19 => &mut cert.basic_constraints, // id-ce-nameConstraints 2.5.29.30 30 => &mut cert.name_constraints, // id-ce-extKeyUsage 2.5.29.37 37 => &mut cert.eku, _ => { return Ok(Understood::No); }, }; match *out { Some(..) => { // The certificate contains more than one instance of this // extension. return Err(Error::ExtensionValueInvalid); }, None => { // All the extensions that we care about are wrapped in a SEQUENCE. let sequence_value = value.read_all(Error::BadDER, |value| { der::expect_tag_and_get_value(value, der::Tag::Sequence) })?; *out = Some(sequence_value); }, } Ok(Understood::Yes) } webpki-0.21.0/src/data/README.md000064400000000000000000000011751314565023400142270ustar0000000000000000These files contain the binary DER encoding of the *values* of some ASN.1 [`AlgorithmIdentifier`]s, without the outer `SEQUENCE` tag or the outer length component. These files were encoded with the help of [der-ascii]. They can be decoded using: ```sh go get github.com/google/der-ascii/cmd/der2ascii der2ascii -i -o .ascii ``` New or modified der-ascii files can be encoded using: ```sh go get github.com/google/der-ascii/cmd/ascii2der ascii2der i .ascii -o ``` [`AlgorithmIdentifier`]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2] [der-ascii]: https://github.com/google/der-ascii webpki-0.21.0/src/data/alg-ecdsa-p256.der000064400000000000000000000000231314565023400157450ustar0000000000000000*H=*H=webpki-0.21.0/src/data/alg-ecdsa-p384.der000064400000000000000000000000201314565023400157440ustar0000000000000000*H=+"webpki-0.21.0/src/data/alg-ecdsa-sha256.der000064400000000000000000000000121314565023400162570ustar0000000000000000*H=webpki-0.21.0/src/data/alg-ecdsa-sha384.der000064400000000000000000000000121314565023400162610ustar0000000000000000*H=webpki-0.21.0/src/data/alg-ed25519.der000064400000000000000000000000051342116420100151610ustar0000000000000000+epwebpki-0.21.0/src/data/alg-rsa-encryption.der000064400000000000000000000000151314565023400171520ustar0000000000000000 *H webpki-0.21.0/src/data/alg-rsa-pkcs1-sha256.der000064400000000000000000000000151314565023400170070ustar0000000000000000 *H  webpki-0.21.0/src/data/alg-rsa-pkcs1-sha384.der000064400000000000000000000000151314565023400170110ustar0000000000000000 *H  webpki-0.21.0/src/data/alg-rsa-pkcs1-sha512.der000064400000000000000000000000151314565023400170020ustar0000000000000000 *H  webpki-0.21.0/src/data/alg-rsa-pss-sha256.der000064400000000000000000000001011314565023400165670ustar0000000000000000 *H  040  `He0 *H 0  `He webpki-0.21.0/src/data/alg-rsa-pss-sha384.der000064400000000000000000000001011314565023400165710ustar0000000000000000 *H  040  `He0 *H 0  `He0webpki-0.21.0/src/data/alg-rsa-pss-sha512.der000064400000000000000000000001011314565023400165620ustar0000000000000000 *H  040  `He0 *H 0  `He@webpki-0.21.0/src/der.rs000064400000000000000000000127311351327572700131700ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use crate::{calendar, time, Error}; pub use ring::io::{ der::{nested, Tag, CONSTRUCTED}, Positive, }; #[inline(always)] pub fn expect_tag_and_get_value<'a>( input: &mut untrusted::Reader<'a>, tag: Tag, ) -> Result, Error> { ring::io::der::expect_tag_and_get_value(input, tag).map_err(|_| Error::BadDER) } #[inline(always)] pub fn read_tag_and_get_value<'a>( input: &mut untrusted::Reader<'a>, ) -> Result<(u8, untrusted::Input<'a>), Error> { ring::io::der::read_tag_and_get_value(input).map_err(|_| Error::BadDER) } // TODO: investigate taking decoder as a reference to reduce generated code // size. #[inline(always)] pub fn nested_mut<'a, F, R, E: Copy>( input: &mut untrusted::Reader<'a>, tag: Tag, error: E, decoder: F, ) -> Result where F: FnMut(&mut untrusted::Reader<'a>) -> Result, { let inner = expect_tag_and_get_value(input, tag).map_err(|_| error)?; inner.read_all(error, decoder).map_err(|_| error) } // TODO: investigate taking decoder as a reference to reduce generated code // size. pub fn nested_of_mut<'a, F, E: Copy>( input: &mut untrusted::Reader<'a>, outer_tag: Tag, inner_tag: Tag, error: E, mut decoder: F, ) -> Result<(), E> where F: FnMut(&mut untrusted::Reader<'a>) -> Result<(), E>, { nested_mut(input, outer_tag, error, |outer| { loop { nested_mut(outer, inner_tag, error, |inner| decoder(inner))?; if outer.at_end() { break; } } Ok(()) }) } pub fn bit_string_with_no_unused_bits<'a>( input: &mut untrusted::Reader<'a>, ) -> Result, Error> { nested(input, Tag::BitString, Error::BadDER, |value| { let unused_bits_at_end = value.read_byte().map_err(|_| Error::BadDER)?; if unused_bits_at_end != 0 { return Err(Error::BadDER); } Ok(value.read_bytes_to_end()) }) } // Like mozilla::pkix, we accept the nonconformant explicit encoding of // the default value (false) for compatibility with real-world certificates. pub fn optional_boolean(input: &mut untrusted::Reader) -> Result { if !input.peek(Tag::Boolean as u8) { return Ok(false); } nested(input, Tag::Boolean, Error::BadDER, |input| { match input.read_byte() { Ok(0xff) => Ok(true), Ok(0x00) => Ok(false), _ => Err(Error::BadDER), } }) } pub fn positive_integer<'a>(input: &'a mut untrusted::Reader) -> Result, Error> { ring::io::der::positive_integer(input).map_err(|_| Error::BadDER) } pub fn small_nonnegative_integer<'a>(input: &'a mut untrusted::Reader) -> Result { ring::io::der::small_nonnegative_integer(input).map_err(|_| Error::BadDER) } pub fn time_choice<'a>(input: &mut untrusted::Reader<'a>) -> Result { let is_utc_time = input.peek(Tag::UTCTime as u8); let expected_tag = if is_utc_time { Tag::UTCTime } else { Tag::GeneralizedTime }; fn read_digit(inner: &mut untrusted::Reader) -> Result { let b = inner.read_byte().map_err(|_| Error::BadDERTime)?; if b < b'0' || b > b'9' { return Err(Error::BadDERTime); } Ok((b - b'0') as u64) } fn read_two_digits(inner: &mut untrusted::Reader, min: u64, max: u64) -> Result { let hi = read_digit(inner)?; let lo = read_digit(inner)?; let value = (hi * 10) + lo; if value < min || value > max { return Err(Error::BadDERTime); } Ok(value) } nested(input, expected_tag, Error::BadDER, |value| { let (year_hi, year_lo) = if is_utc_time { let lo = read_two_digits(value, 0, 99)?; let hi = if lo >= 50 { 19 } else { 20 }; (hi, lo) } else { let hi = read_two_digits(value, 0, 99)?; let lo = read_two_digits(value, 0, 99)?; (hi, lo) }; let year = (year_hi * 100) + year_lo; let month = read_two_digits(value, 1, 12)?; let days_in_month = calendar::days_in_month(year, month); let day_of_month = read_two_digits(value, 1, days_in_month)?; let hours = read_two_digits(value, 0, 23)?; let minutes = read_two_digits(value, 0, 59)?; let seconds = read_two_digits(value, 0, 59)?; let time_zone = value.read_byte().map_err(|_| Error::BadDERTime)?; if time_zone != b'Z' { return Err(Error::BadDERTime); } calendar::time_from_ymdhms_utc(year, month, day_of_month, hours, minutes, seconds) }) } macro_rules! oid { ( $first:expr, $second:expr, $( $tail:expr ),* ) => ( [(40 * $first) + $second, $( $tail ),*] ) } webpki-0.21.0/src/error.rs000064400000000000000000000071231351327563400135430ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use core::fmt; /// An error that occurs during certificate validation or name validation. #[derive(Clone, Copy, Debug, PartialEq)] pub enum Error { /// The encoding of some ASN.1 DER-encoded item is invalid. BadDER, /// The encoding of an ASN.1 DER-encoded time is invalid. BadDERTime, /// A CA certificate is veing used as an end-entity certificate. CAUsedAsEndEntity, /// The certificate is expired; i.e. the time it is being validated for is /// later than the certificate's notAfter time. CertExpired, /// The certificate is not valid for the name it is being validated for. CertNotValidForName, /// The certificate is not valid yet; i.e. the time it is being validated /// for is earlier than the certificate's notBefore time. CertNotValidYet, /// An end-entity certificate is being used as a CA certificate. EndEntityUsedAsCA, /// An X.509 extension is invalid. ExtensionValueInvalid, /// The certificate validity period (notBefore, notAfter) is invalid; e.g. /// the notAfter time is earlier than the notBefore time. InvalidCertValidity, /// The signature is invalid for the given public key. InvalidSignatureForPublicKey, /// The certificate violates one or more name constraints. NameConstraintViolation, /// The certificate violates one or more path length constraints. PathLenConstraintViolated, /// The algorithm in the TBSCertificate "signature" field of a certificate /// does not match the algorithm in the signature of the certificate. SignatureAlgorithmMismatch, /// The certificate is not valid for the Extended Key Usage for which it is /// being validated. RequiredEKUNotFound, /// A valid issuer for the certificate could not be found. UnknownIssuer, /// The certificate is not a v3 X.509 certificate. UnsupportedCertVersion, /// The certificate contains an unsupported critical extension. UnsupportedCriticalExtension, /// The signature's algorithm does not match the algorithm of the public /// key it is being validated for. This may be because the public key /// algorithm's OID isn't recognized (e.g. DSA), or the public key /// algorithm's parameters don't match the supported parameters for that /// algorithm (e.g. ECC keys for unsupported curves), or the public key /// algorithm and the signature algorithm simply don't match (e.g. /// verifying an RSA signature with an ECC public key). UnsupportedSignatureAlgorithmForPublicKey, /// The signature algorithm for a signature is not in the set of supported /// signature algorithms given. UnsupportedSignatureAlgorithm, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } #[cfg(feature = "std")] impl ::std::error::Error for Error {} webpki-0.21.0/src/name.rs000064400000000000000000001246031351327572700133400ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use crate::{ cert::{Cert, EndEntityOrCA}, der, Error, }; use core; /// A DNS Name suitable for use in the TLS Server Name Indication (SNI) /// extension and/or for use as the reference hostname for which to verify a /// certificate. /// /// A `DNSName` is guaranteed to be syntactically valid. The validity rules are /// specified in [RFC 5280 Section 7.2], except that underscores are also /// allowed. /// /// `DNSName` stores a copy of the input it was constructed from in a `String` /// and so it is only available when the `std` default feature is enabled. /// /// `Eq`, `PartialEq`, etc. are not implemented because name comparison /// frequently should be done case-insensitively and/or with other caveats that /// depend on the specific circumstances in which the comparison is done. /// /// [RFC 5280 Section 7.2]: https://tools.ietf.org/html/rfc5280#section-7.2 #[cfg(feature = "std")] #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct DNSName(String); #[cfg(feature = "std")] impl DNSName { /// Returns a `DNSNameRef` that refers to this `DNSName`. pub fn as_ref(&self) -> DNSNameRef { DNSNameRef(self.0.as_bytes()) } } #[cfg(feature = "std")] impl AsRef for DNSName { fn as_ref(&self) -> &str { self.0.as_ref() } } // Deprecated #[cfg(feature = "std")] impl From> for DNSName { fn from(dns_name: DNSNameRef) -> Self { dns_name.to_owned() } } /// A reference to a DNS Name suitable for use in the TLS Server Name Indication /// (SNI) extension and/or for use as the reference hostname for which to verify /// a certificate. /// /// A `DNSNameRef` is guaranteed to be syntactically valid. The validity rules /// are specified in [RFC 5280 Section 7.2], except that underscores are also /// allowed. /// /// `Eq`, `PartialEq`, etc. are not implemented because name comparison /// frequently should be done case-insensitively and/or with other caveats that /// depend on the specific circumstances in which the comparison is done. /// /// [RFC 5280 Section 7.2]: https://tools.ietf.org/html/rfc5280#section-7.2 #[derive(Clone, Copy)] pub struct DNSNameRef<'a>(&'a [u8]); /// An error indicating that a `DNSNameRef` could not built because the input /// is not a syntactically-valid DNS Name. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct InvalidDNSNameError; impl core::fmt::Display for InvalidDNSNameError { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{:?}", self) } } #[cfg(feature = "std")] impl ::std::error::Error for InvalidDNSNameError {} impl<'a> DNSNameRef<'a> { /// Constructs a `DNSNameRef` from the given input if the input is a /// syntactically-valid DNS name. pub fn try_from_ascii(dns_name: &'a [u8]) -> Result { if !is_valid_reference_dns_id(untrusted::Input::from(dns_name)) { return Err(InvalidDNSNameError); } Ok(Self(dns_name)) } /// Constructs a `DNSNameRef` from the given input if the input is a /// syntactically-valid DNS name. pub fn try_from_ascii_str(dns_name: &'a str) -> Result { Self::try_from_ascii(dns_name.as_bytes()) } /// Constructs a `DNSName` from this `DNSNameRef` #[cfg(feature = "std")] pub fn to_owned(&self) -> DNSName { // DNSNameRef is already guaranteed to be valid ASCII, which is a // subset of UTF-8. let s: &str = self.clone().into(); DNSName(s.to_ascii_lowercase()) } } #[cfg(feature = "std")] impl core::fmt::Debug for DNSNameRef<'_> { fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { let lowercase = self.clone().to_owned(); f.debug_tuple("DNSNameRef").field(&lowercase.0).finish() } } impl<'a> From> for &'a str { fn from(DNSNameRef(d): DNSNameRef<'a>) -> Self { // The unwrap won't fail because DNSNameRefs are guaranteed to be ASCII // and ASCII is a subset of UTF-8. core::str::from_utf8(d).unwrap() } } pub fn verify_cert_dns_name( cert: &super::EndEntityCert, DNSNameRef(dns_name): DNSNameRef, ) -> Result<(), Error> { let cert = &cert.inner; let dns_name = untrusted::Input::from(dns_name); iterate_names( cert.subject, cert.subject_alt_name, Err(Error::CertNotValidForName), &|name| { match name { GeneralName::DNSName(presented_id) => match presented_dns_id_matches_reference_dns_id(presented_id, dns_name) { Some(true) => { return NameIteration::Stop(Ok(())); }, Some(false) => (), None => { return NameIteration::Stop(Err(Error::BadDER)); }, }, _ => (), } NameIteration::KeepGoing }, ) } // https://tools.ietf.org/html/rfc5280#section-4.2.1.10 pub fn check_name_constraints( input: Option<&mut untrusted::Reader>, subordinate_certs: &Cert, ) -> Result<(), Error> { let input = match input { Some(input) => input, None => { return Ok(()); }, }; fn parse_subtrees<'b>( inner: &mut untrusted::Reader<'b>, subtrees_tag: der::Tag, ) -> Result>, Error> { if !inner.peek(subtrees_tag as u8) { return Ok(None); } let subtrees = der::nested(inner, subtrees_tag, Error::BadDER, |tagged| { der::expect_tag_and_get_value(tagged, der::Tag::Sequence) })?; Ok(Some(subtrees)) } let permitted_subtrees = parse_subtrees(input, der::Tag::ContextSpecificConstructed0)?; let excluded_subtrees = parse_subtrees(input, der::Tag::ContextSpecificConstructed1)?; let mut child = subordinate_certs; loop { iterate_names(child.subject, child.subject_alt_name, Ok(()), &|name| { check_presented_id_conforms_to_constraints(name, permitted_subtrees, excluded_subtrees) })?; child = match child.ee_or_ca { EndEntityOrCA::CA(child_cert) => child_cert, EndEntityOrCA::EndEntity => { break; }, }; } Ok(()) } fn check_presented_id_conforms_to_constraints( name: GeneralName, permitted_subtrees: Option, excluded_subtrees: Option, ) -> NameIteration { match check_presented_id_conforms_to_constraints_in_subtree( name, Subtrees::PermittedSubtrees, permitted_subtrees, ) { stop @ NameIteration::Stop(..) => { return stop; }, NameIteration::KeepGoing => (), }; check_presented_id_conforms_to_constraints_in_subtree( name, Subtrees::ExcludedSubtrees, excluded_subtrees, ) } #[derive(Clone, Copy)] enum Subtrees { PermittedSubtrees, ExcludedSubtrees, } fn check_presented_id_conforms_to_constraints_in_subtree( name: GeneralName, subtrees: Subtrees, constraints: Option, ) -> NameIteration { let mut constraints = match constraints { Some(constraints) => untrusted::Reader::new(constraints), None => { return NameIteration::KeepGoing; }, }; let mut has_permitted_subtrees_match = false; let mut has_permitted_subtrees_mismatch = false; loop { // http://tools.ietf.org/html/rfc5280#section-4.2.1.10: "Within this // profile, the minimum and maximum fields are not used with any name // forms, thus, the minimum MUST be zero, and maximum MUST be absent." // // Since the default value isn't allowed to be encoded according to the // DER encoding rules for DEFAULT, this is equivalent to saying that // neither minimum or maximum must be encoded. fn general_subtree<'b>( input: &mut untrusted::Reader<'b>, ) -> Result, Error> { let general_subtree = der::expect_tag_and_get_value(input, der::Tag::Sequence)?; general_subtree.read_all(Error::BadDER, |subtree| general_name(subtree)) } let base = match general_subtree(&mut constraints) { Ok(base) => base, Err(err) => { return NameIteration::Stop(Err(err)); }, }; let matches = match (name, base) { (GeneralName::DNSName(name), GeneralName::DNSName(base)) => presented_dns_id_matches_dns_id_constraint(name, base).ok_or(Error::BadDER), (GeneralName::DirectoryName(name), GeneralName::DirectoryName(base)) => presented_directory_name_matches_constraint(name, base, subtrees), (GeneralName::IPAddress(name), GeneralName::IPAddress(base)) => presented_ip_address_matches_constraint(name, base), // RFC 4280 says "If a name constraints extension that is marked as // critical imposes constraints on a particular name form, and an // instance of that name form appears in the subject field or // subjectAltName extension of a subsequent certificate, then the // application MUST either process the constraint or reject the // certificate." Later, the CABForum agreed to support non-critical // constraints, so it is important to reject the cert without // considering whether the name constraint it critical. (GeneralName::Unsupported(name_tag), GeneralName::Unsupported(base_tag)) if name_tag == base_tag => Err(Error::NameConstraintViolation), _ => Ok(false), }; match (subtrees, matches) { (Subtrees::PermittedSubtrees, Ok(true)) => { has_permitted_subtrees_match = true; }, (Subtrees::PermittedSubtrees, Ok(false)) => { has_permitted_subtrees_mismatch = true; }, (Subtrees::ExcludedSubtrees, Ok(true)) => { return NameIteration::Stop(Err(Error::NameConstraintViolation)); }, (Subtrees::ExcludedSubtrees, Ok(false)) => (), (_, Err(err)) => { return NameIteration::Stop(Err(err)); }, } if constraints.at_end() { break; } } if has_permitted_subtrees_mismatch && !has_permitted_subtrees_match { // If there was any entry of the given type in permittedSubtrees, then // it required that at least one of them must match. Since none of them // did, we have a failure. NameIteration::Stop(Err(Error::NameConstraintViolation)) } else { NameIteration::KeepGoing } } // TODO: document this. fn presented_directory_name_matches_constraint( name: untrusted::Input, constraint: untrusted::Input, subtrees: Subtrees, ) -> Result { match subtrees { Subtrees::PermittedSubtrees => Ok(name == constraint), Subtrees::ExcludedSubtrees => Ok(true), } } // https://tools.ietf.org/html/rfc5280#section-4.2.1.10 says: // // For IPv4 addresses, the iPAddress field of GeneralName MUST contain // eight (8) octets, encoded in the style of RFC 4632 (CIDR) to represent // an address range [RFC4632]. For IPv6 addresses, the iPAddress field // MUST contain 32 octets similarly encoded. For example, a name // constraint for "class C" subnet 192.0.2.0 is represented as the // octets C0 00 02 00 FF FF FF 00, representing the CIDR notation // 192.0.2.0/24 (mask 255.255.255.0). fn presented_ip_address_matches_constraint( name: untrusted::Input, constraint: untrusted::Input, ) -> Result { if name.len() != 4 && name.len() != 16 { return Err(Error::BadDER); } if constraint.len() != 8 && constraint.len() != 32 { return Err(Error::BadDER); } // an IPv4 address never matches an IPv6 constraint, and vice versa. if name.len() * 2 != constraint.len() { return Ok(false); } let (constraint_address, constraint_mask) = constraint.read_all(Error::BadDER, |value| { let address = value.read_bytes(constraint.len() / 2).unwrap(); let mask = value.read_bytes(constraint.len() / 2).unwrap(); Ok((address, mask)) })?; let mut name = untrusted::Reader::new(name); let mut constraint_address = untrusted::Reader::new(constraint_address); let mut constraint_mask = untrusted::Reader::new(constraint_mask); loop { let name_byte = name.read_byte().unwrap(); let constraint_address_byte = constraint_address.read_byte().unwrap(); let constraint_mask_byte = constraint_mask.read_byte().unwrap(); if ((name_byte ^ constraint_address_byte) & constraint_mask_byte) != 0 { return Ok(false); } if name.at_end() { break; } } return Ok(true); } #[derive(Clone, Copy)] enum NameIteration { KeepGoing, Stop(Result<(), Error>), } fn iterate_names( subject: untrusted::Input, subject_alt_name: Option, result_if_never_stopped_early: Result<(), Error>, f: &dyn Fn(GeneralName) -> NameIteration, ) -> Result<(), Error> { match subject_alt_name { Some(subject_alt_name) => { let mut subject_alt_name = untrusted::Reader::new(subject_alt_name); // https://bugzilla.mozilla.org/show_bug.cgi?id=1143085: An empty // subjectAltName is not legal, but some certificates have an empty // subjectAltName. Since we don't support CN-IDs, the certificate // will be rejected either way, but checking `at_end` before // attempting to parse the first entry allows us to return a better // error code. while !subject_alt_name.at_end() { let name = general_name(&mut subject_alt_name)?; match f(name) { NameIteration::Stop(result) => { return result; }, NameIteration::KeepGoing => (), } } }, None => (), } match f(GeneralName::DirectoryName(subject)) { NameIteration::Stop(result) => result, NameIteration::KeepGoing => result_if_never_stopped_early, } } // It is *not* valid to derive `Eq`, `PartialEq, etc. for this type. In // particular, for the types of `GeneralName`s that we don't understand, we // don't even store the value. Also, the meaning of a `GeneralName` in a name // constraint is different than the meaning of the identically-represented // `GeneralName` in other contexts. #[derive(Clone, Copy)] enum GeneralName<'a> { DNSName(untrusted::Input<'a>), DirectoryName(untrusted::Input<'a>), IPAddress(untrusted::Input<'a>), // The value is the `tag & ~(der::CONTEXT_SPECIFIC | der::CONSTRUCTED)` so // that the name constraint checking matches tags regardless of whether // those bits are set. Unsupported(u8), } fn general_name<'a>(input: &mut untrusted::Reader<'a>) -> Result, Error> { use ring::io::der::{CONSTRUCTED, CONTEXT_SPECIFIC}; const OTHER_NAME_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 0; const RFC822_NAME_TAG: u8 = CONTEXT_SPECIFIC | 1; const DNS_NAME_TAG: u8 = CONTEXT_SPECIFIC | 2; const X400_ADDRESS_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 3; const DIRECTORY_NAME_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 4; const EDI_PARTY_NAME_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 5; const UNIFORM_RESOURCE_IDENTIFIER_TAG: u8 = CONTEXT_SPECIFIC | 6; const IP_ADDRESS_TAG: u8 = CONTEXT_SPECIFIC | 7; const REGISTERED_ID_TAG: u8 = CONTEXT_SPECIFIC | 8; let (tag, value) = der::read_tag_and_get_value(input)?; let name = match tag { DNS_NAME_TAG => GeneralName::DNSName(value), DIRECTORY_NAME_TAG => GeneralName::DirectoryName(value), IP_ADDRESS_TAG => GeneralName::IPAddress(value), OTHER_NAME_TAG | RFC822_NAME_TAG | X400_ADDRESS_TAG | EDI_PARTY_NAME_TAG | UNIFORM_RESOURCE_IDENTIFIER_TAG | REGISTERED_ID_TAG => GeneralName::Unsupported(tag & !(CONTEXT_SPECIFIC | CONSTRUCTED)), _ => return Err(Error::BadDER), }; Ok(name) } fn presented_dns_id_matches_reference_dns_id( presented_dns_id: untrusted::Input, reference_dns_id: untrusted::Input, ) -> Option { presented_dns_id_matches_reference_dns_id_internal( presented_dns_id, IDRole::ReferenceID, reference_dns_id, ) } fn presented_dns_id_matches_dns_id_constraint( presented_dns_id: untrusted::Input, reference_dns_id: untrusted::Input, ) -> Option { presented_dns_id_matches_reference_dns_id_internal( presented_dns_id, IDRole::NameConstraint, reference_dns_id, ) } // We do not distinguish between a syntactically-invalid presented_dns_id and // one that is syntactically valid but does not match reference_dns_id; in both // cases, the result is false. // // We assume that both presented_dns_id and reference_dns_id are encoded in // such a way that US-ASCII (7-bit) characters are encoded in one byte and no // encoding of a non-US-ASCII character contains a code point in the range // 0-127. For example, UTF-8 is OK but UTF-16 is not. // // RFC6125 says that a wildcard label may be of the form *., where // and/or may be empty. However, NSS requires to be empty, and we // follow NSS's stricter policy by accepting wildcards only of the form // *., where may be empty. // // An relative presented DNS ID matches both an absolute reference ID and a // relative reference ID. Absolute presented DNS IDs are not supported: // // Presented ID Reference ID Result // ------------------------------------- // example.com example.com Match // example.com. example.com Mismatch // example.com example.com. Match // example.com. example.com. Mismatch // // There are more subtleties documented inline in the code. // // Name constraints /////////////////////////////////////////////////////////// // // This is all RFC 5280 has to say about DNSName constraints: // // DNS name restrictions are expressed as host.example.com. Any DNS // name that can be constructed by simply adding zero or more labels to // the left-hand side of the name satisfies the name constraint. For // example, www.host.example.com would satisfy the constraint but // host1.example.com would not. // // This lack of specificity has lead to a lot of uncertainty regarding // subdomain matching. In particular, the following questions have been // raised and answered: // // Q: Does a presented identifier equal (case insensitive) to the name // constraint match the constraint? For example, does the presented // ID "host.example.com" match a "host.example.com" constraint? // A: Yes. RFC5280 says "by simply adding zero or more labels" and this // is the case of adding zero labels. // // Q: When the name constraint does not start with ".", do subdomain // presented identifiers match it? For example, does the presented // ID "www.host.example.com" match a "host.example.com" constraint? // A: Yes. RFC5280 says "by simply adding zero or more labels" and this // is the case of adding more than zero labels. The example is the // one from RFC 5280. // // Q: When the name constraint does not start with ".", does a // non-subdomain prefix match it? For example, does "bigfoo.bar.com" // match "foo.bar.com"? [4] // A: No. We interpret RFC 5280's language of "adding zero or more labels" // to mean that whole labels must be prefixed. // // (Note that the above three scenarios are the same as the RFC 6265 // domain matching rules [0].) // // Q: Is a name constraint that starts with "." valid, and if so, what // semantics does it have? For example, does a presented ID of // "www.example.com" match a constraint of ".example.com"? Does a // presented ID of "example.com" match a constraint of ".example.com"? // A: This implementation, NSS[1], and SChannel[2] all support a // leading ".", but OpenSSL[3] does not yet. Amongst the // implementations that support it, a leading "." is legal and means // the same thing as when the "." is omitted, EXCEPT that a // presented identifier equal (case insensitive) to the name // constraint is not matched; i.e. presented DNSName identifiers // must be subdomains. Some CAs in Mozilla's CA program (e.g. HARICA) // have name constraints with the leading "." in their root // certificates. The name constraints imposed on DCISS by Mozilla also // have the it, so supporting this is a requirement for backward // compatibility, even if it is not yet standardized. So, for example, a // presented ID of "www.example.com" matches a constraint of // ".example.com" but a presented ID of "example.com" does not. // // Q: Is there a way to prevent subdomain matches? // A: Yes. // // Some people have proposed that dNSName constraints that do not // start with a "." should be restricted to exact (case insensitive) // matches. However, such a change of semantics from what RFC5280 // specifies would be a non-backward-compatible change in the case of // permittedSubtrees constraints, and it would be a security issue for // excludedSubtrees constraints. // // However, it can be done with a combination of permittedSubtrees and // excludedSubtrees, e.g. "example.com" in permittedSubtrees and // ".example.com" in excludedSubtrees. // // Q: Are name constraints allowed to be specified as absolute names? // For example, does a presented ID of "example.com" match a name // constraint of "example.com." and vice versa. // A: Absolute names are not supported as presented IDs or name // constraints. Only reference IDs may be absolute. // // Q: Is "" a valid DNSName constraint? If so, what does it mean? // A: Yes. Any valid presented DNSName can be formed "by simply adding zero // or more labels to the left-hand side" of "". In particular, an // excludedSubtrees DNSName constraint of "" forbids all DNSNames. // // Q: Is "." a valid DNSName constraint? If so, what does it mean? // A: No, because absolute names are not allowed (see above). // // [0] RFC 6265 (Cookies) Domain Matching rules: // http://tools.ietf.org/html/rfc6265#section-5.1.3 // [1] NSS source code: // https://mxr.mozilla.org/nss/source/lib/certdb/genname.c?rev=2a7348f013cb#1209 // [2] Description of SChannel's behavior from Microsoft: // http://www.imc.org/ietf-pkix/mail-archive/msg04668.html // [3] Proposal to add such support to OpenSSL: // http://www.mail-archive.com/openssl-dev%40openssl.org/msg36204.html // https://rt.openssl.org/Ticket/Display.html?id=3562 // [4] Feedback on the lack of clarify in the definition that never got // incorporated into the spec: // https://www.ietf.org/mail-archive/web/pkix/current/msg21192.html fn presented_dns_id_matches_reference_dns_id_internal( presented_dns_id: untrusted::Input, reference_dns_id_role: IDRole, reference_dns_id: untrusted::Input, ) -> Option { if !is_valid_dns_id(presented_dns_id, IDRole::PresentedID, AllowWildcards::Yes) { return None; } if !is_valid_dns_id(reference_dns_id, reference_dns_id_role, AllowWildcards::No) { return None; } let mut presented = untrusted::Reader::new(presented_dns_id); let mut reference = untrusted::Reader::new(reference_dns_id); match reference_dns_id_role { IDRole::ReferenceID => (), IDRole::NameConstraint if presented_dns_id.len() > reference_dns_id.len() => { if reference_dns_id.len() == 0 { // An empty constraint matches everything. return Some(true); } // If the reference ID starts with a dot then skip the prefix of // the presented ID and start the comparison at the position of // that dot. Examples: // // Matches Doesn't Match // ----------------------------------------------------------- // original presented ID: www.example.com badexample.com // skipped: www ba // presented ID w/o prefix: .example.com dexample.com // reference ID: .example.com .example.com // // If the reference ID does not start with a dot then we skip // the prefix of the presented ID but also verify that the // prefix ends with a dot. Examples: // // Matches Doesn't Match // ----------------------------------------------------------- // original presented ID: www.example.com badexample.com // skipped: www ba // must be '.': . d // presented ID w/o prefix: example.com example.com // reference ID: example.com example.com // if reference.peek(b'.') { if presented .skip(presented_dns_id.len() - reference_dns_id.len()) .is_err() { unreachable!(); } } else { if presented .skip(presented_dns_id.len() - reference_dns_id.len() - 1) .is_err() { unreachable!(); } if presented.read_byte() != Ok(b'.') { return Some(false); } } }, IDRole::NameConstraint => (), IDRole::PresentedID => unreachable!(), } // Only allow wildcard labels that consist only of '*'. if presented.peek(b'*') { if presented.skip(1).is_err() { unreachable!(); } loop { if reference.read_byte().is_err() { return Some(false); } if reference.peek(b'.') { break; } } } loop { let presented_byte = match (presented.read_byte(), reference.read_byte()) { (Ok(p), Ok(r)) if ascii_lower(p) == ascii_lower(r) => p, _ => { return Some(false); }, }; if presented.at_end() { // Don't allow presented IDs to be absolute. if presented_byte == b'.' { return None; } break; } } // Allow a relative presented DNS ID to match an absolute reference DNS ID, // unless we're matching a name constraint. if !reference.at_end() { if reference_dns_id_role != IDRole::NameConstraint { match reference.read_byte() { Ok(b'.') => (), _ => { return Some(false); }, }; } if !reference.at_end() { return Some(false); } } assert!(presented.at_end()); assert!(reference.at_end()); return Some(true); } #[inline] fn ascii_lower(b: u8) -> u8 { match b { b'A'..=b'Z' => b + b'a' - b'A', _ => b, } } #[derive(PartialEq)] enum AllowWildcards { No, Yes, } #[derive(Clone, Copy, PartialEq)] enum IDRole { ReferenceID, PresentedID, NameConstraint, } fn is_valid_reference_dns_id(hostname: untrusted::Input) -> bool { is_valid_dns_id(hostname, IDRole::ReferenceID, AllowWildcards::No) } // https://tools.ietf.org/html/rfc5280#section-4.2.1.6: // // When the subjectAltName extension contains a domain name system // label, the domain name MUST be stored in the dNSName (an IA5String). // The name MUST be in the "preferred name syntax", as specified by // Section 3.5 of [RFC1034] and as modified by Section 2.1 of // [RFC1123]. // // https://bugzilla.mozilla.org/show_bug.cgi?id=1136616: As an exception to the // requirement above, underscores are also allowed in names for compatibility. fn is_valid_dns_id( hostname: untrusted::Input, id_role: IDRole, allow_wildcards: AllowWildcards, ) -> bool { // https://blogs.msdn.microsoft.com/oldnewthing/20120412-00/?p=7873/ if hostname.len() > 253 { return false; } let mut input = untrusted::Reader::new(hostname); if id_role == IDRole::NameConstraint && input.at_end() { return true; } let mut dot_count = 0; let mut label_length = 0; let mut label_is_all_numeric = false; let mut label_ends_with_hyphen = false; // Only presented IDs are allowed to have wildcard labels. And, like // Chromium, be stricter than RFC 6125 requires by insisting that a // wildcard label consist only of '*'. let is_wildcard = allow_wildcards == AllowWildcards::Yes && input.peek(b'*'); let mut is_first_byte = !is_wildcard; if is_wildcard { if input.read_byte() != Ok(b'*') || input.read_byte() != Ok(b'.') { return false; } dot_count += 1; } loop { const MAX_LABEL_LENGTH: usize = 63; match input.read_byte() { Ok(b'-') => { if label_length == 0 { return false; // Labels must not start with a hyphen. } label_is_all_numeric = false; label_ends_with_hyphen = true; label_length += 1; if label_length > MAX_LABEL_LENGTH { return false; } }, Ok(b'0'..=b'9') => { if label_length == 0 { label_is_all_numeric = true; } label_ends_with_hyphen = false; label_length += 1; if label_length > MAX_LABEL_LENGTH { return false; } }, Ok(b'a'..=b'z') | Ok(b'A'..=b'Z') | Ok(b'_') => { label_is_all_numeric = false; label_ends_with_hyphen = false; label_length += 1; if label_length > MAX_LABEL_LENGTH { return false; } }, Ok(b'.') => { dot_count += 1; if label_length == 0 && (id_role != IDRole::NameConstraint || !is_first_byte) { return false; } if label_ends_with_hyphen { return false; // Labels must not end with a hyphen. } label_length = 0; }, _ => { return false; }, } is_first_byte = false; if input.at_end() { break; } } // Only reference IDs, not presented IDs or name constraints, may be // absolute. if label_length == 0 && id_role != IDRole::ReferenceID { return false; } if label_ends_with_hyphen { return false; // Labels must not end with a hyphen. } if label_is_all_numeric { return false; // Last label must not be all numeric. } if is_wildcard { // If the DNS ID ends with a dot, the last dot signifies an absolute ID. let label_count = if label_length == 0 { dot_count } else { dot_count + 1 }; // Like NSS, require at least two labels to follow the wildcard label. // TODO: Allow the TrustDomain to control this on a per-eTLD+1 basis, // similar to Chromium. Even then, it might be better to still enforce // that there are at least two labels after the wildcard. if label_count < 3 { return false; } } true } #[cfg(test)] mod tests { use super::*; const PRESENTED_MATCHES_REFERENCE: &[(&[u8], &[u8], Option)] = &[ (b"", b"a", None), (b"a", b"a", Some(true)), (b"b", b"a", Some(false)), (b"*.b.a", b"c.b.a", Some(true)), (b"*.b.a", b"b.a", Some(false)), (b"*.b.a", b"b.a.", Some(false)), // Wildcard not in leftmost label (b"d.c.b.a", b"d.c.b.a", Some(true)), (b"d.*.b.a", b"d.c.b.a", None), (b"d.c*.b.a", b"d.c.b.a", None), (b"d.c*.b.a", b"d.cc.b.a", None), // case sensitivity ( b"abcdefghijklmnopqrstuvwxyz", b"ABCDEFGHIJKLMNOPQRSTUVWXYZ", Some(true), ), ( b"ABCDEFGHIJKLMNOPQRSTUVWXYZ", b"abcdefghijklmnopqrstuvwxyz", Some(true), ), (b"aBc", b"Abc", Some(true)), // digits (b"a1", b"a1", Some(true)), // A trailing dot indicates an absolute name, and absolute names can match // relative names, and vice-versa. (b"example", b"example", Some(true)), (b"example.", b"example.", None), (b"example", b"example.", Some(true)), (b"example.", b"example", None), (b"example.com", b"example.com", Some(true)), (b"example.com.", b"example.com.", None), (b"example.com", b"example.com.", Some(true)), (b"example.com.", b"example.com", None), (b"example.com..", b"example.com.", None), (b"example.com..", b"example.com", None), (b"example.com...", b"example.com.", None), // xn-- IDN prefix (b"x*.b.a", b"xa.b.a", None), (b"x*.b.a", b"xna.b.a", None), (b"x*.b.a", b"xn-a.b.a", None), (b"x*.b.a", b"xn--a.b.a", None), (b"xn*.b.a", b"xn--a.b.a", None), (b"xn-*.b.a", b"xn--a.b.a", None), (b"xn--*.b.a", b"xn--a.b.a", None), (b"xn*.b.a", b"xn--a.b.a", None), (b"xn-*.b.a", b"xn--a.b.a", None), (b"xn--*.b.a", b"xn--a.b.a", None), (b"xn---*.b.a", b"xn--a.b.a", None), // "*" cannot expand to nothing. (b"c*.b.a", b"c.b.a", None), // -------------------------------------------------------------------------- // The rest of these are test cases adapted from Chromium's // x509_certificate_unittest.cc. The parameter order is the opposite in // Chromium's tests. Also, they some tests were modified to fit into this // framework or due to intentional differences between mozilla::pkix and // Chromium. (b"foo.com", b"foo.com", Some(true)), (b"f", b"f", Some(true)), (b"i", b"h", Some(false)), (b"*.foo.com", b"bar.foo.com", Some(true)), (b"*.test.fr", b"www.test.fr", Some(true)), (b"*.test.FR", b"wwW.tESt.fr", Some(true)), (b".uk", b"f.uk", None), (b"?.bar.foo.com", b"w.bar.foo.com", None), (b"(www|ftp).foo.com", b"www.foo.com", None), // regex! (b"www.foo.com\0", b"www.foo.com", None), (b"www.foo.com\0*.foo.com", b"www.foo.com", None), (b"ww.house.example", b"www.house.example", Some(false)), (b"www.test.org", b"test.org", Some(false)), (b"*.test.org", b"test.org", Some(false)), (b"*.org", b"test.org", None), // '*' must be the only character in the wildcard label (b"w*.bar.foo.com", b"w.bar.foo.com", None), (b"ww*ww.bar.foo.com", b"www.bar.foo.com", None), (b"ww*ww.bar.foo.com", b"wwww.bar.foo.com", None), (b"w*w.bar.foo.com", b"wwww.bar.foo.com", None), (b"w*w.bar.foo.c0m", b"wwww.bar.foo.com", None), (b"wa*.bar.foo.com", b"WALLY.bar.foo.com", None), (b"*Ly.bar.foo.com", b"wally.bar.foo.com", None), // Chromium does URL decoding of the reference ID, but we don't, and we also // require that the reference ID is valid, so we can't test these two. // (b"www.foo.com", b"ww%57.foo.com", Some(true)), // (b"www&.foo.com", b"www%26.foo.com", Some(true)), (b"*.test.de", b"www.test.co.jp", Some(false)), (b"*.jp", b"www.test.co.jp", None), (b"www.test.co.uk", b"www.test.co.jp", Some(false)), (b"www.*.co.jp", b"www.test.co.jp", None), (b"www.bar.foo.com", b"www.bar.foo.com", Some(true)), (b"*.foo.com", b"www.bar.foo.com", Some(false)), (b"*.*.foo.com", b"www.bar.foo.com", None), // Our matcher requires the reference ID to be a valid DNS name, so we cannot // test this case. // (b"*.*.bar.foo.com", b"*..bar.foo.com", Some(false)), (b"www.bath.org", b"www.bath.org", Some(true)), // Our matcher requires the reference ID to be a valid DNS name, so we cannot // test these cases. // DNS_ID_MISMATCH("www.bath.org", ""), // (b"www.bath.org", b"20.30.40.50", Some(false)), // (b"www.bath.org", b"66.77.88.99", Some(false)), // IDN tests ( b"xn--poema-9qae5a.com.br", b"xn--poema-9qae5a.com.br", Some(true), ), ( b"*.xn--poema-9qae5a.com.br", b"www.xn--poema-9qae5a.com.br", Some(true), ), ( b"*.xn--poema-9qae5a.com.br", b"xn--poema-9qae5a.com.br", Some(false), ), (b"xn--poema-*.com.br", b"xn--poema-9qae5a.com.br", None), (b"xn--*-9qae5a.com.br", b"xn--poema-9qae5a.com.br", None), (b"*--poema-9qae5a.com.br", b"xn--poema-9qae5a.com.br", None), // The following are adapted from the examples quoted from // http://tools.ietf.org/html/rfc6125#section-6.4.3 // (e.g., *.example.com would match foo.example.com but // not bar.foo.example.com or example.com). (b"*.example.com", b"foo.example.com", Some(true)), (b"*.example.com", b"bar.foo.example.com", Some(false)), (b"*.example.com", b"example.com", Some(false)), (b"baz*.example.net", b"baz1.example.net", None), (b"*baz.example.net", b"foobaz.example.net", None), (b"b*z.example.net", b"buzz.example.net", None), // Wildcards should not be valid for public registry controlled domains, // and unknown/unrecognized domains, at least three domain components must // be present. For mozilla::pkix and NSS, there must always be at least two // labels after the wildcard label. (b"*.test.example", b"www.test.example", Some(true)), (b"*.example.co.uk", b"test.example.co.uk", Some(true)), (b"*.example", b"test.example", None), // The result is different than Chromium, because Chromium takes into account // the additional knowledge it has that "co.uk" is a TLD. mozilla::pkix does // not know that. (b"*.co.uk", b"example.co.uk", Some(true)), (b"*.com", b"foo.com", None), (b"*.us", b"foo.us", None), (b"*", b"foo", None), // IDN variants of wildcards and registry controlled domains. ( b"*.xn--poema-9qae5a.com.br", b"www.xn--poema-9qae5a.com.br", Some(true), ), ( b"*.example.xn--mgbaam7a8h", b"test.example.xn--mgbaam7a8h", Some(true), ), // RFC6126 allows this, and NSS accepts it, but Chromium disallows it. // TODO: File bug against Chromium. (b"*.com.br", b"xn--poema-9qae5a.com.br", Some(true)), (b"*.xn--mgbaam7a8h", b"example.xn--mgbaam7a8h", None), // Wildcards should be permissible for 'private' registry-controlled // domains. (In mozilla::pkix, we do not know if it is a private registry- // controlled domain or not.) (b"*.appspot.com", b"www.appspot.com", Some(true)), (b"*.s3.amazonaws.com", b"foo.s3.amazonaws.com", Some(true)), // Multiple wildcards are not valid. (b"*.*.com", b"foo.example.com", None), (b"*.bar.*.com", b"foo.bar.example.com", None), // Absolute vs relative DNS name tests. Although not explicitly specified // in RFC 6125, absolute reference names (those ending in a .) should // match either absolute or relative presented names. // TODO: File errata against RFC 6125 about this. (b"foo.com.", b"foo.com", None), (b"foo.com", b"foo.com.", Some(true)), (b"foo.com.", b"foo.com.", None), (b"f.", b"f", None), (b"f", b"f.", Some(true)), (b"f.", b"f.", None), (b"*.bar.foo.com.", b"www-3.bar.foo.com", None), (b"*.bar.foo.com", b"www-3.bar.foo.com.", Some(true)), (b"*.bar.foo.com.", b"www-3.bar.foo.com.", None), // We require the reference ID to be a valid DNS name, so we cannot test this // case. // (b".", b".", Some(false)), (b"*.com.", b"example.com", None), (b"*.com", b"example.com.", None), (b"*.com.", b"example.com.", None), (b"*.", b"foo.", None), (b"*.", b"foo", None), // The result is different than Chromium because we don't know that co.uk is // a TLD. (b"*.co.uk.", b"foo.co.uk", None), (b"*.co.uk.", b"foo.co.uk.", None), ]; #[test] fn presented_matches_reference_test() { for &(presented, reference, expected_result) in PRESENTED_MATCHES_REFERENCE { use std::string::String; let actual_result = presented_dns_id_matches_reference_dns_id( untrusted::Input::from(presented), untrusted::Input::from(reference), ); assert_eq!( actual_result, expected_result, "presented_dns_id_matches_reference_dns_id(\"{}\", IDRole::ReferenceID, \"{}\")", String::from_utf8_lossy(presented), String::from_utf8_lossy(reference) ); } } } webpki-0.21.0/src/signed_data.rs000064400000000000000000000644501351327572700146650ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use crate::{der, Error}; use ring::signature; /// X.509 certificates and related items that are signed are almost always /// encoded in the format "tbs||signatureAlgorithm||signature". This structure /// captures this pattern. pub struct SignedData<'a> { /// The signed data. This would be `tbsCertificate` in the case of an X.509 /// certificate, `tbsResponseData` in the case of an OCSP response, and the /// data nested in the `digitally-signed` construct for TLS 1.2 signed /// data. data: untrusted::Input<'a>, /// The value of the `AlgorithmIdentifier`. This would be /// `signatureAlgorithm` in the case of an X.509 certificate or OCSP /// response. This would have to be synthesized in the case of TLS 1.2 /// signed data, since TLS does not identify algorithms by ASN.1 OIDs. pub(crate) algorithm: untrusted::Input<'a>, /// The value of the signature. This would be `signature` in an X.509 /// certificate or OCSP response. This would be the value of /// `DigitallySigned.signature` for TLS 1.2 signed data. signature: untrusted::Input<'a>, } /// Parses the concatenation of "tbs||signatureAlgorithm||signature" that /// is common in the X.509 certificate and OCSP response syntaxes. /// /// X.509 Certificates (RFC 5280) look like this: /// /// ```ASN.1 /// Certificate (SEQUENCE) { /// tbsCertificate TBSCertificate, /// signatureAlgorithm AlgorithmIdentifier, /// signatureValue BIT STRING /// } /// /// OCSP responses (RFC 6960) look like this: /// ```ASN.1 /// BasicOCSPResponse { /// tbsResponseData ResponseData, /// signatureAlgorithm AlgorithmIdentifier, /// signature BIT STRING, /// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL /// } /// ``` /// /// Note that this function does NOT parse the outermost `SEQUENCE` or the /// `certs` value. /// /// The return value's first component is the contents of /// `tbsCertificate`/`tbsResponseData`; the second component is a `SignedData` /// structure that can be passed to `verify_signed_data`. pub(crate) fn parse_signed_data<'a>( der: &mut untrusted::Reader<'a>, ) -> Result<(untrusted::Input<'a>, SignedData<'a>), Error> { let (data, tbs) = der.read_partial(|input| der::expect_tag_and_get_value(input, der::Tag::Sequence))?; let algorithm = der::expect_tag_and_get_value(der, der::Tag::Sequence)?; let signature = der::bit_string_with_no_unused_bits(der)?; Ok(( tbs, SignedData { data, algorithm, signature, }, )) } /// Verify `signed_data` using the public key in the DER-encoded /// SubjectPublicKeyInfo `spki` using one of the algorithms in /// `supported_algorithms`. /// /// The algorithm is chosen based on the algorithm information encoded in the /// algorithm identifiers in `public_key` and `signed_data.algorithm`. The /// ordering of the algorithms in `supported_algorithms` does not really matter, /// but generally more common algorithms should go first, as it is scanned /// linearly for matches. pub(crate) fn verify_signed_data( supported_algorithms: &[&SignatureAlgorithm], spki_value: untrusted::Input, signed_data: &SignedData, ) -> Result<(), Error> { // We need to verify the signature in `signed_data` using the public key // in `public_key`. In order to know which *ring* signature verification // algorithm to use, we need to know the public key algorithm (ECDSA, // RSA PKCS#1, etc.), the curve (if applicable), and the digest algorithm. // `signed_data` identifies only the public key algorithm and the digest // algorithm, and `public_key` identifies only the public key algorithm and // the curve (if any). Thus, we have to combine information from both // inputs to figure out which `ring::signature::VerificationAlgorithm` to // use to verify the signature. // // This is all further complicated by the fact that we don't have any // implicit knowledge about any algorithms or identifiers, since all of // that information is encoded in `supported_algorithms.` In particular, we // avoid hard-coding any of that information so that (link-time) dead code // elimination will work effectively in eliminating code for unused // algorithms. // Parse the signature. // let mut found_signature_alg_match = false; for supported_alg in supported_algorithms.iter().filter(|alg| { alg.signature_alg_id .matches_algorithm_id_value(signed_data.algorithm) }) { match verify_signature( supported_alg, spki_value, signed_data.data, signed_data.signature, ) { Err(Error::UnsupportedSignatureAlgorithmForPublicKey) => { found_signature_alg_match = true; continue; }, result => { return result; }, } } if found_signature_alg_match { Err(Error::UnsupportedSignatureAlgorithmForPublicKey) } else { Err(Error::UnsupportedSignatureAlgorithm) } } pub(crate) fn verify_signature( signature_alg: &SignatureAlgorithm, spki_value: untrusted::Input, msg: untrusted::Input, signature: untrusted::Input, ) -> Result<(), Error> { let spki = parse_spki_value(spki_value)?; if !signature_alg .public_key_alg_id .matches_algorithm_id_value(spki.algorithm_id_value) { return Err(Error::UnsupportedSignatureAlgorithmForPublicKey); } signature::UnparsedPublicKey::new( signature_alg.verification_alg, spki.key_value.as_slice_less_safe(), ) .verify(msg.as_slice_less_safe(), signature.as_slice_less_safe()) .map_err(|_| Error::InvalidSignatureForPublicKey) } struct SubjectPublicKeyInfo<'a> { algorithm_id_value: untrusted::Input<'a>, key_value: untrusted::Input<'a>, } // Parse the public key into an algorithm OID, an optional curve OID, and the // key value. The caller needs to check whether these match the // `PublicKeyAlgorithm` for the `SignatureAlgorithm` that is matched when // parsing the signature. fn parse_spki_value(input: untrusted::Input) -> Result { input.read_all(Error::BadDER, |input| { let algorithm_id_value = der::expect_tag_and_get_value(input, der::Tag::Sequence)?; let key_value = der::bit_string_with_no_unused_bits(input)?; Ok(SubjectPublicKeyInfo { algorithm_id_value, key_value, }) }) } /// A signature algorithm. pub struct SignatureAlgorithm { public_key_alg_id: AlgorithmIdentifier, signature_alg_id: AlgorithmIdentifier, verification_alg: &'static dyn signature::VerificationAlgorithm, } /// ECDSA signatures using the P-256 curve and SHA-256. pub static ECDSA_P256_SHA256: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: ECDSA_P256, signature_alg_id: ECDSA_SHA256, verification_alg: &signature::ECDSA_P256_SHA256_ASN1, }; /// ECDSA signatures using the P-256 curve and SHA-384. Deprecated. pub static ECDSA_P256_SHA384: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: ECDSA_P256, signature_alg_id: ECDSA_SHA384, verification_alg: &signature::ECDSA_P256_SHA384_ASN1, }; /// ECDSA signatures using the P-384 curve and SHA-256. Deprecated. pub static ECDSA_P384_SHA256: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: ECDSA_P384, signature_alg_id: ECDSA_SHA256, verification_alg: &signature::ECDSA_P384_SHA256_ASN1, }; /// ECDSA signatures using the P-384 curve and SHA-384. pub static ECDSA_P384_SHA384: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: ECDSA_P384, signature_alg_id: ECDSA_SHA384, verification_alg: &signature::ECDSA_P384_SHA384_ASN1, }; /// RSA PKCS#1 1.5 signatures using SHA-256 for keys of 2048-8192 bits. pub static RSA_PKCS1_2048_8192_SHA256: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: RSA_ENCRYPTION, signature_alg_id: RSA_PKCS1_SHA256, verification_alg: &signature::RSA_PKCS1_2048_8192_SHA256, }; /// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 2048-8192 bits. pub static RSA_PKCS1_2048_8192_SHA384: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: RSA_ENCRYPTION, signature_alg_id: RSA_PKCS1_SHA384, verification_alg: &signature::RSA_PKCS1_2048_8192_SHA384, }; /// RSA PKCS#1 1.5 signatures using SHA-512 for keys of 2048-8192 bits. pub static RSA_PKCS1_2048_8192_SHA512: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: RSA_ENCRYPTION, signature_alg_id: RSA_PKCS1_SHA512, verification_alg: &signature::RSA_PKCS1_2048_8192_SHA512, }; /// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 3072-8192 bits. pub static RSA_PKCS1_3072_8192_SHA384: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: RSA_ENCRYPTION, signature_alg_id: RSA_PKCS1_SHA384, verification_alg: &signature::RSA_PKCS1_3072_8192_SHA384, }; /// RSA PSS signatures using SHA-256 for keys of 2048-8192 bits and of /// type rsaEncryption; see https://tools.ietf.org/html/rfc4055#section-1.2 pub static RSA_PSS_2048_8192_SHA256_LEGACY_KEY: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: RSA_ENCRYPTION, signature_alg_id: RSA_PSS_SHA256, verification_alg: &signature::RSA_PSS_2048_8192_SHA256, }; /// RSA PSS signatures using SHA-384 for keys of 2048-8192 bits and of /// type rsaEncryption; see https://tools.ietf.org/html/rfc4055#section-1.2 pub static RSA_PSS_2048_8192_SHA384_LEGACY_KEY: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: RSA_ENCRYPTION, signature_alg_id: RSA_PSS_SHA384, verification_alg: &signature::RSA_PSS_2048_8192_SHA384, }; /// RSA PSS signatures using SHA-512 for keys of 2048-8192 bits and of /// type rsaEncryption; see https://tools.ietf.org/html/rfc4055#section-1.2 pub static RSA_PSS_2048_8192_SHA512_LEGACY_KEY: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: RSA_ENCRYPTION, signature_alg_id: RSA_PSS_SHA512, verification_alg: &signature::RSA_PSS_2048_8192_SHA512, }; /// ED25519 signatures according to RFC 8410 pub static ED25519: SignatureAlgorithm = SignatureAlgorithm { public_key_alg_id: ED_25519, signature_alg_id: ED_25519, verification_alg: &signature::ED25519, }; struct AlgorithmIdentifier { asn1_id_value: untrusted::Input<'static>, } impl AlgorithmIdentifier { fn matches_algorithm_id_value(&self, encoded: untrusted::Input) -> bool { encoded == self.asn1_id_value } } // See src/data/README.md. const ECDSA_P256: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-ecdsa-p256.der")), }; const ECDSA_P384: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-ecdsa-p384.der")), }; const ECDSA_SHA256: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-ecdsa-sha256.der")), }; const ECDSA_SHA384: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-ecdsa-sha384.der")), }; const RSA_ENCRYPTION: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-rsa-encryption.der")), }; const RSA_PKCS1_SHA256: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-rsa-pkcs1-sha256.der")), }; const RSA_PKCS1_SHA384: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-rsa-pkcs1-sha384.der")), }; const RSA_PKCS1_SHA512: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-rsa-pkcs1-sha512.der")), }; const RSA_PSS_SHA256: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-rsa-pss-sha256.der")), }; const RSA_PSS_SHA384: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-rsa-pss-sha384.der")), }; const RSA_PSS_SHA512: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-rsa-pss-sha512.der")), }; const ED_25519: AlgorithmIdentifier = AlgorithmIdentifier { asn1_id_value: untrusted::Input::from(include_bytes!("data/alg-ed25519.der")), }; #[cfg(test)] mod tests { use crate::{der, signed_data, Error}; use base64; use std::{self, io::BufRead, string::String, vec::Vec}; // TODO: The expected results need to be modified for SHA-1 deprecation. macro_rules! test_verify_signed_data { ($fn_name:ident, $file_name:expr, $expected_result:expr) => { #[test] fn $fn_name() { test_verify_signed_data($file_name, $expected_result); } }; } fn test_verify_signed_data(file_name: &str, expected_result: Result<(), Error>) { let tsd = parse_test_signed_data(file_name); let spki_value = untrusted::Input::from(&tsd.spki); let spki_value = spki_value .read_all(Error::BadDER, |input| { der::expect_tag_and_get_value(input, der::Tag::Sequence) }) .unwrap(); // we can't use `parse_signed_data` because it requires `data` // to be an ASN.1 SEQUENCE, and that isn't the case with // Chromium's test data. TODO: The test data set should be // expanded with SEQUENCE-wrapped data so that we can actually // test `parse_signed_data`. let algorithm = untrusted::Input::from(&tsd.algorithm); let algorithm = algorithm .read_all(Error::BadDER, |input| { der::expect_tag_and_get_value(input, der::Tag::Sequence) }) .unwrap(); let signature = untrusted::Input::from(&tsd.signature); let signature = signature .read_all(Error::BadDER, |input| { der::bit_string_with_no_unused_bits(input) }) .unwrap(); let signed_data = signed_data::SignedData { data: untrusted::Input::from(&tsd.data), algorithm, signature, }; assert_eq!( expected_result, signed_data::verify_signed_data( SUPPORTED_ALGORITHMS_IN_TESTS, spki_value, &signed_data ) ); } // XXX: This is testing code that isn't even in this module. macro_rules! test_verify_signed_data_signature_outer { ($fn_name:ident, $file_name:expr, $expected_result:expr) => { #[test] fn $fn_name() { test_verify_signed_data_signature_outer($file_name, $expected_result); } }; } fn test_verify_signed_data_signature_outer(file_name: &str, expected_error: Error) { let tsd = parse_test_signed_data(file_name); let signature = untrusted::Input::from(&tsd.signature); assert_eq!( Err(expected_error), signature.read_all(Error::BadDER, |input| { der::bit_string_with_no_unused_bits(input) }) ); } // XXX: This is testing code that is not even in this module. macro_rules! test_parse_spki_bad_outer { ($fn_name:ident, $file_name:expr, $error:expr) => { #[test] fn $fn_name() { test_parse_spki_bad_outer($file_name, $error) } }; } fn test_parse_spki_bad_outer(file_name: &str, expected_error: Error) { let tsd = parse_test_signed_data(file_name); let spki = untrusted::Input::from(&tsd.spki); assert_eq!( Err(expected_error), spki.read_all(Error::BadDER, |input| { der::expect_tag_and_get_value(input, der::Tag::Sequence) }) ); } // XXX: Some of the BadDER tests should have better error codes, maybe? // XXX: We should have a variant of this test with a SHA-256 digest that gives // `Error::UnsupportedSignatureAlgorithmForPublicKey`. test_verify_signed_data!( test_ecdsa_prime256v1_sha512_spki_params_null, "ecdsa-prime256v1-sha512-spki-params-null.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data_signature_outer!( test_ecdsa_prime256v1_sha512_unused_bits_signature, "ecdsa-prime256v1-sha512-unused-bits-signature.pem", Error::BadDER ); // XXX: We should have a variant of this test with a SHA-256 digest that gives // `Error::UnsupportedSignatureAlgorithmForPublicKey`. test_verify_signed_data!( test_ecdsa_prime256v1_sha512_using_ecdh_key, "ecdsa-prime256v1-sha512-using-ecdh-key.pem", Err(Error::UnsupportedSignatureAlgorithm) ); // XXX: We should have a variant of this test with a SHA-256 digest that gives // `Error::UnsupportedSignatureAlgorithmForPublicKey`. test_verify_signed_data!( test_ecdsa_prime256v1_sha512_using_ecmqv_key, "ecdsa-prime256v1-sha512-using-ecmqv-key.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_ecdsa_prime256v1_sha512_using_rsa_algorithm, "ecdsa-prime256v1-sha512-using-rsa-algorithm.pem", Err(Error::UnsupportedSignatureAlgorithmForPublicKey) ); // XXX: We should have a variant of this test with a SHA-256 digest that gives // `Error::InvalidSignatureForPublicKey`. test_verify_signed_data!( test_ecdsa_prime256v1_sha512_wrong_signature_format, "ecdsa-prime256v1-sha512-wrong-signature-format.pem", Err(Error::UnsupportedSignatureAlgorithm) ); // Differs from Chromium because we don't support P-256 with SHA-512. test_verify_signed_data!( test_ecdsa_prime256v1_sha512, "ecdsa-prime256v1-sha512.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_ecdsa_secp384r1_sha256_corrupted_data, "ecdsa-secp384r1-sha256-corrupted-data.pem", Err(Error::InvalidSignatureForPublicKey) ); test_verify_signed_data!( test_ecdsa_secp384r1_sha256, "ecdsa-secp384r1-sha256.pem", Ok(()) ); test_verify_signed_data!( test_ecdsa_using_rsa_key, "ecdsa-using-rsa-key.pem", Err(Error::UnsupportedSignatureAlgorithmForPublicKey) ); test_parse_spki_bad_outer!( test_rsa_pkcs1_sha1_bad_key_der_length, "rsa-pkcs1-sha1-bad-key-der-length.pem", Error::BadDER ); test_parse_spki_bad_outer!( test_rsa_pkcs1_sha1_bad_key_der_null, "rsa-pkcs1-sha1-bad-key-der-null.pem", Error::BadDER ); test_verify_signed_data!( test_rsa_pkcs1_sha1_key_params_absent, "rsa-pkcs1-sha1-key-params-absent.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pkcs1_sha1_using_pss_key_no_params, "rsa-pkcs1-sha1-using-pss-key-no-params.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pkcs1_sha1_wrong_algorithm, "rsa-pkcs1-sha1-wrong-algorithm.pem", Err(Error::InvalidSignatureForPublicKey) ); test_verify_signed_data!( test_rsa_pkcs1_sha1, "rsa-pkcs1-sha1.pem", Err(Error::UnsupportedSignatureAlgorithm) ); // XXX: RSA PKCS#1 with SHA-1 is a supported algorithm, but we only accept // 2048-8192 bit keys, and this test file is using a 1024 bit key. Thus, // our results differ from Chromium's. TODO: this means we need a 2048+ bit // version of this test. test_verify_signed_data!( test_rsa_pkcs1_sha256, "rsa-pkcs1-sha256.pem", Err(Error::InvalidSignatureForPublicKey) ); test_parse_spki_bad_outer!( test_rsa_pkcs1_sha256_key_encoded_ber, "rsa-pkcs1-sha256-key-encoded-ber.pem", Error::BadDER ); test_verify_signed_data!( test_rsa_pkcs1_sha256_spki_non_null_params, "rsa-pkcs1-sha256-spki-non-null-params.pem", Err(Error::UnsupportedSignatureAlgorithmForPublicKey) ); test_verify_signed_data!( test_rsa_pkcs1_sha256_using_ecdsa_algorithm, "rsa-pkcs1-sha256-using-ecdsa-algorithm.pem", Err(Error::UnsupportedSignatureAlgorithmForPublicKey) ); test_verify_signed_data!( test_rsa_pkcs1_sha256_using_id_ea_rsa, "rsa-pkcs1-sha256-using-id-ea-rsa.pem", Err(Error::UnsupportedSignatureAlgorithmForPublicKey) ); // Chromium's PSS test are for parameter combinations we don't support. test_verify_signed_data!( test_rsa_pss_sha1_salt20_using_pss_key_no_params, "rsa-pss-sha1-salt20-using-pss-key-no-params.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pss_sha1_salt20_using_pss_key_with_null_params, "rsa-pss-sha1-salt20-using-pss-key-with-null-params.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pss_sha1_salt20, "rsa-pss-sha1-salt20.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pss_sha1_wrong_salt, "rsa-pss-sha1-wrong-salt.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pss_sha256_mgf1_sha512_salt33, "rsa-pss-sha256-mgf1-sha512-salt33.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pss_sha256_salt10_using_pss_key_with_params, "rsa-pss-sha256-salt10-using-pss-key-with-params.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pss_sha256_salt10_using_pss_key_with_wrong_params, "rsa-pss-sha256-salt10-using-pss-key-with-wrong-params.pem", Err(Error::UnsupportedSignatureAlgorithm) ); test_verify_signed_data!( test_rsa_pss_sha256_salt10, "rsa-pss-sha256-salt10.pem", Err(Error::UnsupportedSignatureAlgorithm) ); // Our PSS tests that should work. test_verify_signed_data!( test_rsa_pss_sha256_salt32, "ours/rsa-pss-sha256-salt32.pem", Ok(()) ); test_verify_signed_data!( test_rsa_pss_sha384_salt48, "ours/rsa-pss-sha384-salt48.pem", Ok(()) ); test_verify_signed_data!( test_rsa_pss_sha512_salt64, "ours/rsa-pss-sha512-salt64.pem", Ok(()) ); test_verify_signed_data!( test_rsa_pss_sha256_salt32_corrupted_data, "ours/rsa-pss-sha256-salt32-corrupted-data.pem", Err(Error::InvalidSignatureForPublicKey) ); test_verify_signed_data!( test_rsa_pss_sha384_salt48_corrupted_data, "ours/rsa-pss-sha384-salt48-corrupted-data.pem", Err(Error::InvalidSignatureForPublicKey) ); test_verify_signed_data!( test_rsa_pss_sha512_salt64_corrupted_data, "ours/rsa-pss-sha512-salt64-corrupted-data.pem", Err(Error::InvalidSignatureForPublicKey) ); test_verify_signed_data!( test_rsa_using_ec_key, "rsa-using-ec-key.pem", Err(Error::UnsupportedSignatureAlgorithmForPublicKey) ); test_verify_signed_data!( test_rsa2048_pkcs1_sha512, "rsa2048-pkcs1-sha512.pem", Ok(()) ); struct TestSignedData { spki: Vec, data: Vec, algorithm: Vec, signature: Vec, } fn parse_test_signed_data(file_name: &str) -> TestSignedData { let path = std::path::PathBuf::from("third-party/chromium/data/verify_signed_data") .join(file_name); let file = std::fs::File::open(path).unwrap(); let mut lines = std::io::BufReader::new(&file).lines(); let spki = read_pem_section(&mut lines, "PUBLIC KEY"); let algorithm = read_pem_section(&mut lines, "ALGORITHM"); let data = read_pem_section(&mut lines, "DATA"); let signature = read_pem_section(&mut lines, "SIGNATURE"); TestSignedData { spki, data, algorithm, signature, } } type FileLines<'a> = std::io::Lines>; fn read_pem_section(lines: &mut FileLines, section_name: &str) -> Vec { // Skip comments and header let begin_section = format!("-----BEGIN {}-----", section_name); loop { let line = lines.next().unwrap().unwrap(); if line == begin_section { break; } } let mut base64 = String::new(); let end_section = format!("-----END {}-----", section_name); loop { let line = lines.next().unwrap().unwrap(); if line == end_section { break; } base64.push_str(&line); } base64::decode(&base64).unwrap() } static SUPPORTED_ALGORITHMS_IN_TESTS: &[&signed_data::SignatureAlgorithm] = &[ // Reasonable algorithms. &signed_data::RSA_PKCS1_2048_8192_SHA256, &signed_data::ECDSA_P256_SHA256, &signed_data::ECDSA_P384_SHA384, &signed_data::RSA_PKCS1_2048_8192_SHA384, &signed_data::RSA_PKCS1_2048_8192_SHA512, &signed_data::RSA_PKCS1_3072_8192_SHA384, &signed_data::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, &signed_data::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, &signed_data::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, &signed_data::ED25519, // Algorithms deprecated because they are annoying (P-521) or because // they are nonsensical combinations. &signed_data::ECDSA_P256_SHA384, // Truncates digest. &signed_data::ECDSA_P384_SHA256, // Digest is unnecessarily short. ]; } webpki-0.21.0/src/time.rs000064400000000000000000000045511351327563400133520ustar0000000000000000// Copyright 2015-2016 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. //! Conversions into the library's time type. #[cfg(feature = "std")] use {ring, std}; /// The time type. /// /// Internally this is merely a UNIX timestamp: a count of non-leap /// seconds since the start of 1970. This type exists to assist /// unit-of-measure correctness. #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub struct Time(u64); impl Time { /// Create a `webpki::Time` from a `std::time::SystemTime`. /// /// This will be replaced with a real `TryFrom` /// implementation when `TryFrom` is added to Rust Stable. /// /// # Example: /// /// Construct a `webpki::Time` from the current system time: /// /// ``` /// # extern crate ring; /// # extern crate webpki; /// # /// #[cfg(feature = "std")] /// # fn foo() -> Result<(), ring::error::Unspecified> { /// let time = webpki::Time::try_from(std::time::SystemTime::now())?; /// # Ok(()) /// # } /// ``` #[cfg(feature = "std")] pub fn try_from(time: std::time::SystemTime) -> Result { time.duration_since(std::time::UNIX_EPOCH) .map(|d| Time::from_seconds_since_unix_epoch(d.as_secs())) .map_err(|_| ring::error::Unspecified) } /// Create a `webpki::Time` from a unix timestamp. /// /// It is usually better to use the less error-prone /// `webpki::Time::try_from(time: &std::time::SystemTime)` instead when /// `std::time::SystemTime` is available (when `#![no_std]` isn't being /// used). pub fn from_seconds_since_unix_epoch(secs: u64) -> Time { Time(secs) } } webpki-0.21.0/src/trust_anchor_util.rs000064400000000000000000000121271351327572700161650ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. //! Utilities for efficiently embedding trust anchors in programs. use super::der; use crate::{ cert::{certificate_serial_number, parse_cert_internal, Cert, EndEntityOrCA}, Error, TrustAnchor, }; /// Interprets the given DER-encoded certificate as a `TrustAnchor`. The /// certificate is not validated. In particular, there is no check that the /// certificate is self-signed or even that the certificate has the cA basic /// constraint. pub fn cert_der_as_trust_anchor(cert_der: &[u8]) -> Result { let cert_der = untrusted::Input::from(cert_der); // XXX: `EndEntityOrCA::EndEntity` is used instead of `EndEntityOrCA::CA` // because we don't have a reference to a child cert, which is needed for // `EndEntityOrCA::CA`. For this purpose, it doesn't matter. // // v1 certificates will result in `Error::BadDER` because `parse_cert` will // expect a version field that isn't there. In that case, try to parse the // certificate using a special parser for v1 certificates. Notably, that // parser doesn't allow extensions, so there's no need to worry about // embedded name constraints in a v1 certificate. match parse_cert_internal( cert_der, EndEntityOrCA::EndEntity, possibly_invalid_certificate_serial_number, ) { Ok(cert) => Ok(trust_anchor_from_cert(cert)), Err(Error::BadDER) => parse_cert_v1(cert_der).or(Err(Error::BadDER)), Err(err) => Err(err), } } fn possibly_invalid_certificate_serial_number<'a>( input: &mut untrusted::Reader<'a>, ) -> Result<(), Error> { // https://tools.ietf.org/html/rfc5280#section-4.1.2.2: // * Conforming CAs MUST NOT use serialNumber values longer than 20 octets." // * "The serial number MUST be a positive integer [...]" // // However, we don't enforce these constraints on trust anchors, as there // are widely-deployed trust anchors that violate these constraints. skip(input, der::Tag::Integer) } /// Generates code for hard-coding the given trust anchors into a program. This /// is designed to be used in a build script. `name` is the name of the public /// static variable that will contain the TrustAnchor array. pub fn generate_code_for_trust_anchors(name: &str, trust_anchors: &[TrustAnchor]) -> String { let decl = format!( "static {}: [TrustAnchor<'static>; {}] = ", name, trust_anchors.len() ); // "{:?}" formats the array of trust anchors as Rust code, approximately, // except that it drops the leading "&" on slices. let value = str::replace(&format!("{:?};\n", trust_anchors), ": [", ": &["); decl + &value } fn trust_anchor_from_cert<'a>(cert: Cert<'a>) -> TrustAnchor<'a> { TrustAnchor { subject: cert.subject.as_slice_less_safe(), spki: cert.spki.as_slice_less_safe(), name_constraints: cert.name_constraints.map(|nc| nc.as_slice_less_safe()), } } /// Parses a v1 certificate directly into a TrustAnchor. fn parse_cert_v1<'a>(cert_der: untrusted::Input<'a>) -> Result, Error> { // X.509 Certificate: https://tools.ietf.org/html/rfc5280#section-4.1. cert_der.read_all(Error::BadDER, |cert_der| { der::nested(cert_der, der::Tag::Sequence, Error::BadDER, |cert_der| { let anchor = der::nested(cert_der, der::Tag::Sequence, Error::BadDER, |tbs| { // The version number field does not appear in v1 certificates. certificate_serial_number(tbs)?; skip(tbs, der::Tag::Sequence)?; // signature. skip(tbs, der::Tag::Sequence)?; // issuer. skip(tbs, der::Tag::Sequence)?; // validity. let subject = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?; let spki = der::expect_tag_and_get_value(tbs, der::Tag::Sequence)?; Ok(TrustAnchor { subject: subject.as_slice_less_safe(), spki: spki.as_slice_less_safe(), name_constraints: None, }) }); // read and discard signatureAlgorithm + signature skip(cert_der, der::Tag::Sequence)?; skip(cert_der, der::Tag::BitString)?; anchor }) }) } fn skip(input: &mut untrusted::Reader, tag: der::Tag) -> Result<(), Error> { der::expect_tag_and_get_value(input, tag).map(|_| ()) } webpki-0.21.0/src/verify_cert.rs000064400000000000000000000256331351327572700147440ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use crate::{ cert::{self, Cert, EndEntityOrCA}, der, name, signed_data, time, Error, SignatureAlgorithm, TrustAnchor, }; pub fn build_chain( required_eku_if_present: KeyPurposeId, supported_sig_algs: &[&SignatureAlgorithm], trust_anchors: &[TrustAnchor], intermediate_certs: &[&[u8]], cert: &Cert, time: time::Time, sub_ca_count: usize, ) -> Result<(), Error> { let used_as_ca = used_as_ca(&cert.ee_or_ca); check_issuer_independent_properties( cert, time, used_as_ca, sub_ca_count, required_eku_if_present, )?; // TODO: HPKP checks. match used_as_ca { UsedAsCA::Yes => { const MAX_SUB_CA_COUNT: usize = 6; if sub_ca_count >= MAX_SUB_CA_COUNT { return Err(Error::UnknownIssuer); } }, UsedAsCA::No => { assert_eq!(0, sub_ca_count); }, } // TODO: revocation. match loop_while_non_fatal_error(trust_anchors, |trust_anchor: &TrustAnchor| { let trust_anchor_subject = untrusted::Input::from(trust_anchor.subject); if cert.issuer != trust_anchor_subject { return Err(Error::UnknownIssuer); } let name_constraints = trust_anchor.name_constraints.map(untrusted::Input::from); untrusted::read_all_optional(name_constraints, Error::BadDER, |value| { name::check_name_constraints(value, &cert) })?; let trust_anchor_spki = untrusted::Input::from(trust_anchor.spki); // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?; check_signatures(supported_sig_algs, cert, trust_anchor_spki)?; Ok(()) }) { Ok(()) => { return Ok(()); }, Err(..) => { // If the error is not fatal, then keep going. }, } loop_while_non_fatal_error(intermediate_certs, |cert_der| { let potential_issuer = cert::parse_cert(untrusted::Input::from(*cert_der), EndEntityOrCA::CA(&cert))?; if potential_issuer.subject != cert.issuer { return Err(Error::UnknownIssuer); } // Prevent loops; see RFC 4158 section 5.2. let mut prev = cert; loop { if potential_issuer.spki == prev.spki && potential_issuer.subject == prev.subject { return Err(Error::UnknownIssuer); } match &prev.ee_or_ca { &EndEntityOrCA::EndEntity => { break; }, &EndEntityOrCA::CA(child_cert) => { prev = child_cert; }, } } untrusted::read_all_optional(potential_issuer.name_constraints, Error::BadDER, |value| { name::check_name_constraints(value, &cert) })?; let next_sub_ca_count = match used_as_ca { UsedAsCA::No => sub_ca_count, UsedAsCA::Yes => sub_ca_count + 1, }; build_chain( required_eku_if_present, supported_sig_algs, trust_anchors, intermediate_certs, &potential_issuer, time, next_sub_ca_count, ) }) } fn check_signatures( supported_sig_algs: &[&SignatureAlgorithm], cert_chain: &Cert, trust_anchor_key: untrusted::Input, ) -> Result<(), Error> { let mut spki_value = trust_anchor_key; let mut cert = cert_chain; loop { signed_data::verify_signed_data(supported_sig_algs, spki_value, &cert.signed_data)?; // TODO: check revocation match &cert.ee_or_ca { &EndEntityOrCA::CA(child_cert) => { spki_value = cert.spki; cert = child_cert; }, &EndEntityOrCA::EndEntity => { break; }, } } Ok(()) } fn check_issuer_independent_properties( cert: &Cert, time: time::Time, used_as_ca: UsedAsCA, sub_ca_count: usize, required_eku_if_present: KeyPurposeId, ) -> Result<(), Error> { // TODO: check_distrust(trust_anchor_subject, trust_anchor_spki)?; // TODO: Check signature algorithm like mozilla::pkix. // TODO: Check SPKI like mozilla::pkix. // TODO: check for active distrust like mozilla::pkix. // See the comment in `remember_extension` for why we don't check the // KeyUsage extension. cert.validity .read_all(Error::BadDER, |value| check_validity(value, time))?; untrusted::read_all_optional(cert.basic_constraints, Error::BadDER, |value| { check_basic_constraints(value, used_as_ca, sub_ca_count) })?; untrusted::read_all_optional(cert.eku, Error::BadDER, |value| { check_eku(value, required_eku_if_present) })?; Ok(()) } // https://tools.ietf.org/html/rfc5280#section-4.1.2.5 fn check_validity(input: &mut untrusted::Reader, time: time::Time) -> Result<(), Error> { let not_before = der::time_choice(input)?; let not_after = der::time_choice(input)?; if not_before > not_after { return Err(Error::InvalidCertValidity); } if time < not_before { return Err(Error::CertNotValidYet); } if time > not_after { return Err(Error::CertExpired); } // TODO: mozilla::pkix allows the TrustDomain to check not_before and // not_after, to enforce things like a maximum validity period. We should // do something similar. Ok(()) } #[derive(Clone, Copy)] enum UsedAsCA { Yes, No, } fn used_as_ca(ee_or_ca: &EndEntityOrCA) -> UsedAsCA { match ee_or_ca { &EndEntityOrCA::EndEntity => UsedAsCA::No, &EndEntityOrCA::CA(..) => UsedAsCA::Yes, } } // https://tools.ietf.org/html/rfc5280#section-4.2.1.9 fn check_basic_constraints( input: Option<&mut untrusted::Reader>, used_as_ca: UsedAsCA, sub_ca_count: usize, ) -> Result<(), Error> { let (is_ca, path_len_constraint) = match input { Some(input) => { let is_ca = der::optional_boolean(input)?; // https://bugzilla.mozilla.org/show_bug.cgi?id=985025: RFC 5280 // says that a certificate must not have pathLenConstraint unless // it is a CA certificate, but some real-world end-entity // certificates have pathLenConstraint. let path_len_constraint = if !input.at_end() { let value = der::small_nonnegative_integer(input)?; Some(value as usize) } else { None }; (is_ca, path_len_constraint) }, None => (false, None), }; match (used_as_ca, is_ca, path_len_constraint) { (UsedAsCA::No, true, _) => Err(Error::CAUsedAsEndEntity), (UsedAsCA::Yes, false, _) => Err(Error::EndEntityUsedAsCA), (UsedAsCA::Yes, true, Some(len)) if sub_ca_count > len => Err(Error::PathLenConstraintViolated), _ => Ok(()), } } #[derive(Clone, Copy)] pub struct KeyPurposeId { oid_value: untrusted::Input<'static>, } // id-pkix OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7 } // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } pub static EKU_SERVER_AUTH: KeyPurposeId = KeyPurposeId { oid_value: untrusted::Input::from(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 1]), }; // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } pub static EKU_CLIENT_AUTH: KeyPurposeId = KeyPurposeId { oid_value: untrusted::Input::from(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 2]), }; // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } pub static EKU_OCSP_SIGNING: KeyPurposeId = KeyPurposeId { oid_value: untrusted::Input::from(&[(40 * 1) + 3, 6, 1, 5, 5, 7, 3, 9]), }; // https://tools.ietf.org/html/rfc5280#section-4.2.1.12 // // Notable Differences from RFC 5280: // // * We follow the convention established by Microsoft's implementation and // mozilla::pkix of treating the EKU extension in a CA certificate as a // restriction on the allowable EKUs for certificates issued by that CA. RFC // 5280 doesn't prescribe any meaning to the EKU extension when a certificate // is being used as a CA certificate. // // * We do not recognize anyExtendedKeyUsage. NSS and mozilla::pkix do not // recognize it either. // // * We treat id-Netscape-stepUp as being equivalent to id-kp-serverAuth in CA // certificates (only). Comodo has issued certificates that require this // behavior that don't expire until June 2020. See https://bugzilla.mozilla.org/show_bug.cgi?id=982292. fn check_eku( input: Option<&mut untrusted::Reader>, required_eku_if_present: KeyPurposeId, ) -> Result<(), Error> { match input { Some(input) => { loop { let value = der::expect_tag_and_get_value(input, der::Tag::OID)?; if value == required_eku_if_present.oid_value { input.skip_to_end(); break; } if input.at_end() { return Err(Error::RequiredEKUNotFound); } } Ok(()) }, None => { // http://tools.ietf.org/html/rfc6960#section-4.2.2.2: // "OCSP signing delegation SHALL be designated by the inclusion of // id-kp-OCSPSigning in an extended key usage certificate extension // included in the OCSP response signer's certificate." // // A missing EKU extension generally means "any EKU", but it is // important that id-kp-OCSPSigning is explicit so that a normal // end-entity certificate isn't able to sign trusted OCSP responses // for itself or for other certificates issued by its issuing CA. if required_eku_if_present.oid_value == EKU_OCSP_SIGNING.oid_value { return Err(Error::RequiredEKUNotFound); } Ok(()) }, } } fn loop_while_non_fatal_error(values: V, f: F) -> Result<(), Error> where V: IntoIterator, F: Fn(V::Item) -> Result<(), Error>, { for v in values { match f(v) { Ok(()) => { return Ok(()); }, Err(..) => { // If the error is not fatal, then keep going. }, } } Err(Error::UnknownIssuer) } webpki-0.21.0/src/webpki.rs000064400000000000000000000255221351327572700137010ustar0000000000000000// Copyright 2015 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. //! webpki: Web PKI X.509 Certificate Validation. //! //! git clone https://github.com/briansmith/webpki //! //! See `EndEntityCert`'s documentation for a description of the certificate //! processing steps necessary for a TLS connection. #![doc(html_root_url = "https://briansmith.org/rustdoc/")] #![cfg_attr(not(feature = "std"), no_std)] #![allow(missing_debug_implementations)] // `#[derive(...)]` uses `#[allow(unused_qualifications)]` internally. #![deny(unused_qualifications)] #![forbid( anonymous_parameters, box_pointers, missing_copy_implementations, missing_docs, trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates, unused_import_braces, unused_results, variant_size_differences, warnings )] #[cfg(all(test, not(feature = "std")))] #[macro_use] extern crate std; #[macro_use] mod der; mod calendar; mod cert; mod error; mod name; mod signed_data; mod time; #[cfg(feature = "trust_anchor_util")] pub mod trust_anchor_util; mod verify_cert; pub use error::Error; pub use name::{DNSNameRef, InvalidDNSNameError}; #[cfg(feature = "std")] pub use name::DNSName; pub use signed_data::{ SignatureAlgorithm, ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, ECDSA_P384_SHA384, ED25519, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_2048_8192_SHA384, RSA_PKCS1_2048_8192_SHA512, RSA_PKCS1_3072_8192_SHA384, RSA_PSS_2048_8192_SHA256_LEGACY_KEY, RSA_PSS_2048_8192_SHA384_LEGACY_KEY, RSA_PSS_2048_8192_SHA512_LEGACY_KEY, }; pub use time::Time; /// An end-entity certificate. /// /// Server certificate processing in a TLS connection consists of several /// steps. All of these steps are necessary: /// /// * `EndEntityCert.verify_is_valid_tls_server_cert`: Verify that the server's /// certificate is currently valid *for use by a TLS server*. /// * `EndEntityCert.verify_is_valid_for_dns_name`: Verify that the server's /// certificate is valid for the host that is being connected to. /// * `EndEntityCert.verify_signature`: Verify that the signature of server's /// `ServerKeyExchange` message is valid for the server's certificate. /// /// Client certificate processing in a TLS connection consists of analogous /// steps. All of these steps are necessary: /// /// * `EndEntityCert.verify_is_valid_tls_client_cert`: Verify that the client's /// certificate is currently valid *for use by a TLS client*. /// * `EndEntityCert.verify_is_valid_for_dns_name` or /// `EndEntityCert.verify_is_valid_for_at_least_one_dns_name`: Verify that the /// client's certificate is valid for the identity or identities used to /// identify the client. (Currently client authentication only works when the /// client is identified by one or more DNS hostnames.) /// * `EndEntityCert.verify_signature`: Verify that the client's signature in /// its `CertificateVerify` message is valid using the public key from the /// client's certificate. /// /// Although it would be less error-prone to combine all these steps into a /// single function call, some significant optimizations are possible if the /// three steps are processed separately (in parallel). It does not matter much /// which order the steps are done in, but **all of these steps must completed /// before application data is sent and before received application data is /// processed**. `EndEntityCert::from` is an inexpensive operation and is /// deterministic, so if these tasks are done in multiple threads, it is /// probably best to just call `EndEntityCert::from` multiple times (before each /// operation) for the same DER-encoded ASN.1 certificate bytes. pub struct EndEntityCert<'a> { inner: cert::Cert<'a>, } impl<'a> EndEntityCert<'a> { /// Parse the ASN.1 DER-encoded X.509 encoding of the certificate /// `cert_der`. pub fn from(cert_der: &'a [u8]) -> Result { Ok(Self { inner: cert::parse_cert( untrusted::Input::from(cert_der), cert::EndEntityOrCA::EndEntity, )?, }) } /// Verifies that the end-entity certificate is valid for use by a TLS /// server. /// /// `supported_sig_algs` is the list of signature algorithms that are /// trusted for use in certificate signatures; the end-entity certificate's /// public key is not validated against this list. `trust_anchors` is the /// list of root CAs to trust. `intermediate_certs` is the sequence of /// intermediate certificates that the server sent in the TLS handshake. /// `time` is the time for which the validation is effective (usually the /// current time). pub fn verify_is_valid_tls_server_cert( &self, supported_sig_algs: &[&SignatureAlgorithm], &TLSServerTrustAnchors(trust_anchors): &TLSServerTrustAnchors, intermediate_certs: &[&[u8]], time: Time, ) -> Result<(), Error> { verify_cert::build_chain( verify_cert::EKU_SERVER_AUTH, supported_sig_algs, trust_anchors, intermediate_certs, &self.inner, time, 0, ) } /// Verifies that the end-entity certificate is valid for use by a TLS /// client. /// /// If the certificate is not valid for any of the given names then this /// fails with `Error::CertNotValidForName`. /// /// `supported_sig_algs` is the list of signature algorithms that are /// trusted for use in certificate signatures; the end-entity certificate's /// public key is not validated against this list. `trust_anchors` is the /// list of root CAs to trust. `intermediate_certs` is the sequence of /// intermediate certificates that the client sent in the TLS handshake. /// `cert` is the purported end-entity certificate of the client. `time` is /// the time for which the validation is effective (usually the current /// time). pub fn verify_is_valid_tls_client_cert( &self, supported_sig_algs: &[&SignatureAlgorithm], &TLSClientTrustAnchors(trust_anchors): &TLSClientTrustAnchors, intermediate_certs: &[&[u8]], time: Time, ) -> Result<(), Error> { verify_cert::build_chain( verify_cert::EKU_CLIENT_AUTH, supported_sig_algs, trust_anchors, intermediate_certs, &self.inner, time, 0, ) } /// Verifies that the certificate is valid for the given DNS host name. pub fn verify_is_valid_for_dns_name(&self, dns_name: DNSNameRef) -> Result<(), Error> { name::verify_cert_dns_name(&self, dns_name) } /// Verifies that the certificate is valid for at least one of the given DNS /// host names. /// /// If the certificate is not valid for any of the given names then this /// fails with `Error::CertNotValidForName`. Otherwise the DNS names for /// which the certificate is valid are returned. /// /// Requires the `std` default feature; i.e. this isn't available in /// `#![no_std]` configurations. #[cfg(feature = "std")] pub fn verify_is_valid_for_at_least_one_dns_name<'names, Names>( &self, dns_names: Names, ) -> Result>, Error> where Names: Iterator>, { let result: Vec> = dns_names .filter(|n| self.verify_is_valid_for_dns_name(*n).is_ok()) .collect(); if result.is_empty() { return Err(Error::CertNotValidForName); } Ok(result) } /// Verifies the signature `signature` of message `msg` using the /// certificate's public key. /// /// `signature_alg` is the algorithm to use to /// verify the signature; the certificate's public key is verified to be /// compatible with this algorithm. /// /// For TLS 1.2, `signature` corresponds to TLS's /// `DigitallySigned.signature` and `signature_alg` corresponds to TLS's /// `DigitallySigned.algorithm` of TLS type `SignatureAndHashAlgorithm`. In /// TLS 1.2 a single `SignatureAndHashAlgorithm` may map to multiple /// `SignatureAlgorithm`s. For example, a TLS 1.2 /// `ignatureAndHashAlgorithm` of (ECDSA, SHA-256) may map to any or all /// of {`ECDSA_P256_SHA256`, `ECDSA_P384_SHA256`}, depending on how the TLS /// implementation is configured. /// /// For current TLS 1.3 drafts, `signature_alg` corresponds to TLS's /// `algorithm` fields of type `SignatureScheme`. There is (currently) a /// one-to-one correspondence between TLS 1.3's `SignatureScheme` and /// `SignatureAlgorithm`. pub fn verify_signature( &self, signature_alg: &SignatureAlgorithm, msg: &[u8], signature: &[u8], ) -> Result<(), Error> { signed_data::verify_signature( signature_alg, self.inner.spki, untrusted::Input::from(msg), untrusted::Input::from(signature), ) } } /// A trust anchor (a.k.a. root CA). /// /// Traditionally, certificate verification libraries have represented trust /// anchors as full X.509 root certificates. However, those certificates /// contain a lot more data than is needed for verifying certificates. The /// `TrustAnchor` representation allows an application to store just the /// essential elements of trust anchors. The `webpki::trust_anchor_util` module /// provides functions for converting X.509 certificates to to the minimized /// `TrustAnchor` representation, either at runtime or in a build script. #[derive(Debug)] pub struct TrustAnchor<'a> { /// The value of the `subject` field of the trust anchor. pub subject: &'a [u8], /// The value of the `subjectPublicKeyInfo` field of the trust anchor. pub spki: &'a [u8], /// The value of a DER-encoded NameConstraints, containing name /// constraints to apply to the trust anchor, if any. pub name_constraints: Option<&'a [u8]>, } /// Trust anchors which may be used for authenticating servers. #[derive(Debug)] pub struct TLSServerTrustAnchors<'a>(pub &'a [TrustAnchor<'a>]); /// Trust anchors which may be used for authenticating clients. #[derive(Debug)] pub struct TLSClientTrustAnchors<'a>(pub &'a [TrustAnchor<'a>]); webpki-0.21.0/tests/dns_name_tests.rs000064400000000000000000000277751351327563400160120ustar0000000000000000// Copyright 2014-2017 Brian Smith. use webpki; // (name, is_valid) static DNS_NAME_VALIDITY: &[(&[u8], bool)] = &[ (b"a", true), (b"a.b", true), (b"a.b.c", true), (b"a.b.c.d", true), // Hyphens, one component. (b"-", false), (b"-a", false), (b"a-", false), (b"a-b", true), // Hyphens, last component. (b"a.-", false), (b"a.-a", false), (b"a.a-", false), (b"a.a-b", true), // Hyphens, not last component. (b"-.a", false), (b"-a.a", false), (b"a-.a", false), (b"a-b.a", true), // Underscores, one component. (b"_", true), // TODO: Perhaps this should be rejected for '_' being sole character?. (b"_a", true), // TODO: Perhaps this should be rejected for '_' being 1st? (b"a_", true), (b"a_b", true), // Underscores, last component. (b"a._", true), // TODO: Perhaps this should be rejected for '_' being sole character?. (b"a._a", true), // TODO: Perhaps this should be rejected for '_' being 1st? (b"a.a_", true), (b"a.a_b", true), // Underscores, not last component. (b"_.a", true), // TODO: Perhaps this should be rejected for '_' being sole character?. (b"_a.a", true), (b"a_.a", true), (b"a_b.a", true), // empty labels (b"", false), (b".", false), (b"a", true), (b".a", false), (b".a.b", false), (b"..a", false), (b"a..b", false), (b"a...b", false), (b"a..b.c", false), (b"a.b..c", false), (b".a.b.c.", false), // absolute names (b"a.", true), (b"a.b.", true), (b"a.b.c.", true), // absolute names with empty label at end (b"a..", false), (b"a.b..", false), (b"a.b.c..", false), (b"a...", false), // Punycode (b"xn--", false), (b"xn--.", false), (b"xn--.a", false), (b"a.xn--", false), (b"a.xn--.", false), (b"a.xn--.b", false), (b"a.xn--.b", false), (b"a.xn--\0.b", false), (b"a.xn--a.b", true), (b"xn--a", true), (b"a.xn--a", true), (b"a.xn--a.a", true), (b"\xc4\x95.com", false), // UTF-8 ĕ (b"xn--jea.com", true), // punycode ĕ (b"xn--\xc4\x95.com", false), // UTF-8 ĕ, malformed punycode + UTF-8 mashup // Surprising punycode (b"xn--google.com", true), // 䕮䕵䕶䕱.com (b"xn--citibank.com", true), // 岍岊岊岅岉岎.com (b"xn--cnn.com", true), // 䁾.com (b"a.xn--cnn", true), // a.䁾 (b"a.xn--cnn.com", true), // a.䁾.com (b"1.2.3.4", false), // IPv4 address (b"1::2", false), // IPV6 address // whitespace not allowed anywhere. (b" ", false), (b" a", false), (b"a ", false), (b"a b", false), (b"a.b 1", false), (b"a\t", false), // Nulls not allowed (b"\0", false), (b"a\0", false), (b"example.org\0.example.com", false), // Hi Moxie! (b"\0a", false), (b"xn--\0", false), // Allowed character set (b"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z", true), (b"A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z", true), (b"0.1.2.3.4.5.6.7.8.9.a", true), // "a" needed to avoid numeric last label (b"a-b", true), // hyphen (a label cannot start or end with a hyphen) // An invalid character in various positions (b"!", false), (b"!a", false), (b"a!", false), (b"a!b", false), (b"a.!", false), (b"a.a!", false), (b"a.!a", false), (b"a.a!a", false), (b"a.!a.a", false), (b"a.a!.a", false), (b"a.a!a.a", false), // Various other invalid characters (b"a!", false), (b"a@", false), (b"a#", false), (b"a$", false), (b"a%", false), (b"a^", false), (b"a&", false), (b"a*", false), (b"a(", false), (b"a)", false), // last label can't be fully numeric (b"1", false), (b"a.1", false), // other labels can be fully numeric (b"1.a", true), (b"1.2.a", true), (b"1.2.3.a", true), // last label can be *partly* numeric (b"1a", true), (b"1.1a", true), (b"1-1", true), (b"a.1-1", true), (b"a.1-a", true), // labels cannot start with a hyphen (b"-", false), (b"-1", false), // labels cannot end with a hyphen (b"1-", false), (b"1-.a", false), (b"a-", false), (b"a-.a", false), (b"a.1-.a", false), (b"a.a-.a", false), // labels can contain a hyphen in the middle (b"a-b", true), (b"1-2", true), (b"a.a-1", true), // multiple consecutive hyphens allowed (b"a--1", true), (b"1---a", true), (b"a-----------------b", true), // Wildcard specifications are not valid reference names. (b"*.a", false), (b"a*", false), (b"a*.", false), (b"a*.a", false), (b"a*.a.", false), (b"*.a.b", false), (b"*.a.b.", false), (b"a*.b.c", false), (b"*.a.b.c", false), (b"a*.b.c.d", false), // Multiple wildcards. (b"a**.b.c", false), (b"a*b*.c.d", false), (b"a*.b*.c", false), // Wildcards not in the first label. (b"a.*", false), (b"a.*.b", false), (b"a.b.*", false), (b"a.b*.c", false), (b"*.b*.c", false), (b".*.a.b", false), (b".a*.b.c", false), // Wildcards not at the end of the first label. (b"*a.b.c", false), (b"a*b.c.d", false), // Wildcards and IDNA prefix. (b"x*.a.b", false), (b"xn*.a.b", false), (b"xn-*.a.b", false), (b"xn--*.a.b", false), (b"xn--w*.a.b", false), // Redacted labels from RFC6962bis draft 4 // https://tools.ietf.org/html/draft-ietf-trans-rfc6962-bis-04#section-3.2.2 (b"(PRIVATE).foo", false), // maximum label length is 63 characters (b"123456789012345678901234567890123456789012345678901234567890abc", true), (b"123456789012345678901234567890123456789012345678901234567890abcd", false), // maximum total length is 253 characters (b"12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678a", true), (b"12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.12345678901234567890123456789012345678901234567890.1234567890123456789012345678901234567890123456789a", false), ]; // (IP address, is valid DNS name). The comments here refer to the validity of // the string as an IP address, not as a DNS name validity. static IP_ADDRESS_DNS_VALIDITY: &[(&[u8], bool)] = &[ (b"", false), (b"1", false), (b"1.2", false), (b"1.2.3", false), (b"1.2.3.4", false), (b"1.2.3.4.5", false), (b"1.2.3.4a", true), // a DNSName! (b"a.2.3.4", false), // not even a DNSName! (b"1::2", false), // IPv6 address // Whitespace not allowed (b" 1.2.3.4", false), (b"1.2.3.4 ", false), (b"1 .2.3.4", false), (b"\n1.2.3.4", false), (b"1.2.3.4\n", false), // Nulls not allowed (b"\0", false), (b"\01.2.3.4", false), (b"1.2.3.4\0", false), (b"1.2.3.4\0.5", false), // Range (b"0.0.0.0", false), (b"255.255.255.255", false), (b"256.0.0.0", false), (b"0.256.0.0", false), (b"0.0.256.0", false), (b"0.0.0.256", false), (b"999.0.0.0", false), (b"9999999999999999999.0.0.0", false), // All digits allowed (b"0.1.2.3", false), (b"4.5.6.7", false), (b"8.9.0.1", false), // Leading zeros not allowed (b"01.2.3.4", false), (b"001.2.3.4", false), (b"00000000001.2.3.4", false), (b"010.2.3.4", false), (b"1.02.3.4", false), (b"1.2.03.4", false), (b"1.2.3.04", false), // Empty components (b".2.3.4", false), (b"1..3.4", false), (b"1.2..4", false), (b"1.2.3.", false), // Too many components (b"1.2.3.4.5", false), (b"1.2.3.4.5.6", false), (b"0.1.2.3.4", false), (b"1.2.3.4.0", false), // Leading/trailing dot (b".1.2.3.4", false), (b"1.2.3.4.", false), // Other common forms of IPv4 address // http://en.wikipedia.org/wiki/IPv4#Address_representations (b"192.0.2.235", false), // dotted decimal (control value) (b"0xC0.0x00.0x02.0xEB", true), // dotted hex - actually a DNS name! (b"0301.0000.0002.0353", false), // dotted octal (b"0xC00002EB", true), // non-dotted hex, actually a DNS name! (b"3221226219", false), // non-dotted decimal (b"030000001353", false), // non-dotted octal (b"192.0.0002.0xEB", true), // mixed, actually a DNS name! (b"1234", false), (b"1234:5678", false), (b"1234:5678:9abc", false), (b"1234:5678:9abc:def0", false), (b"1234:5678:9abc:def0:1234:", false), (b"1234:5678:9abc:def0:1234:5678:", false), (b"1234:5678:9abc:def0:1234:5678:9abc:", false), (b"1234:5678:9abc:def0:1234:5678:9abc:def0", false), (b"1234:5678:9abc:def0:1234:5678:9abc:def0:", false), (b":1234:5678:9abc:def0:1234:5678:9abc:def0", false), (b"1234:5678:9abc:def0:1234:5678:9abc:def0:0000", false), // Valid contractions (b"::1", false), (b"::1234", false), (b"1234::", false), (b"1234::5678", false), (b"1234:5678::abcd", false), (b"1234:5678:9abc:def0:1234:5678:9abc::", false), // Contraction in full IPv6 addresses not allowed (b"::1234:5678:9abc:def0:1234:5678:9abc:def0", false), // start (b"1234:5678:9abc:def0:1234:5678:9abc:def0::", false), // end (b"1234:5678::9abc:def0:1234:5678:9abc:def0", false), // interior // Multiple contractions not allowed (b"::1::", false), (b"::1::2", false), (b"1::2::", false), // Colon madness! (b":", false), (b"::", false), (b":::", false), (b"::::", false), (b":::1", false), (b"::::1", false), (b"1:::2", false), (b"1::::2", false), (b"1:2:::", false), (b"1:2::::", false), (b"::1234:", false), (b":1234::", false), (b"01234::", false), // too many digits, even if zero (b"12345678::", false), // too many digits or missing colon // uppercase (b"ABCD:EFAB::", false), // miXeD CAse (b"aBcd:eFAb::", false), // IPv4-style (b"::2.3.4.5", false), (b"1234::2.3.4.5", false), (b"::abcd:2.3.4.5", false), (b"1234:5678:9abc:def0:1234:5678:252.253.254.255", false), (b"1234:5678:9abc:def0:1234::252.253.254.255", false), (b"1234::252.253.254", false), (b"::252.253.254", false), (b"::252.253.254.300", false), (b"1234::252.253.254.255:", false), (b"1234::252.253.254.255:5678", false), // Contractions that don't contract (b"::1234:5678:9abc:def0:1234:5678:9abc:def0", false), (b"1234:5678:9abc:def0:1234:5678:9abc:def0::", false), (b"1234:5678:9abc:def0::1234:5678:9abc:def0", false), (b"1234:5678:9abc:def0:1234:5678::252.253.254.255", false), // With and without leading zeros (b"::123", false), (b"::0123", false), (b"::012", false), (b"::0012", false), (b"::01", false), (b"::001", false), (b"::0001", false), (b"::0", false), (b"::00", false), (b"::000", false), (b"::0000", false), (b"::01234", false), (b"::00123", false), (b"::000123", false), // Trailing zero (b"::12340", false), // Whitespace (b" 1234:5678:9abc:def0:1234:5678:9abc:def0", false), (b"\t1234:5678:9abc:def0:1234:5678:9abc:def0", false), (b"\t1234:5678:9abc:def0:1234:5678:9abc:def0\n", false), (b"1234 :5678:9abc:def0:1234:5678:9abc:def0", false), (b"1234: 5678:9abc:def0:1234:5678:9abc:def0", false), (b":: 2.3.4.5", false), (b"1234::252.253.254.255 ", false), (b"1234::252.253.254.255\n", false), (b"1234::252.253. 254.255", false), // Nulls (b"\0", false), (b"::1\0:2", false), (b"::1\0", false), (b"::1.2.3.4\0", false), (b"::1.2\02.3.4", false), ]; #[test] fn dns_name_ref_try_from_ascii_test() { for &(s, is_valid) in DNS_NAME_VALIDITY .iter() .chain(IP_ADDRESS_DNS_VALIDITY.iter()) { assert_eq!( webpki::DNSNameRef::try_from_ascii(s).is_ok(), is_valid, "DNSNameRef::try_from_ascii_str failed for \"{:?}\"", s ); } } webpki-0.21.0/tests/integration.rs000064400000000000000000000070521351327572700153140ustar0000000000000000// Copyright 2016 Joseph Birr-Pixton. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #![deny(box_pointers)] #![forbid( anonymous_parameters, legacy_directory_ownership, missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features, unused_extern_crates, unused_import_braces, unused_qualifications, unused_results, variant_size_differences, warnings )] #[cfg(any(feature = "std", feature = "trust_anchor_util"))] extern crate webpki; #[cfg(feature = "trust_anchor_util")] static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[ &webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P256_SHA384, &webpki::ECDSA_P384_SHA256, &webpki::ECDSA_P384_SHA384, &webpki::RSA_PKCS1_2048_8192_SHA256, &webpki::RSA_PKCS1_2048_8192_SHA384, &webpki::RSA_PKCS1_2048_8192_SHA512, &webpki::RSA_PKCS1_3072_8192_SHA384, &webpki::ED25519, ]; /* Checks we can verify netflix's cert chain. This is notable * because they're rooted at a Verisign v1 root. */ #[allow(box_pointers)] #[cfg(feature = "trust_anchor_util")] #[test] pub fn netflix() { let ee = include_bytes!("netflix/ee.der"); let inter = include_bytes!("netflix/inter.der"); let ca = include_bytes!("netflix/ca.der"); let anchors = vec![webpki::trust_anchor_util::cert_der_as_trust_anchor(ca).unwrap()]; let anchors = webpki::TLSServerTrustAnchors(&anchors); let time = webpki::Time::from_seconds_since_unix_epoch(1492441716); let cert = webpki::EndEntityCert::from(ee).unwrap(); let _ = cert .verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[inter], time) .unwrap(); } #[cfg(feature = "trust_anchor_util")] #[test] pub fn ed25519() { let ee = include_bytes!("ed25519/ee.der"); let ca = include_bytes!("ed25519/ca.der"); let anchors = vec![webpki::trust_anchor_util::cert_der_as_trust_anchor(ca).unwrap()]; let anchors = webpki::TLSServerTrustAnchors(&anchors); let time = webpki::Time::from_seconds_since_unix_epoch(1547363522); let cert = webpki::EndEntityCert::from(ee).unwrap(); let _ = cert .verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[], time) .unwrap(); } #[cfg(feature = "trust_anchor_util")] #[test] fn read_root_with_zero_serial() { let ca = include_bytes!("misc/serial_zero.der"); let _ = webpki::trust_anchor_util::cert_der_as_trust_anchor(ca) .expect("godaddy cert should parse as anchor"); } #[cfg(feature = "trust_anchor_util")] #[test] fn read_root_with_neg_serial() { let ca = include_bytes!("misc/serial_neg.der"); let _ = webpki::trust_anchor_util::cert_der_as_trust_anchor(ca) .expect("idcat cert should parse as anchor"); } #[cfg(feature = "std")] #[test] fn time_constructor() { let _ = webpki::Time::try_from(std::time::SystemTime::now()).unwrap(); } webpki-0.21.0/tests/misc/serial_neg.der000064400000000000000000000025321314565023400161470ustar00000000000000000V0>+=!b0  *H 01 0 UES1;09U 2Agencia Catalana de Certificacio (NIF Q-0801176-I)1(0&U Serveis Publics de Certificacio1503U ,Vegeu https://www.catcert.net/verarrel (c)031503U ,Jerarquia Entitats de Certificacio Catalanes10 UEC-ACC0 030107230000Z 310107225959Z01 0 UES1;09U 2Agencia Catalana de Certificacio (NIF Q-0801176-I)1(0&U Serveis Publics de Certificacio1503U ,Vegeu https://www.catcert.net/verarrel (c)031503U ,Jerarquia Entitats de Certificacio Catalanes10 UEC-ACC0"0  *H 0 "OBG@s$QÒ@p`e"ClfD >9oKzcDcf(Bn'i_frOez>O `:BDz4ՙ^H~euB}Hd]Prv]BPyД>k kN*>̂e3w]=ȗzp|q-bm8?  uBp4" KА'00U0ec_acc@catcert.net0U00U0UËD7EZx]0U x0v0t +x 0e0,+ https://www.catcert.net/verarrel05+0)'Vegeu https://www.catcert.net/verarrel 0  *H H[MH9U5zSZq;9 ^[]}O͠A4↜7V)Ğ5ߊ !C骈5BcZ^H:oܝ?zaw pzٗ,dtz n x k/j+ň~ĻE'o7X&-r6N?e*n] :-؎_=\e8E``tArbbo_BQe#jxMZ@^s wyg ݠXD{ >b(_ASX~8tit00UİґLqa=ݨj0U#0İґLqa=ݨjge0c1 0 UUS1!0U The Go Daddy Group, Inc.110/U (Go Daddy Class 2 Certification Authority0 U00  *H 2K>ơw3\= ni04cr8(1zT1Xb۔EsE$Ղ#yiML3#An 剞;p~& T%ns! l l a+r9 ͗nN&s+L&qatJWuH.Qia@LĬC Օb ψ2 +E (*ZW7۽webpki-0.21.0/tests/netflix/ca.der000064400000000000000000000020361314565023400151370ustar000000000000000000~I>bHq)W0  *H 01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1:08U 1(c) 1999 VeriSign, Inc. - For authorized use only1E0CU f/G/F +QvF ̨LYUS\b _ vίjA3zcӞb7ՅeS$t^S[,I;hW0  *H ?/ɲZd!O4v6W/ŭ7bs>_5+ۮ` __n =Z `o#". ˩tGץk/BIݧSZ(P0)F=58bJQlޯb$zhfE\i+Z7^*\TTǘ0;6ۣnG1OO x 5VڷmdEk zNOKK}webpki-0.21.0/tests/netflix/ee.der000064400000000000000000000033541315562153200151510ustar000000000000000000РLd.#Li'Pi)0  *H  0~1 0 UUS10U Symantec Corporation10U Symantec Trust Network1/0-U&Symantec Class 3 Secure Server CA - G40 161108000000Z 181102235959Z0}1 0 UUS10U California10U los gatos10U Netflix, Inc.10U Operations10U www.netflix.com0"0  *H 0  {}ZP#OYPf^av(_v˂NmC^@S ոnnzm&Λ3e3VZu^e7K(^YԤ "1{C NrNC镔,H)Yˢj8%2d&vhd:(LqQ]gD gOOXEIG0E!oZӒ/ce`3s4m 7' u vŽF`U|vKu`Bif~_r؃{zXEIG0E d}꒯hHf@axU!@.SŌ Ҡ󔔥8y9g{ǝ,10  *H  3\nnR*B kwm6'C\hFY<ܯ'GW۪P{꧰9^/lD7 hmx oR\c31yn9綋 Luk&ҙ)+^ hB"50(?۷4zf?<ϟT*1xJ+r˄l2~S xdW"re3f)gjQ[i̝V5¥>ƨ_ ɂZwebpki-0.21.0/tests/netflix/inter.der000064400000000000000000000024311314565023400156740ustar000000000000000000(.'y3(!N70  *H  01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1:08U 1(c) 1999 VeriSign, Inc. - For authorized use only1E0CUZp-W+'zwebpki-0.21.0/third-party/chromium/LICENSE000064400000000000000000000030271261452200500163370ustar0000000000000000// Copyright 2015 The Chromium Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. webpki-0.21.0/third-party/chromium/data/verify_signed_data/README000064400000000000000000000021271261452200500227510ustar0000000000000000This directory contains test data for testing net::VerifySignedData(). When adding or changing test data, run the script $ python annotate_test_data.py This script will apply a uniform formatting. For instance it will add a comment showing what the parsed ASN.1 looks like, and reformat the base64 to have consistent line breaks. The general format for the test files is as follows: -----BEGIN PUBLIC KEY----- -----END PUBLIC KEY----- -----BEGIN ALGORITHM----- -----END ALGORITHM----- -----BEGIN DATA----- -----END DATA----- -----BEGIN SIGNATURE----- -----END SIGNATURE----- Comments for a PEM block should be placed immediately below that block. The script will also insert a comment after the block describing its parsed ASN.1 structure (your extra comments need to be above the script-generated comments or they will be stripped). ecdsa-prime256v1-sha512-spki-params-null.pem000064400000000000000000000025171261452200500316130ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same test as ecdsa-prime256v1-sha512.pem except the public key's algorithm has been tampered with. The parameters for ecPublicKey should be a namedCurve, but here they have been replaced by NULL. -----BEGIN PUBLIC KEY----- MFEwCwYHKoZIzj0CAQUAA0IABJywz2kwPa/HYdTkaHtOzwOebTSrlkr4CBDY1VikqNb3LVEjOhe IkgqG7gihlix576MX+3h54pfa0hRtuZX6HHg= -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 81 cons: SEQUENCE 2:d=1 hl=2 l= 11 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 0 prim: NULL 15:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAME -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA512 -----BEGIN DATA----- bikyFTMBpO72gOZCiSmtrpiMEI1mijH/VdBImUfXX/gaRr+J6E1kAfAjvm6HaI+814TXhcqEZzV SSstS0ARSyEBApHnnzDMJNkQdk7vnIqlDKm4dsRK1yUA7ECcssTR/1hnUY/ep0iOtdv3gbYpog1 APuEMjWr/5jiQb37VTjD4= -----END DATA----- -----BEGIN SIGNATURE----- A0cAMEQCIEufkeQoUocmGh0ckjz2Gc1SwXXP5/G+YKUljGEDSLo9AiAoxF+QHXHEGymGOOwNaoX X/LDDO7/sWpyBCEa2OSiahA== -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 71 prim: BIT STRING ecdsa-prime256v1-sha512-unused-bits-signature.pem000064400000000000000000000031371261452200500326540ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same test as ecdsa-prime256v1-sha512.pem, however the SIGNATURE has been changed to a (valid) BIT STRING containing two unused bits. Note that the last two bits of the original signature were 0, so the DER-encoded bytes portion of the mutated BIT STRING remains the same. All that changes is the octet at the start which indicates the number of unused bits. In other words SIGNATURE changes from: 03 47 00 30 ... 84 To: 03 47 02 30 ... 84 -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnLDPaTA9r8dh1ORoe07PA55tNKuWSvgIENjVWKS o1vctUSM6F4iSCobuCKGWLHnvoxf7eHnil9rSFG25lfoceA== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 89 cons: SEQUENCE 2:d=1 hl=2 l= 19 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 23:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAME -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA512 -----BEGIN DATA----- bikyFTMBpO72gOZCiSmtrpiMEI1mijH/VdBImUfXX/gaRr+J6E1kAfAjvm6HaI+814TXhcqEZzV SSstS0ARSyEBApHnnzDMJNkQdk7vnIqlDKm4dsRK1yUA7ECcssTR/1hnUY/ep0iOtdv3gbYpog1 APuEMjWr/5jiQb37VTjD4= -----END DATA----- -----BEGIN SIGNATURE----- A0cCMEQCIEufkeQoUocmGh0ckjz2Gc1SwXXP5/G+YKUljGEDSLo9AiAoxF+QHXHEGymGOOwNaoX X/LDDO7/sWpyBCEa2OSiahA== -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 71 prim: BIT STRING ecdsa-prime256v1-sha512-using-ecdh-key.pem000064400000000000000000000026671261452200500312360ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis uses the same test data as ecdsa-prime256v1-sha512.pem, HOWEVER the algorithm OID for the public key has been changed from id-ecPublicKey (1.2.840.10045.2.1) to id-ecDH (1.3.132.1.12) This test should fail because the public key's algorithm does not match that of the signature algorithm. -----BEGIN PUBLIC KEY----- MFcwEQYFK4EEAQwGCCqGSM49AwEHA0IABJywz2kwPa/HYdTkaHtOzwOebTSrlkr4CBDY1VikqNb 3LVEjOheIkgqG7gihlix576MX+3h54pfa0hRtuZX6HHg= -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 87 cons: SEQUENCE 2:d=1 hl=2 l= 17 cons: SEQUENCE 4:d=2 hl=2 l= 5 prim: OBJECT :1.3.132.1.12 11:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 21:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAME -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA512 -----BEGIN DATA----- bikyFTMBpO72gOZCiSmtrpiMEI1mijH/VdBImUfXX/gaRr+J6E1kAfAjvm6HaI+814TXhcqEZzV SSstS0ARSyEBApHnnzDMJNkQdk7vnIqlDKm4dsRK1yUA7ECcssTR/1hnUY/ep0iOtdv3gbYpog1 APuEMjWr/5jiQb37VTjD4= -----END DATA----- -----BEGIN SIGNATURE----- A0cAMEQCIEufkeQoUocmGh0ckjz2Gc1SwXXP5/G+YKUljGEDSLo9AiAoxF+QHXHEGymGOOwNaoX X/LDDO7/sWpyBCEa2OSiahA== -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 71 prim: BIT STRING ecdsa-prime256v1-sha512-using-ecmqv-key.pem000064400000000000000000000026701261452200500314400ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis uses the same test data as ecdsa-prime256v1-sha512.pem, HOWEVER the algorithm OID for the public key has been changed from id-ecPublicKey (1.2.840.10045.2.1) to id-ecMQV (1.3.132.1.13) This test should fail because the public key's algorithm does not match that of the signature algorithm. -----BEGIN PUBLIC KEY----- MFcwEQYFK4EEAQ0GCCqGSM49AwEHA0IABJywz2kwPa/HYdTkaHtOzwOebTSrlkr4CBDY1VikqNb 3LVEjOheIkgqG7gihlix576MX+3h54pfa0hRtuZX6HHg= -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 87 cons: SEQUENCE 2:d=1 hl=2 l= 17 cons: SEQUENCE 4:d=2 hl=2 l= 5 prim: OBJECT :1.3.132.1.13 11:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 21:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAME -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA512 -----BEGIN DATA----- bikyFTMBpO72gOZCiSmtrpiMEI1mijH/VdBImUfXX/gaRr+J6E1kAfAjvm6HaI+814TXhcqEZzV SSstS0ARSyEBApHnnzDMJNkQdk7vnIqlDKm4dsRK1yUA7ECcssTR/1hnUY/ep0iOtdv3gbYpog1 APuEMjWr/5jiQb37VTjD4= -----END DATA----- -----BEGIN SIGNATURE----- A0cAMEQCIEufkeQoUocmGh0ckjz2Gc1SwXXP5/G+YKUljGEDSLo9AiAoxF+QHXHEGymGOOwNaoX X/LDDO7/sWpyBCEa2OSiahA== -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 71 prim: BIT STRING ecdsa-prime256v1-sha512-using-rsa-algorithm.pem000064400000000000000000000026731261452200500323130ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis test specified a valid ECDSA signature and EC key (the same as ecdsa-prime256v1-sha512.pem) The problem however is the signature algorithm is indicated as being RSA PKCS#1 v1.5. Signature verification consequently should fail. -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnLDPaTA9r8dh1ORoe07PA55tNKuWSvgIENjVWKS o1vctUSM6F4iSCobuCKGWLHnvoxf7eHnil9rSFG25lfoceA== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 89 cons: SEQUENCE 2:d=1 hl=2 l= 19 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 23:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBDQUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha512WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- bikyFTMBpO72gOZCiSmtrpiMEI1mijH/VdBImUfXX/gaRr+J6E1kAfAjvm6HaI+814TXhcqEZzV SSstS0ARSyEBApHnnzDMJNkQdk7vnIqlDKm4dsRK1yUA7ECcssTR/1hnUY/ep0iOtdv3gbYpog1 APuEMjWr/5jiQb37VTjD4= -----END DATA----- -----BEGIN SIGNATURE----- A0cAMEQCIEufkeQoUocmGh0ckjz2Gc1SwXXP5/G+YKUljGEDSLo9AiAoxF+QHXHEGymGOOwNaoX X/LDDO7/sWpyBCEa2OSiahA== -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 71 prim: BIT STRING ecdsa-prime256v1-sha512-wrong-signature-format.pem000064400000000000000000000026741261452200500330410ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same as ecdsa-prime256v1-sha512.pem, except the signature is wrong. Rather than encoding the signature into a DER-encoded Ecdsa-Sig-Value, it is a concatenation of the r and s values. This is the format that WebCrypto uses for ECDSA signature, but not what is used for digital signatures. -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnLDPaTA9r8dh1ORoe07PA55tNKuWSvgIENjVWKS o1vctUSM6F4iSCobuCKGWLHnvoxf7eHnil9rSFG25lfoceA== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 89 cons: SEQUENCE 2:d=1 hl=2 l= 19 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 23:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAME -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA512 -----BEGIN DATA----- bikyFTMBpO72gOZCiSmtrpiMEI1mijH/VdBImUfXX/gaRr+J6E1kAfAjvm6HaI+814TXhcqEZzV SSstS0ARSyEBApHnnzDMJNkQdk7vnIqlDKm4dsRK1yUA7ECcssTR/1hnUY/ep0iOtdv3gbYpog1 APuEMjWr/5jiQb37VTjD4= -----END DATA----- -----BEGIN SIGNATURE----- A0EAS5+R5ChShyYaHRySPPYZzVLBdc/n8b5gpSWMYQNIuj0oxF+QHXHEGymGOOwNaoXX/LDDO7/ sWpyBCEa2OSiahA== -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 65 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ecdsa-prime256v1-sha512.pem000064400000000000000000000027631261452200500265000ustar0000000000000000The key, message, and signature come from: http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip (SigVer.rsp) The algorithm DER was synthesized to match, and the signature (provided as an r and s tuple) was encoded into a Ecdsa-Sig-Value and then a BIT STRING. It uses ECDSA verification, using curve prime256v1 and SHA-512 -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnLDPaTA9r8dh1ORoe07PA55tNKuWSvgIENjVWKS o1vctUSM6F4iSCobuCKGWLHnvoxf7eHnil9rSFG25lfoceA== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 89 cons: SEQUENCE 2:d=1 hl=2 l= 19 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 23:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAME -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA512 -----BEGIN DATA----- bikyFTMBpO72gOZCiSmtrpiMEI1mijH/VdBImUfXX/gaRr+J6E1kAfAjvm6HaI+814TXhcqEZzV SSstS0ARSyEBApHnnzDMJNkQdk7vnIqlDKm4dsRK1yUA7ECcssTR/1hnUY/ep0iOtdv3gbYpog1 APuEMjWr/5jiQb37VTjD4= -----END DATA----- -----BEGIN SIGNATURE----- A0cAMEQCIEufkeQoUocmGh0ckjz2Gc1SwXXP5/G+YKUljGEDSLo9AiAoxF+QHXHEGymGOOwNaoX X/LDDO7/sWpyBCEa2OSiahA== -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 71 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ecdsa-secp384r1-sha256-corrupted-data.pem000064400000000000000000000036031261452200500312270ustar0000000000000000This is the same test as ecdsa-secp384r1-sha256.pem, except the DATA section has been corrupted. The third byte has been set to 0. This signature should NOT verify successfully. -----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEXFhBi+WKXuxeK9yCbC9jqEchwjCNsQ4RXAsJ07oHZ+Q qz55cNIY5BAhcQ0QYY5jv9BimGL9SuhUuOSuS3Pn9rrsIFGcFsihy4kDr8rq5+7RbN8bV057gW5 emYjLtvDsQ -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 118 cons: SEQUENCE 2:d=1 hl=2 l= 16 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 5 prim: OBJECT :secp384r1 20:d=1 hl=2 l= 98 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAMC -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA256 -----BEGIN DATA----- MIIA6KADAgECAgkAtUVxft6/Vc0wCgYIKoZIzj0EAwIwbzELMAkGA1UEBhMCQVUxEzARBgNVBAg MClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEMMAoGA1UEAw wDYWhhMRowGAYJKoZIhvcNAQkBFgtzdXBAZm9vLmNvbTAeFw0xNTA3MDIwMDM4MTRaFw0xNjA3M DEwMDM4MTRaMG8xCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDDAKBgNVBAMMA2FoYTEaMBgGCSqGSIb3DQEJARYLc3V wQGZvby5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARcWEGL5Ype7F4r3IJsL2OoRyHCMI2xDh FcCwnTugdn5CrPnlw0hjkECFxDRBhjmO/0GKYYv1K6FS45K5Lc+f2uuwgUZwWyKHLiQOvyurn7t Fs3xtXTnuBbl6ZiMu28OxCjUDBOMB0GA1UdDgQWBBR6nDgtPalG2JvSlWzdGRCi/Cu7NjAfBgNV HSMEGDAWgBR6nDgtPalG2JvSlWzdGRCi/Cu7NjAMBgNVHRMEBTADAQH/ -----END DATA----- -----BEGIN SIGNATURE----- A2kAMGYCMQCDwMSZVJZ8qThiNTV7VX57m8fdNnNS6cXIjRYoh4SozlYWmWGh87nhmJJCeD16jVM CMQDkroAY8oNi8RxLUor+LozhhVgu24tu6lcp4MP8H3Zy8bBea5HerAd1AqJp3Ox7KDU= -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 105 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ecdsa-secp384r1-sha256.pem000064400000000000000000000052331261452200500263140ustar0000000000000000This test data was produced by creating a self-signed EC cert using OpenSSL, and then extracting the relevant fields. It uses ECDSA with curve secp384r1 an SHA-256. (1) Generate self-signed certificate openssl ecparam -out ec_key.pem -name secp384r1 -genkey openssl req -new -key ec_key.pem -x509 -nodes -days 365 -out cert.pem (2) Extract public key openssl x509 -in cert.pem -pubkey -noout > pubkey.pem cat pubkey.pem (3) Extract signed data (tbsCertificate) openssl asn1parse -in cert.pem -out tbs -noout -strparse 4 base64 tbs (4) Extract signature algorithm # Find the offset of the signature algorithm near the end (496 in this case) openssl asn1parse -in cert.pem openssl asn1parse -in cert.pem -out alg -noout -strparse 496 base64 alg (5) Extract the signature # Find the final offset of BIT STRING (508 in this case) openssl asn1parse -in cert.pem openssl asn1parse -in cert.pem -out sig -noout -strparse 508 base64 sig -----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEXFhBi+WKXuxeK9yCbC9jqEchwjCNsQ4RXAsJ07oHZ+Q qz55cNIY5BAhcQ0QYY5jv9BimGL9SuhUuOSuS3Pn9rrsIFGcFsihy4kDr8rq5+7RbN8bV057gW5 emYjLtvDsQ -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 118 cons: SEQUENCE 2:d=1 hl=2 l= 16 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 5 prim: OBJECT :secp384r1 20:d=1 hl=2 l= 98 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAMC -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA256 -----BEGIN DATA----- MIIB6KADAgECAgkAtUVxft6/Vc0wCgYIKoZIzj0EAwIwbzELMAkGA1UEBhMCQVUxEzARBgNVBAg MClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEMMAoGA1UEAw wDYWhhMRowGAYJKoZIhvcNAQkBFgtzdXBAZm9vLmNvbTAeFw0xNTA3MDIwMDM4MTRaFw0xNjA3M DEwMDM4MTRaMG8xCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDDAKBgNVBAMMA2FoYTEaMBgGCSqGSIb3DQEJARYLc3V wQGZvby5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARcWEGL5Ype7F4r3IJsL2OoRyHCMI2xDh FcCwnTugdn5CrPnlw0hjkECFxDRBhjmO/0GKYYv1K6FS45K5Lc+f2uuwgUZwWyKHLiQOvyurn7t Fs3xtXTnuBbl6ZiMu28OxCjUDBOMB0GA1UdDgQWBBR6nDgtPalG2JvSlWzdGRCi/Cu7NjAfBgNV HSMEGDAWgBR6nDgtPalG2JvSlWzdGRCi/Cu7NjAMBgNVHRMEBTADAQH/ -----END DATA----- -----BEGIN SIGNATURE----- A2kAMGYCMQCDwMSZVJZ8qThiNTV7VX57m8fdNnNS6cXIjRYoh4SozlYWmWGh87nhmJJCeD16jVM CMQDkroAY8oNi8RxLUor+LozhhVgu24tu6lcp4MP8H3Zy8bBea5HerAd1AqJp3Ox7KDU= -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 105 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ecdsa-using-rsa-key.pem000064400000000000000000000036071261452200500263530ustar0000000000000000This test specifies an ECDSA signature algorithm (and a valid ecdsa signature), HOWEVER it provides an RSA key. Verification should fail. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAMC -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA256 -----BEGIN DATA----- MIIB6KADAgECAgkAtUVxft6/Vc0wCgYIKoZIzj0EAwIwbzELMAkGA1UEBhMCQVUxEzARBgNVBAg MClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEMMAoGA1UEAw wDYWhhMRowGAYJKoZIhvcNAQkBFgtzdXBAZm9vLmNvbTAeFw0xNTA3MDIwMDM4MTRaFw0xNjA3M DEwMDM4MTRaMG8xCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDDAKBgNVBAMMA2FoYTEaMBgGCSqGSIb3DQEJARYLc3V wQGZvby5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARcWEGL5Ype7F4r3IJsL2OoRyHCMI2xDh FcCwnTugdn5CrPnlw0hjkECFxDRBhjmO/0GKYYv1K6FS45K5Lc+f2uuwgUZwWyKHLiQOvyurn7t Fs3xtXTnuBbl6ZiMu28OxCjUDBOMB0GA1UdDgQWBBR6nDgtPalG2JvSlWzdGRCi/Cu7NjAfBgNV HSMEGDAWgBR6nDgtPalG2JvSlWzdGRCi/Cu7NjAMBgNVHRMEBTADAQH/ -----END DATA----- -----BEGIN SIGNATURE----- A2kAMGYCMQCDwMSZVJZ8qThiNTV7VX57m8fdNnNS6cXIjRYoh4SozlYWmWGh87nhmJJCeD16jVM CMQDkroAY8oNi8RxLUor+LozhhVgu24tu6lcp4MP8H3Zy8bBea5HerAd1AqJp3Ox7KDU= -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=2 l= 105 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ours/make-pss.py000064400000000000000000000044571314565023400251710ustar0000000000000000# Copyright 2016 Joseph Birr-Pixton. # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import subprocess import glob import hashlib import os TOP = '../../../../../' def dump(bin, type): return '-----BEGIN %s-----\n%s-----END %s-----\n' % \ (type, bin.encode('base64'), type) def gen(outfile, paramfile, hashfn): param = open(paramfile).read() rand = os.urandom(64) hash = getattr(hashlib, hashfn)(rand).digest() proc = subprocess.Popen(['openssl', 'pkeyutl', '-inkey', 'priv.pem', '-sign', '-pkeyopt', 'rsa_padding_mode:pss', '-pkeyopt', 'rsa_pss_saltlen:-1', '-pkeyopt', 'digest:%s' % hashfn ], stdout = subprocess.PIPE, stdin = subprocess.PIPE) sig, _ = proc.communicate(hash) with open(outfile, 'w') as f: print >>f, dump(open('pub.der').read(), 'PUBLIC KEY') print >>f, dump(param, 'ALGORITHM') print >>f, dump(rand, 'DATA') assert len(sig) == 256 # only works with 2048-bit keys # turn it into a DER bitstring print >>f, dump('\x03\x82\x01\x01\x00' + sig, 'SIGNATURE') if __name__ == '__main__': subprocess.check_call('openssl genrsa -out priv.pem 2048', shell = True) subprocess.check_call('openssl rsa -pubout -out pub.pem -in priv.pem', shell = True) subprocess.check_call('openssl asn1parse -inform pem -in pub.pem -out pub.der', shell = True) gen('rsa-pss-sha256-salt32.pem', TOP + 'src/data/alg-pss-sha256.der', 'sha256') gen('rsa-pss-sha384-salt48.pem', TOP + 'src/data/alg-pss-sha384.der', 'sha384') gen('rsa-pss-sha512-salt64.pem', TOP + 'src/data/alg-pss-sha512.der', 'sha512') webpki-0.21.0/third-party/chromium/data/verify_signed_data/ours/priv.pem000064400000000000000000000032171314565023400245530ustar0000000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAtVDcg1BMqPneiNBL5+mjEB5mxjJzgkmClZR5z1jNht+As6+M lgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDOFwtrxJE6Eg1GQ2ux9nDVNvrQkoOL znXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbcWc/4wTZOfO6lns4nb5s08oaUv3uF 5Wc0sktNr6he6R3zSQ6YK5KZFzQdnEtGc4gwHWXZ9xt4JeANht3m4RNpMY89qZsZ xmqoewYHuXQUAfl7W0DC3hoxOoLwSqL2bt2zMMeR8WAo51YY0cJnzAEETcnWIM6e alb5Osj3iSEknxRTley47SsODQ0maUUWj8wEjwIDAQABAoIBAFBAVQmt7fBQgAWQ JDimeWz198k7pVKCVND94Zg7luReYmmlhpUVM7V6A1/BC9EMuERlmq6YEgwIyZjW KUFxhQZAINfk64334CSRMzh/om9uPgjLPoMIQG1dzL9NtR0Ic7wKV8afxPf/mKL9 Iwvv1+HMoi5qafzz58xNNLk6OgopdZ6H2aX0QtHy/jkMfpE3od7W6Xc+lSVUO7HG zmN3pHaM5K5n59cX9jpg/K+a0loceY5vmqUfXyh6IP6h1XyAb2NTpU04klDEFEnU tyaYtxL4ZMZzefoeVXVbCl7qeOE7KGIz7gcvsqL7T8dkK+uYf6mLENeyUvkCKiTG QAqon0kCgYEA6pLLAYpRo9JbLYlYNt9iTFwIU+R8RcxzZrltm7OUqztmaVq4pOek cPw/2sCMvqeEWuGhv+bbeIsDUWADU9NFkWySlVRKEFKGb3ECv3A07yfP2K22exOZ /SglNZKB/ycvpOMcNKnJD5folRrh0actdVG8vOf/sN+887vE77u0f6sCgYEAxeC0 /6831k/EWYzQf+OfeLqx4ABgkgqxvMXO3YCp44+DD4l8TVWfP4Ahfj5p0zCbXIv3 5OcxdVwjNljZw4Y5vDNwcDK7vKwp9ne+H9xJB7Yedfr7oyJbqIvJ1nd6jmXoL7GA dX9xSxJ1CucD7RAY99MS77y8xm0sTbFoI6SvOq0CgYEApeQihXhYvE6sBMw5ArWA QxhjG1FfQc2RX3iLt62M2nwrtR5frt/TP8RlNEMwRjUaOVuQlLKjS+Cj/Ay2zbWA YZQzJkByEJEMWgvGMbUc+nVhXI+dmfUG1i5qAjUWkmgYHbgv3l6kvs5jwe88/JQK ZgnkPISmI2RXsNd+MzzALfkCgYB/56HXa/ERzHnE0KqtH/si1LrJajUB8Xu14761 msc12rwCvQHmEyRerXn42msZIeAq0CaqhW6Ix8fTB1erdQW4yx8wxvpnGHn/YKM6 gO+L1oKWDGe/qSPKLKGIya4kgWa1/Wxlhr06o3GYXH9DKxaYio1A/aSgNk1e4v/H mlnR+QKBgQDd2cdhBTXIo5FZSONip5GG2Ku9m60qGSyPTCqxLNWBfYE/fu0aFCUU GemqA2ygxFnyCG1Af0SDWwQFH8W7BJ6H1geJVcwVKLrZokKOul8kdwXCxz1J2XGe gskT4Dsd9K8TSU3J09XVKhC5SrF0vDjdXOE6rtFSqa/bs7B2JcfNwQ== -----END RSA PRIVATE KEY----- webpki-0.21.0/third-party/chromium/data/verify_signed_data/ours/pub.pem000064400000000000000000000007031314565023400243560ustar0000000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVDcg1BMqPneiNBL5+mj EB5mxjJzgkmClZR5z1jNht+As6+Mlgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDO FwtrxJE6Eg1GQ2ux9nDVNvrQkoOLznXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbc Wc/4wTZOfO6lns4nb5s08oaUv3uF5Wc0sktNr6he6R3zSQ6YK5KZFzQdnEtGc4gw HWXZ9xt4JeANht3m4RNpMY89qZsZxmqoewYHuXQUAfl7W0DC3hoxOoLwSqL2bt2z MMeR8WAo51YY0cJnzAEETcnWIM6ealb5Osj3iSEknxRTley47SsODQ0maUUWj8wE jwIDAQAB -----END PUBLIC KEY----- rsa-pss-sha256-salt32-corrupted-data.pem000064400000000000000000000045611314565023400321370ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_data/oursThis has had DATA corrupted, so the signature is not valid. -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVDcg1BMqPneiNBL5+mjEB5mxjJzgkm ClZR5z1jNht+As6+Mlgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDOFwtrxJE6Eg1GQ2ux9nDVNv rQkoOLznXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbcWc/4wTZOfO6lns4nb5s08oaUv3uF5Wc0s ktNr6he6R3zSQ6YK5KZFzQdnEtGc4gwHWXZ9xt4JeANht3m4RNpMY89qZsZxmqoewYHuXQUAfl7 W0DC3hoxOoLwSqL2bt2zMMeR8WAo51YY0cJnzAEETcnWIM6ealb5Osj3iSEknxRTley47SsODQ0 maUUWj8wEjwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIBBQCiAwIBIA== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha256 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha256 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :20 -----BEGIN DATA----- K6BCjy4hCNAZBmRT+wS4h5wDg7pO67oHFabDt5cXNp8X6sLNH2vjICLtO2niPwZ/Yk2ySxC8MgO /+U9sdSXxqA== -----END DATA----- -----BEGIN SIGNATURE----- A4IBAQCZqlXJhviFKOKHe1ssbm0ThtAnAbcuP3ACBZyfpBjfYlxAgltNzBnmEtxjsbZQPMXHDHy Y+fdEXwK2vboCz7BzIRXcrcJGzjsBc2zPeNZlmhaadIoa5d8jy3kxnT+f3YVjKGZBqwDaqE5Kie jhV0laTK+cNGFXo9a3ylICok+s4jVN2Y7qE+ImgyANbZyn1d6W6VnFf4GVvin2hFwTCcZnKA6Db NYnArbbNmHmMB2S+1Kw9dAklnzZmwWgNSRirtTpUHTBIWYq3B0hPL8IzwKk89/iKDaY2fpV/Wnt oL2mgM7oa/7+oQWa27BGYftYZmDpIQtNbUeO4VBnaeqGgA5f -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=4 l= 257 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ours/rsa-pss-sha256-salt32.pem000064400000000000000000000044661314565023400273060ustar0000000000000000 -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVDcg1BMqPneiNBL5+mjEB5mxjJzgkm ClZR5z1jNht+As6+Mlgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDOFwtrxJE6Eg1GQ2ux9nDVNv rQkoOLznXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbcWc/4wTZOfO6lns4nb5s08oaUv3uF5Wc0s ktNr6he6R3zSQ6YK5KZFzQdnEtGc4gwHWXZ9xt4JeANht3m4RNpMY89qZsZxmqoewYHuXQUAfl7 W0DC3hoxOoLwSqL2bt2zMMeR8WAo51YY0cJnzAEETcnWIM6ealb5Osj3iSEknxRTley47SsODQ0 maUUWj8wEjwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIBBQCiAwIBIA== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha256 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha256 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :20 -----BEGIN DATA----- K5BCjy4hCNAZBmRT+wS4h5wDg7pO67oHFabDt5cXNp8X6sLNH2vjICLtO2niPwZ/Yk2ySxC8MgO /+U9sdSXxqA== -----END DATA----- -----BEGIN SIGNATURE----- A4IBAQCZqlXJhviFKOKHe1ssbm0ThtAnAbcuP3ACBZyfpBjfYlxAgltNzBnmEtxjsbZQPMXHDHy Y+fdEXwK2vboCz7BzIRXcrcJGzjsBc2zPeNZlmhaadIoa5d8jy3kxnT+f3YVjKGZBqwDaqE5Kie jhV0laTK+cNGFXo9a3ylICok+s4jVN2Y7qE+ImgyANbZyn1d6W6VnFf4GVvin2hFwTCcZnKA6Db NYnArbbNmHmMB2S+1Kw9dAklnzZmwWgNSRirtTpUHTBIWYq3B0hPL8IzwKk89/iKDaY2fpV/Wnt oL2mgM7oa/7+oQWa27BGYftYZmDpIQtNbUeO4VBnaeqGgA5f -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=4 l= 257 prim: BIT STRING rsa-pss-sha384-salt48-corrupted-data.pem000064400000000000000000000045611314565023400321500ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_data/oursThis has had DATA corrupted, so the signature is not valid. -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVDcg1BMqPneiNBL5+mjEB5mxjJzgkm ClZR5z1jNht+As6+Mlgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDOFwtrxJE6Eg1GQ2ux9nDVNv rQkoOLznXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbcWc/4wTZOfO6lns4nb5s08oaUv3uF5Wc0s ktNr6he6R3zSQ6YK5KZFzQdnEtGc4gwHWXZ9xt4JeANht3m4RNpMY89qZsZxmqoewYHuXQUAfl7 W0DC3hoxOoLwSqL2bt2zMMeR8WAo51YY0cJnzAEETcnWIM6ealb5Osj3iSEknxRTley47SsODQ0 maUUWj8wEjwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAICBQCiAwIBMA== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha384 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha384 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :30 -----BEGIN DATA----- TDrlz5dKOqfOQhirwHj00bsVlf+0WEe2qMe9l6SVr9SHB4Eow26r+aU7+pGZFp774O041xIeU2g ZHYzNWBjGZQ== -----END DATA----- -----BEGIN SIGNATURE----- A4IBAQBvlL4AuwL3hEobMolBzR/0gzuJ9u4ATWEPO5uTiBtdJ5Nx9O6gFCrtZMwfEU9q4bzazKV yWRSpn23GZjlmNYhFCNlfY3l6IlhxGEVz/YeOglrBR8hFbA17835jTmcCR09G6SZ7Wwm8NV7riw woW15A1N2axuaAAcCxf9T48uehAmXrfApJygl2PWeKzzATUAuGzLLmQ0hNGVvUraxCJfiehtnMl kWUiSZgjvmXKv6N2JtN8dHMHVEzPTBou4a25ozQIRAIGFvZYcDm5DW4CNJqFM1mTv2BEeOCW5hw Bt60xm8kXOX4OGwgEyB/aHttWHPdAiFUoODo5j4MtcvajuWt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=4 l= 257 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ours/rsa-pss-sha384-salt48.pem000064400000000000000000000044661314565023400273170ustar0000000000000000 -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVDcg1BMqPneiNBL5+mjEB5mxjJzgkm ClZR5z1jNht+As6+Mlgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDOFwtrxJE6Eg1GQ2ux9nDVNv rQkoOLznXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbcWc/4wTZOfO6lns4nb5s08oaUv3uF5Wc0s ktNr6he6R3zSQ6YK5KZFzQdnEtGc4gwHWXZ9xt4JeANht3m4RNpMY89qZsZxmqoewYHuXQUAfl7 W0DC3hoxOoLwSqL2bt2zMMeR8WAo51YY0cJnzAEETcnWIM6ealb5Osj3iSEknxRTley47SsODQ0 maUUWj8wEjwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAICBQCiAwIBMA== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha384 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha384 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :30 -----BEGIN DATA----- TDRlz5dKOqfOQhirwHj00bsVlf+0WEe2qMe9l6SVr9SHB4Eow26r+aU7+pGZFp774O041xIeU2g ZHYzNWBjGZQ== -----END DATA----- -----BEGIN SIGNATURE----- A4IBAQBvlL4AuwL3hEobMolBzR/0gzuJ9u4ATWEPO5uTiBtdJ5Nx9O6gFCrtZMwfEU9q4bzazKV yWRSpn23GZjlmNYhFCNlfY3l6IlhxGEVz/YeOglrBR8hFbA17835jTmcCR09G6SZ7Wwm8NV7riw woW15A1N2axuaAAcCxf9T48uehAmXrfApJygl2PWeKzzATUAuGzLLmQ0hNGVvUraxCJfiehtnMl kWUiSZgjvmXKv6N2JtN8dHMHVEzPTBou4a25ozQIRAIGFvZYcDm5DW4CNJqFM1mTv2BEeOCW5hw Bt60xm8kXOX4OGwgEyB/aHttWHPdAiFUoODo5j4MtcvajuWt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=4 l= 257 prim: BIT STRING rsa-pss-sha512-salt64-corrupted-data.pem000064400000000000000000000045611314565023400321370ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_data/oursThis has had DATA corrupted, so the signature is not valid. -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVDcg1BMqPneiNBL5+mjEB5mxjJzgkm ClZR5z1jNht+As6+Mlgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDOFwtrxJE6Eg1GQ2ux9nDVNv rQkoOLznXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbcWc/4wTZOfO6lns4nb5s08oaUv3uF5Wc0s ktNr6he6R3zSQ6YK5KZFzQdnEtGc4gwHWXZ9xt4JeANht3m4RNpMY89qZsZxmqoewYHuXQUAfl7 W0DC3hoxOoLwSqL2bt2zMMeR8WAo51YY0cJnzAEETcnWIM6ealb5Osj3iSEknxRTley47SsODQ0 maUUWj8wEjwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIDBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIDBQCiAwIBQA== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha512 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha512 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :40 -----BEGIN DATA----- BENGYY+GrDsvawb08kP/OZ0iWbG5yBlJpCIJ1YLPfTCjEouvBzwAkWpUEsI3zk0N8+xcMyJ3qOi pIsX4YnFfPw== -----END DATA----- -----BEGIN SIGNATURE----- A4IBAQBPA1K787NaEycdAHDfil1/F2imI9PcVD5ZuloBz9Qj1q4ZfdZ9PMagunDBVRQoBr1VDhI 6VkDfyQvhKebIbSsfk/qJoNZGCZtsKhXcGm5ZI2+fUbbMW7EwlKle8SqXCHRAIICND/qwundcqp kLNHOqOK8GRUYHnJcMmQbMCBUx9aw3IRu2LRp6FtBwA16stpSat/NlX+aH79f1B/uoFpDVzG7Kw oqmAuv81vOVQSCNTn4MrCyxmJTLqbk6frXN7nRF+SQOPksUwXXYgpzGyFhrwgUHwkc3skNx/jOT fpWnvjOUVbi80Sa9i7EIOcmt4IP4a3BRPWT/MTYDDPADIgVf -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=4 l= 257 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/ours/rsa-pss-sha512-salt64.pem000064400000000000000000000044661314565023400273060ustar0000000000000000 -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVDcg1BMqPneiNBL5+mjEB5mxjJzgkm ClZR5z1jNht+As6+Mlgflni0bB8LjhWbIt+dZ6Bt4cSHOnAOnkMDOFwtrxJE6Eg1GQ2ux9nDVNv rQkoOLznXrxMh/af0pcSo8kItDmkqbV/fi3Q7agpbcWc/4wTZOfO6lns4nb5s08oaUv3uF5Wc0s ktNr6he6R3zSQ6YK5KZFzQdnEtGc4gwHWXZ9xt4JeANht3m4RNpMY89qZsZxmqoewYHuXQUAfl7 W0DC3hoxOoLwSqL2bt2zMMeR8WAo51YY0cJnzAEETcnWIM6ealb5Osj3iSEknxRTley47SsODQ0 maUUWj8wEjwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIDBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIDBQCiAwIBQA== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha512 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha512 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :40 -----BEGIN DATA----- BEnGYY+GrDsvawb08kP/OZ0iWbG5yBlJpCIJ1YLPfTCjEouvBzwAkWpUEsI3zk0N8+xcMyJ3qOi pIsX4YnFfPw== -----END DATA----- -----BEGIN SIGNATURE----- A4IBAQBPA1K787NaEycdAHDfil1/F2imI9PcVD5ZuloBz9Qj1q4ZfdZ9PMagunDBVRQoBr1VDhI 6VkDfyQvhKebIbSsfk/qJoNZGCZtsKhXcGm5ZI2+fUbbMW7EwlKle8SqXCHRAIICND/qwundcqp kLNHOqOK8GRUYHnJcMmQbMCBUx9aw3IRu2LRp6FtBwA16stpSat/NlX+aH79f1B/uoFpDVzG7Kw oqmAuv81vOVQSCNTn4MrCyxmJTLqbk6frXN7nRF+SQOPksUwXXYgpzGyFhrwgUHwkc3skNx/jOT fpWnvjOUVbi80Sa9i7EIOcmt4IP4a3BRPWT/MTYDDPADIgVf -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=4 l= 257 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha1-bad-key-der-length.pem000064400000000000000000000025561261452200500306010ustar0000000000000000Same test as rsa-pkcs1-sha1.pem except the length of the first SEQUENCE has been increased by 2 (which makes it invalid). -----BEGIN PUBLIC KEY----- MIOfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] Error in encoding -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBBQUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAGvDoGZWhCkwokfjDVhktNgZI2unxollhirX28TiSvKOhrtTHwM1i+X7dHd8YIb4UMrviT8 Nb8wtDJHsATaTtOoAuAzUmqxOy1+JEa/lOa2kqPOCPR0T5HLRSQVHxlnHYX89JAh9228rcglhZ/ wJfKsY6aRY/LY0zc6O41iUxITX -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha1-bad-key-der-null.pem000064400000000000000000000033271261452200500302670ustar0000000000000000Same test as rsa-pkcs1-sha1.pem except an extra NULL (0x05, 0x00) has been appended to the SPKI. The DER can still be parsed, however it should fail due to the unconsumed data at the end. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQABBQA= -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING 162:d=0 hl=2 l= 0 prim: NULL -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBBQUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAGvDoGZWhCkwokfjDVhktNgZI2unxollhirX28TiSvKOhrtTHwM1i+X7dHd8YIb4UMrviT8 Nb8wtDJHsATaTtOoAuAzUmqxOy1+JEa/lOa2kqPOCPR0T5HLRSQVHxlnHYX89JAh9228rcglhZ/ wJfKsY6aRY/LY0zc6O41iUxITX -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha1-key-params-absent.pem000064400000000000000000000031651261452200500305560ustar0000000000000000Same test as rsa-pkcs1-sha1.pem, except the SPKI has been modified so the algorithm parameters are absent rather than NULL. This should fail because RFC 3279 says the parameters MUST be NULL. -----BEGIN PUBLIC KEY----- MIGdMAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEApW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h9 62ZHYxRBW/+2xYrTA8oOhKoijlN/1JqtykcuzB86r/OCx39XNlQgJbVsri2311nHvY3fAkhyyPC cKcOJZjm/4nRnxBazC0/DLNfKSgOE4a29kxO8i4eHyDQzoz/siSb2aITcCAwEAAQ== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 157 cons: SEQUENCE 3:d=1 hl=2 l= 11 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBBQUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAGvDoGZWhCkwokfjDVhktNgZI2unxollhirX28TiSvKOhrtTHwM1i+X7dHd8YIb4UMrviT8 Nb8wtDJHsATaTtOoAuAzUmqxOy1+JEa/lOa2kqPOCPR0T5HLRSQVHxlnHYX89JAh9228rcglhZ/ wJfKsY6aRY/LY0zc6O41iUxITX -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING rsa-pkcs1-sha1-using-pss-key-no-params.pem000064400000000000000000000032771261452200500315710ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same test as rsa-pkcs1-sha1.pem, except the SPKI has been modified so that the key algorithm is rsaPss (1.2.840.113549.1.1.10) with absent parameters. Subsequently this should fail, as a PSS key should not be used with a signature algorithm for PKCS#1 v1.5. -----BEGIN PUBLIC KEY----- MIGdMAsGCSqGSIb3DQEBCgOBjQAwgYkCgYEApW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h9 62ZHYxRBW/+2xYrTA8oOhKoijlN/1JqtykcuzB86r/OCx39XNlQgJbVsri2311nHvY3fAkhyyPC cKcOJZjm/4nRnxBazC0/DLNfKSgOE4a29kxO8i4eHyDQzoz/siSb2aITcCAwEAAQ== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 157 cons: SEQUENCE 3:d=1 hl=2 l= 11 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsassaPss 16:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBBQUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAGvDoGZWhCkwokfjDVhktNgZI2unxollhirX28TiSvKOhrtTHwM1i+X7dHd8YIb4UMrviT8 Nb8wtDJHsATaTtOoAuAzUmqxOy1+JEa/lOa2kqPOCPR0T5HLRSQVHxlnHYX89JAh9228rcglhZ/ wJfKsY6aRY/LY0zc6O41iUxITX -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha1-wrong-algorithm.pem000064400000000000000000000032051261452200500303460ustar0000000000000000This is the same as rsa-pkcs1-sha1.pem, however the ALGORITHM has been change to have SHA256 instead of SHA1. Using this algorithm verification should fail. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCwUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAGvDoGZWhCkwokfjDVhktNgZI2unxollhirX28TiSvKOhrtTHwM1i+X7dHd8YIb4UMrviT8 Nb8wtDJHsATaTtOoAuAzUmqxOy1+JEa/lOa2kqPOCPR0T5HLRSQVHxlnHYX89JAh9228rcglhZ/ wJfKsY6aRY/LY0zc6O41iUxITX -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha1.pem000064400000000000000000000034301261452200500252300ustar0000000000000000The key, message, and signature come from Example 1 of: ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt (The algorithm DER was synthesized to match, and the signature enclosed in a BIT STRING). It uses an RSA key with modulus length of 1024 bits, PKCS#1 v1.5 padding, and SHA-1 as the digest. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBBQUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAGvDoGZWhCkwokfjDVhktNgZI2unxollhirX28TiSvKOhrtTHwM1i+X7dHd8YIb4UMrviT8 Nb8wtDJHsATaTtOoAuAzUmqxOy1+JEa/lOa2kqPOCPR0T5HLRSQVHxlnHYX89JAh9228rcglhZ/ wJfKsY6aRY/LY0zc6O41iUxITX -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha256-key-encoded-ber.pem000064400000000000000000000043131261452200500303400ustar0000000000000000This is the same test as rsa-pkcs1-sha256.pem except the SPKI has been encoded using a non-minimal length for the outtermost SEQUENCE. Under DER, the tag-length-value encodings should be minimal and hence this should fail. Specifically the SPKI start was changed from: 30 81 9f To: 30 82 00 9f (the length of 0x9F is being expressed using 2 bytes instead of 1) -----BEGIN PUBLIC KEY----- MIIAnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqkfgdjI9YqzadSZ2Ns0CEEUD8+8m7OplIx0 94X+QD8mooNrunwT04asbLIINGL4qiI/+9IVSvyV3Kj9c4EeQIbANGoJ8AI3wf6MOBB/txxGFed qqcTffKVMQvtZdoYFbZ/MQkvyRsoyvunb/pWcN4sSaF9kY1bXSeP3J99fBIYUCAwEAAQ== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 159 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCwUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- MIIB46ADAgECAgkA3l4tFOVii0UwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgN VBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1 UEAwwGTXkga2V5MB4XDTE1MDcwMjE3MDYzOVoXDTE2MDcwMTE3MDYzOVowVjELMAkGA1UEBhMCQ VUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGTXkga2V5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp 1JnY2zQIQRQPz7ybs6mUjHT3hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA 0agnwAjfB/ow4EH+3HEYV52qpxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/ cn318EhhQIDAQABo1AwTjAdBgNVHQ4EFgQUzQBVKTEknyLndWd2HTsBdTKvyikwHwYDVR0jBBgw FoAUzQBVKTEknyLndWd2HTsBdTKvyikwDAYDVR0TBAUwAwEB/w== -----END DATA----- -----BEGIN SIGNATURE----- A4GBADrHSmFSJw/Gv7hs5PNzpaJwAri/sitarIZfzN/SjR+n8L8yeTEoiDb1+BkxlFvXvPHTaOK oO3WlslNNOxh1W5/JkYYGOUkCcyIjnln6qS560imcr3VNjomT/M8M2Iss+rJiKau1TRuaP7H8i6 +Gqf3saGdr8/LnvFAdNQvkalQt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha256-spki-non-null-params.pem000064400000000000000000000040531261452200500313730ustar0000000000000000This is the same test as rsa-pkcs1-sha256.pem except the SPKI has been tampered with. The parameters have been changed from NULL to an INTEGER. This was done by changing: 05 00 (NULL) To: 02 00 (INTEGER) -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQIAA4GNADCBiQKBgQCqR+B2Mj1irNp1JnY2zQIQRQPz7ybs6mUjHT3 hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA0agnwAjfB/ow4EH+3HEYV52q pxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/cn318EhhQIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: INTEGER :00 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCwUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- MIIB46ADAgECAgkA3l4tFOVii0UwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgN VBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1 UEAwwGTXkga2V5MB4XDTE1MDcwMjE3MDYzOVoXDTE2MDcwMTE3MDYzOVowVjELMAkGA1UEBhMCQ VUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGTXkga2V5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp 1JnY2zQIQRQPz7ybs6mUjHT3hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA 0agnwAjfB/ow4EH+3HEYV52qpxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/ cn318EhhQIDAQABo1AwTjAdBgNVHQ4EFgQUzQBVKTEknyLndWd2HTsBdTKvyikwHwYDVR0jBBgw FoAUzQBVKTEknyLndWd2HTsBdTKvyikwDAYDVR0TBAUwAwEB/w== -----END DATA----- -----BEGIN SIGNATURE----- A4GBADrHSmFSJw/Gv7hs5PNzpaJwAri/sitarIZfzN/SjR+n8L8yeTEoiDb1+BkxlFvXvPHTaOK oO3WlslNNOxh1W5/JkYYGOUkCcyIjnln6qS560imcr3VNjomT/M8M2Iss+rJiKau1TRuaP7H8i6 +Gqf3saGdr8/LnvFAdNQvkalQt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING rsa-pkcs1-sha256-using-ecdsa-algorithm.pem000064400000000000000000000040001261452200500315030ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis test specified a valid RSA PKCS#1 v.1.5 signature and RSA key (the same as rsa-pkcs1-sha256.pem). The problem however is the signature algorithm is indicated as being ECDSA. Signature verification consequently should fail. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp1JnY2zQIQRQPz7ybs6mUjHT3 hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA0agnwAjfB/ow4EH+3HEYV52q pxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/cn318EhhQIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MAoGCCqGSM49BAMC -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 10 cons: SEQUENCE 2:d=1 hl=2 l= 8 prim: OBJECT :ecdsa-with-SHA256 -----BEGIN DATA----- MIIB46ADAgECAgkA3l4tFOVii0UwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgN VBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1 UEAwwGTXkga2V5MB4XDTE1MDcwMjE3MDYzOVoXDTE2MDcwMTE3MDYzOVowVjELMAkGA1UEBhMCQ VUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGTXkga2V5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp 1JnY2zQIQRQPz7ybs6mUjHT3hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA 0agnwAjfB/ow4EH+3HEYV52qpxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/ cn318EhhQIDAQABo1AwTjAdBgNVHQ4EFgQUzQBVKTEknyLndWd2HTsBdTKvyikwHwYDVR0jBBgw FoAUzQBVKTEknyLndWd2HTsBdTKvyikwDAYDVR0TBAUwAwEB/w== -----END DATA----- -----BEGIN SIGNATURE----- A4GBADrHSmFSJw/Gv7hs5PNzpaJwAri/sitarIZfzN/SjR+n8L8yeTEoiDb1+BkxlFvXvPHTaOK oO3WlslNNOxh1W5/JkYYGOUkCcyIjnln6qS560imcr3VNjomT/M8M2Iss+rJiKau1TRuaP7H8i6 +Gqf3saGdr8/LnvFAdNQvkalQt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha256-using-id-ea-rsa.pem000064400000000000000000000037741261452200500303020ustar0000000000000000This is the same test as rsa-pkcs1-sha256.pem except the SPKI has been tampered with. Rather than using an rsaEncryption OID for the key's algorithm, it uses id-ea-rsa (2.5.8.1.1). -----BEGIN PUBLIC KEY----- MIGaMAgGBFUIAQEFAAOBjQAwgYkCgYEAqkfgdjI9YqzadSZ2Ns0CEEUD8+8m7OplIx094X+QD8m ooNrunwT04asbLIINGL4qiI/+9IVSvyV3Kj9c4EeQIbANGoJ8AI3wf6MOBB/txxGFedqqcTffKV MQvtZdoYFbZ/MQkvyRsoyvunb/pWcN4sSaF9kY1bXSeP3J99fBIYUCAwEAAQ== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 154 cons: SEQUENCE 3:d=1 hl=2 l= 8 cons: SEQUENCE 5:d=2 hl=2 l= 4 prim: OBJECT :rsa 11:d=2 hl=2 l= 0 prim: NULL 13:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCwUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- MIIB46ADAgECAgkA3l4tFOVii0UwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgN VBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1 UEAwwGTXkga2V5MB4XDTE1MDcwMjE3MDYzOVoXDTE2MDcwMTE3MDYzOVowVjELMAkGA1UEBhMCQ VUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGTXkga2V5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp 1JnY2zQIQRQPz7ybs6mUjHT3hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA 0agnwAjfB/ow4EH+3HEYV52qpxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/ cn318EhhQIDAQABo1AwTjAdBgNVHQ4EFgQUzQBVKTEknyLndWd2HTsBdTKvyikwHwYDVR0jBBgw FoAUzQBVKTEknyLndWd2HTsBdTKvyikwDAYDVR0TBAUwAwEB/w== -----END DATA----- -----BEGIN SIGNATURE----- A4GBADrHSmFSJw/Gv7hs5PNzpaJwAri/sitarIZfzN/SjR+n8L8yeTEoiDb1+BkxlFvXvPHTaOK oO3WlslNNOxh1W5/JkYYGOUkCcyIjnln6qS560imcr3VNjomT/M8M2Iss+rJiKau1TRuaP7H8i6 +Gqf3saGdr8/LnvFAdNQvkalQt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pkcs1-sha256.pem000064400000000000000000000054271261452200500254140ustar0000000000000000This test data was produced by creating a self-signed EC cert using OpenSSL, and then extracting the relevant fields. It uses RSA PKCS#1 v1.5 with SHA-256 and a 1024-bit key. (1) Generate self-signed certificate openssl genrsa -out rsa_key.pem 1024 openssl req -new -key rsa_key.pem -x509 -nodes -days 365 -out cert.pem (2) Extract public key openssl x509 -in cert.pem -pubkey -noout > pubkey.pem cat pubkey.pem (3) Extract signed data (tbsCertificate) openssl asn1parse -in cert.pem -out tbs -noout -strparse 4 base64 tbs (4) Extract signature algorithm # Find the offset of the signature algorithm near the end (491 in this case) openssl asn1parse -in cert.pem openssl asn1parse -in cert.pem -out alg -noout -strparse 491 base64 alg (5) Extract the signature # Find the final offset of BIT STRING (506 in this case) openssl asn1parse -in cert.pem openssl asn1parse -in cert.pem -out sig -noout -strparse 506 base64 sig -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp1JnY2zQIQRQPz7ybs6mUjHT3 hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA0agnwAjfB/ow4EH+3HEYV52q pxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/cn318EhhQIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCwUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- MIIB46ADAgECAgkA3l4tFOVii0UwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgN VBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1 UEAwwGTXkga2V5MB4XDTE1MDcwMjE3MDYzOVoXDTE2MDcwMTE3MDYzOVowVjELMAkGA1UEBhMCQ VUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGTXkga2V5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp 1JnY2zQIQRQPz7ybs6mUjHT3hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA 0agnwAjfB/ow4EH+3HEYV52qpxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/ cn318EhhQIDAQABo1AwTjAdBgNVHQ4EFgQUzQBVKTEknyLndWd2HTsBdTKvyikwHwYDVR0jBBgw FoAUzQBVKTEknyLndWd2HTsBdTKvyikwDAYDVR0TBAUwAwEB/w== -----END DATA----- -----BEGIN SIGNATURE----- A4GBADrHSmFSJw/Gv7hs5PNzpaJwAri/sitarIZfzN/SjR+n8L8yeTEoiDb1+BkxlFvXvPHTaOK oO3WlslNNOxh1W5/JkYYGOUkCcyIjnln6qS560imcr3VNjomT/M8M2Iss+rJiKau1TRuaP7H8i6 +Gqf3saGdr8/LnvFAdNQvkalQt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING rsa-pss-sha1-salt20-using-pss-key-no-params.pem000064400000000000000000000031411261452200500324460ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same test as rsa-pss-sha1-salt20.pem, except the public key's algorithm identifier has been changed from rsaEncryption (1.2.840.113549.1.1.1) to rsaPss (1.2.840.113549.1.1.10). -----BEGIN PUBLIC KEY----- MIGdMAsGCSqGSIb3DQEBCgOBjQAwgYkCgYEApW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h9 62ZHYxRBW/+2xYrTA8oOhKoijlN/1JqtykcuzB86r/OCx39XNlQgJbVsri2311nHvY3fAkhyyPC cKcOJZjm/4nRnxBazC0/DLNfKSgOE4a29kxO8i4eHyDQzoz/siSb2aITcCAwEAAQ== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 157 cons: SEQUENCE 3:d=1 hl=2 l= 11 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsassaPss 16:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCjAA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 0 cons: SEQUENCE -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAJB0MI+1mOlwGyKUOI5S+XH6rCtgpRRa8YXfUoe17SiH5Xzn/UTchjTkB8jg5DYLwibz7CJ /nZ5UY46NMfUFEhXfbrucL5V5qndZijj5FLW5wb2DxOL584Kg0Ko1Qv/uZZhKYBvGnrKN6yfcoS yCwtTD9mzVAPH/K5lNik4wy7M8 -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING rsa-pss-sha1-salt20-using-pss-key-with-null-params.pem000064400000000000000000000033361261452200500337630ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same test as rsa-pss-sha1-salt20.pem, except the public key's algorithm identifier has been changed from rsaEncryption (1.2.840.113549.1.1.1) to rsaPss (1.2.840.113549.1.1.10). Note that the PSS parameters have been encoded as NULL which is incorrect. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBCgUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsassaPss 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCjAA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 0 cons: SEQUENCE -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAJB0MI+1mOlwGyKUOI5S+XH6rCtgpRRa8YXfUoe17SiH5Xzn/UTchjTkB8jg5DYLwibz7CJ /nZ5UY46NMfUFEhXfbrucL5V5qndZijj5FLW5wb2DxOL584Kg0Ko1Qv/uZZhKYBvGnrKN6yfcoS yCwtTD9mzVAPH/K5lNik4wy7M8 -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pss-sha1-salt20.pem000064400000000000000000000034731261452200500261260ustar0000000000000000The key, message, and signature come from Example 1.1 of: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip (pss-vect.txt) (The algorithm DER was synthesized to match, and the signature enclosed in a BIT STRING). It uses an RSA key with modulus length of 1024 bits, PSS padding, SHA-1 as the digest, MGF1 with SHA-1, and salt length of 20. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCjAA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 0 cons: SEQUENCE -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAJB0MI+1mOlwGyKUOI5S+XH6rCtgpRRa8YXfUoe17SiH5Xzn/UTchjTkB8jg5DYLwibz7CJ /nZ5UY46NMfUFEhXfbrucL5V5qndZijj5FLW5wb2DxOL584Kg0Ko1Qv/uZZhKYBvGnrKN6yfcoS yCwtTD9mzVAPH/K5lNik4wy7M8 -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pss-sha1-wrong-salt.pem000064400000000000000000000034311261452200500271100ustar0000000000000000Same as rsa-pss-sha1-wrong-salt.pem except the ALGORITHM has been changed to have a salt of 23. When verified using this algorithm it will fail, however if the default salt of 20 were used it would succeed. -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MBIGCSqGSIb3DQEBCjAFogMCARc= -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 18 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 5 cons: SEQUENCE 15:d=2 hl=2 l= 3 cons: cont [ 2 ] 17:d=3 hl=2 l= 1 prim: INTEGER :17 -----BEGIN DATA----- zch9oiPXht87ReC7vHITJtHuKvgGzDFUdcxvDZxm4bYjcdRc4jkuGskoRMMQEC8Vag2NUsH0xAu jqmUJV4bLdpdXplY7qVj+0LzJhOi1F6PV9RWyO4pB50qoZ2k/kN+wYabobfqu5kRywA5fIJRXKc vr538Gznjgj0CY+6QfnWGTwDF+i2DUtghKy0LSnjgIo7w3LYXjMRcPy/fMctC3HClmSLOk0Q9BY pXQgHqmJcqydE/Z6o/SI8QlNwKYKL0WvgJUbxMP0uM7k20mduCK7RtzMYt1CgFn0A== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAJB0MI+1mOlwGyKUOI5S+XH6rCtgpRRa8YXfUoe17SiH5Xzn/UTchjTkB8jg5DYLwibz7CJ /nZ5UY46NMfUFEhXfbrucL5V5qndZijj5FLW5wb2DxOL584Kg0Ko1Qv/uZZhKYBvGnrKN6yfcoS yCwtTD9mzVAPH/K5lNik4wy7M8 -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pss-sha256-mgf1-sha512-salt33.pem000064400000000000000000000044711261452200500301360ustar0000000000000000This test exercises using a different hash function parameter to the mask gen function (SHA-256 for the hash, but SHA-512 for the MGF1 hash). This test data was constructed manually by calling signing functions from OpenSSL code. It constructs an RSASSA-PSS signature using: * Key with modulus 1024 bit * Salt length 33 bytes * Digest function of SHA-256 * Mask gen function of MGF1 with SHA-512 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClbkoOcBAXWJpRh9x+qEHRVvLsDjatUqRN/rH mH3rZkdjFEFb/7bFitMDyg6EqiKOU3/Umq3KRy7MHzqv84LHf1c2VCAltWyuLbfXWce9jd8CSHL I8Jwpw4lmOb/idGfEFrMLT8Ms18pKA4Thrb2TE7yLh4fINDOjP+yJJvZohNwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 159 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 141 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIDBQCiAwIBIQ== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha256 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha512 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :21 -----BEGIN DATA----- VGVzdCBtZXNzYWdlIHRvIGJlIHNpZ25lZC4uLg== -----END DATA----- -----BEGIN SIGNATURE----- A4GBAFob0HSC5uuTqKu4J/lj+5bDa+Hhij4H3klWnvt6Yc+wwPza7/UC4lgGGyvZqD32RUEdt7v Z14qqYNk53b5aj4C2gBMvLzV7Pay4mmQM4DSWa5JHMxTILqE3DDqihrbMcBw2q3XAsLcjeqLWQ9 yp8tfnV21h98qsCLtErrxZWHRr -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING rsa-pss-sha256-salt10-using-pss-key-with-params.pem000064400000000000000000000057021261452200500331650ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same test as rsa-pss-sha256-salt10.pem except instead of specifying the SPKI using rsaEncryption it is specified using rsaPss along with parameters that match those of the signature algorithm. -----BEGIN PUBLIC KEY----- MIHRMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZ IAWUDBAIBBQCiAwIBCgOBiwAwgYcCgYEAvkmbXn8GyD+gKT4xRlyOtrWK+SC65Sp7W5v+t6py2x JkES6z/UMdMaKn5QlBVmkpSUoOiR7VYTkYtLUbDR+5d4Oyas99DzhM+zX00oJPXdOAYjomvxgLY 5YcYZ3NsgyuQG8i9uJ2yAo3JZSQz+tywacahPGEbTMId7o+MQHsnHsCARE= -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 209 cons: SEQUENCE 3:d=1 hl=2 l= 65 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsassaPss 16:d=2 hl=2 l= 52 cons: SEQUENCE 18:d=3 hl=2 l= 15 cons: cont [ 0 ] 20:d=4 hl=2 l= 13 cons: SEQUENCE 22:d=5 hl=2 l= 9 prim: OBJECT :sha256 33:d=5 hl=2 l= 0 prim: NULL 35:d=3 hl=2 l= 28 cons: cont [ 1 ] 37:d=4 hl=2 l= 26 cons: SEQUENCE 39:d=5 hl=2 l= 9 prim: OBJECT :mgf1 50:d=5 hl=2 l= 13 cons: SEQUENCE 52:d=6 hl=2 l= 9 prim: OBJECT :sha256 63:d=6 hl=2 l= 0 prim: NULL 65:d=3 hl=2 l= 3 cons: cont [ 2 ] 67:d=4 hl=2 l= 1 prim: INTEGER :0A 70:d=1 hl=3 l= 139 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIBBQCiAwIBCg== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha256 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha256 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :0A -----BEGIN DATA----- x/UnD8pyX5vRn1GajXzKPMXAeQJAKfO65RD5sCFA/iOJCOT2wY8HqJxofIaEZpsfHbK6+SUaPIK frMtJMIThbsnijViGgHSl1iIWZ91uUo0W/iyfPbTPr2xNzoyEOa84zqqqnOLsrnvI9KWlXjv5bf nNV1xPnLMnlRuM3+QIcWg= -----END DATA----- -----BEGIN SIGNATURE----- A4GBABHhafL9QLB2Qbl2iiqxmWX7bCfxD88DI/zG0S608cBrMw3aoepQRAevop3p6+A3T+nR59D /vV/Bzzo0RuQUVBXSqyT3ibNGTFxDola7wdaSz38EgB2sW7QBpKA6t9VyioYMGeGk3Hl8pULIID zsLmAesMUfVn8u2gIrC5693u76 -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING rsa-pss-sha256-salt10-using-pss-key-with-wrong-params.pem000064400000000000000000000056301261452200500343170ustar0000000000000000webpki-0.21.0/third-party/chromium/data/verify_signed_dataThis is the same test as rsa-pss-sha256-salt10-using-pss-key-with-params.pem except the hash in the PSS key's parameters has been changed from SHA-256 to SHA-384. -----BEGIN PUBLIC KEY----- MIHRMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZ IAWUDBAIBBQCiAwIBCgOBiwAwgYcCgYEAvkmbXn8GyD+gKT4xRlyOtrWK+SC65Sp7W5v+t6py2x JkES6z/UMdMaKn5QlBVmkpSUoOiR7VYTkYtLUbDR+5d4Oyas99DzhM+zX00oJPXdOAYjomvxgLY 5YcYZ3NsgyuQG8i9uJ2yAo3JZSQz+tywacahPGEbTMId7o+MQHsnHsCARE= -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 209 cons: SEQUENCE 3:d=1 hl=2 l= 65 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsassaPss 16:d=2 hl=2 l= 52 cons: SEQUENCE 18:d=3 hl=2 l= 15 cons: cont [ 0 ] 20:d=4 hl=2 l= 13 cons: SEQUENCE 22:d=5 hl=2 l= 9 prim: OBJECT :sha384 33:d=5 hl=2 l= 0 prim: NULL 35:d=3 hl=2 l= 28 cons: cont [ 1 ] 37:d=4 hl=2 l= 26 cons: SEQUENCE 39:d=5 hl=2 l= 9 prim: OBJECT :mgf1 50:d=5 hl=2 l= 13 cons: SEQUENCE 52:d=6 hl=2 l= 9 prim: OBJECT :sha256 63:d=6 hl=2 l= 0 prim: NULL 65:d=3 hl=2 l= 3 cons: cont [ 2 ] 67:d=4 hl=2 l= 1 prim: INTEGER :0A 70:d=1 hl=3 l= 139 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIBBQCiAwIBCg== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha256 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha256 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :0A -----BEGIN DATA----- x/UnD8pyX5vRn1GajXzKPMXAeQJAKfO65RD5sCFA/iOJCOT2wY8HqJxofIaEZpsfHbK6+SUaPIK frMtJMIThbsnijViGgHSl1iIWZ91uUo0W/iyfPbTPr2xNzoyEOa84zqqqnOLsrnvI9KWlXjv5bf nNV1xPnLMnlRuM3+QIcWg= -----END DATA----- -----BEGIN SIGNATURE----- A4GBABHhafL9QLB2Qbl2iiqxmWX7bCfxD88DI/zG0S608cBrMw3aoepQRAevop3p6+A3T+nR59D /vV/Bzzo0RuQUVBXSqyT3ibNGTFxDola7wdaSz38EgB2sW7QBpKA6t9VyioYMGeGk3Hl8pULIID zsLmAesMUfVn8u2gIrC5693u76 -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-pss-sha256-salt10.pem000064400000000000000000000046231261452200500262770ustar0000000000000000The key, message, and signature come from: http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-2rsatestvectors.zip (SigVerPSS_186-3.rsp) (The algorithm DER was synthesized to match, and the signature wrapped in a BIT STRING). It uses an RSA key with modulus length of 1024 bits, PSS padding, SHA-256 as the digest, MGF1 with SHA-256, and salt length of 10. -----BEGIN PUBLIC KEY----- MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC+SZtefwbIP6ApPjFGXI62tYr5ILrlKntbm/6 3qnLbEmQRLrP9Qx0xoqflCUFWaSlJSg6JHtVhORi0tRsNH7l3g7Jqz30POEz7NfTSgk9d04BiOi a/GAtjlhxhnc2yDK5AbyL24nbICjcllJDP63LBpxqE8YRtMwh3uj4xAeycewIBEQ== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=3 l= 157 cons: SEQUENCE 3:d=1 hl=2 l= 13 cons: SEQUENCE 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 16:d=2 hl=2 l= 0 prim: NULL 18:d=1 hl=3 l= 139 prim: BIT STRING -----BEGIN ALGORITHM----- MEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWU DBAIBBQCiAwIBCg== -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 65 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :rsassaPss 13:d=1 hl=2 l= 52 cons: SEQUENCE 15:d=2 hl=2 l= 15 cons: cont [ 0 ] 17:d=3 hl=2 l= 13 cons: SEQUENCE 19:d=4 hl=2 l= 9 prim: OBJECT :sha256 30:d=4 hl=2 l= 0 prim: NULL 32:d=2 hl=2 l= 28 cons: cont [ 1 ] 34:d=3 hl=2 l= 26 cons: SEQUENCE 36:d=4 hl=2 l= 9 prim: OBJECT :mgf1 47:d=4 hl=2 l= 13 cons: SEQUENCE 49:d=5 hl=2 l= 9 prim: OBJECT :sha256 60:d=5 hl=2 l= 0 prim: NULL 62:d=2 hl=2 l= 3 cons: cont [ 2 ] 64:d=3 hl=2 l= 1 prim: INTEGER :0A -----BEGIN DATA----- x/UnD8pyX5vRn1GajXzKPMXAeQJAKfO65RD5sCFA/iOJCOT2wY8HqJxofIaEZpsfHbK6+SUaPIK frMtJMIThbsnijViGgHSl1iIWZ91uUo0W/iyfPbTPr2xNzoyEOa84zqqqnOLsrnvI9KWlXjv5bf nNV1xPnLMnlRuM3+QIcWg= -----END DATA----- -----BEGIN SIGNATURE----- A4GBABHhafL9QLB2Qbl2iiqxmWX7bCfxD88DI/zG0S608cBrMw3aoepQRAevop3p6+A3T+nR59D /vV/Bzzo0RuQUVBXSqyT3ibNGTFxDola7wdaSz38EgB2sW7QBpKA6t9VyioYMGeGk3Hl8pULIID zsLmAesMUfVn8u2gIrC5693u76 -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa-using-ec-key.pem000064400000000000000000000036251261452200500256630ustar0000000000000000This test specifies an RSA PKCS#1 v1.5 signature algorithm (and a valid RSA signature), HOWEVER it provides an EC key. Verification should fail. -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnLDPaTA9r8dh1ORoe07PA55tNKuWSvgIENjVWKS o1vctUSM6F4iSCobuCKGWLHnvoxf7eHnil9rSFG25lfoceA== -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=2 l= 89 cons: SEQUENCE 2:d=1 hl=2 l= 19 cons: SEQUENCE 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 23:d=1 hl=2 l= 66 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBCwUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- MIIB46ADAgECAgkA3l4tFOVii0UwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCQVUxEzARBgN VBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1 UEAwwGTXkga2V5MB4XDTE1MDcwMjE3MDYzOVoXDTE2MDcwMTE3MDYzOVowVjELMAkGA1UEBhMCQ VUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEPMA0GA1UEAwwGTXkga2V5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqR+B2Mj1irNp 1JnY2zQIQRQPz7ybs6mUjHT3hf5APyaig2u6fBPThqxssgg0YviqIj/70hVK/JXcqP1zgR5AhsA 0agnwAjfB/ow4EH+3HEYV52qpxN98pUxC+1l2hgVtn8xCS/JGyjK+6dv+lZw3ixJoX2RjVtdJ4/ cn318EhhQIDAQABo1AwTjAdBgNVHQ4EFgQUzQBVKTEknyLndWd2HTsBdTKvyikwHwYDVR0jBBgw FoAUzQBVKTEknyLndWd2HTsBdTKvyikwDAYDVR0TBAUwAwEB/w== -----END DATA----- -----BEGIN SIGNATURE----- A4GBADrHSmFSJw/Gv7hs5PNzpaJwAri/sitarIZfzN/SjR+n8L8yeTEoiDb1+BkxlFvXvPHTaOK oO3WlslNNOxh1W5/JkYYGOUkCcyIjnln6qS560imcr3VNjomT/M8M2Iss+rJiKau1TRuaP7H8i6 +Gqf3saGdr8/LnvFAdNQvkalQt -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=3 l= 129 prim: BIT STRING webpki-0.21.0/third-party/chromium/data/verify_signed_data/rsa2048-pkcs1-sha512.pem000064400000000000000000000064031261452200500257200ustar0000000000000000This test data was produced by creating a self-signed RSA cert using OpenSSL, and then extracting the relevant fields. It uses RSA PKCS#1 v1.5 with SHA-512 and a 2048-bit key. (1) Generate self-signed certificate openssl genrsa -out rsa_key.pem 2048 openssl req -new -key rsa_key.pem -x509 -nodes -days 365 -sha512 -out cert.pem (2) Extract public key openssl x509 -in cert.pem -pubkey -noout > pubkey.pem cat pubkey.pem (3) Extract signed data (tbsCertificate) openssl asn1parse -in cert.pem -out tbs -noout -strparse 4 base64 tbs (4) Extract signature algorithm # Find the offset of the signature algorithm near the end (589 in this case) openssl asn1parse -in cert.pem openssl asn1parse -in cert.pem -out alg -noout -strparse 589 base64 alg (5) Extract the signature # Find the final offset of BIT STRING (506 in this case) openssl asn1parse -in cert.pem openssl asn1parse -in cert.pem -out sig -noout -strparse 506 base64 sig -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzcu2shJRrXFAwMkf30y2AY1zIg9VF/h egYcejzdR2AzUb8vU2TXld2i8pp44l+DrvtqmzS7G+yxx3uOx+zsoqBaUT0c9HfkbE+IRmcLkQF vYpSpm6Eu8OS14CSmEtiR91Et8LR0+bd0Gn3pgmb+epFJBaBPeDSiI/smqKCs7yP04+tS4Q4r47 G04LhSp4/hmqH32b4Gcm9nsihHV9FfPfVdxDQUEJp3AgyBPwhPZEAyhoQS73TjjxXHqJRSz37Sl ueMVPuNncqbT4nAMKz25J1CtRlQh21uZzfY2QRP3m6rAZquQUos1febC6A7qmhQljWKKmXtfVY+ fAamstdHrWwIDAQAB -----END PUBLIC KEY----- $ openssl asn1parse -i < [PUBLIC KEY] 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING -----BEGIN ALGORITHM----- MA0GCSqGSIb3DQEBDQUA -----END ALGORITHM----- $ openssl asn1parse -i < [ALGORITHM] 0:d=0 hl=2 l= 13 cons: SEQUENCE 2:d=1 hl=2 l= 9 prim: OBJECT :sha512WithRSAEncryption 13:d=1 hl=2 l= 0 prim: NULL -----BEGIN DATA----- MIICRaADAgECAgkA7jWRLkwHvHswDQYJKoZIhvcNAQENBQAwRTELMAkGA1UEBhMCQVUxEzARBgN VBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNT A3MjgwMjIyMzFaFw0xNjA3MjcwMjIyMzFaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lL VN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDNy7ayElGtcUDAyR/fTLYBjXMiD1UX+F6Bhx6PN1HYDNRvy9TZNeV 3aLymnjiX4Ou+2qbNLsb7LHHe47H7OyioFpRPRz0d+RsT4hGZwuRAW9ilKmboS7w5LXgJKYS2JH 3US3wtHT5t3QafemCZv56kUkFoE94NKIj+yaooKzvI/Tj61LhDivjsbTguFKnj+GaoffZvgZyb2 eyKEdX0V899V3ENBQQmncCDIE/CE9kQDKGhBLvdOOPFceolFLPftKW54xU+42dyptPicAwrPbkn UK1GVCHbW5nN9jZBE/ebqsBmq5BSizV95sLoDuqaFCWNYoqZe19Vj58Bqay10etbAgMBAAGjUDB OMB0GA1UdDgQWBBRsCPajkEscZM6SpLbNTa/7dY5azzAfBgNVHSMEGDAWgBRsCPajkEscZM6SpL bNTa/7dY5azzAMBgNVHRMEBTADAQH/ -----END DATA----- -----BEGIN SIGNATURE----- A4IBAQAhKSNq+X/CfzhtNsMo6MJpTBjJBV5fhHerIZr6e3ozCTBCR29vYsVnJ4/6i5lL1pNeOhM ldthnuSlMzTS1Zme1OqRWB3U8QmwCFwhDxW/i4fdT8kxDAmELNp4z0GcXbe27V895PE0R/m8P47 B6xbra+SQlEMW12K1EndUqrO6vgLbobV14mveWdgc0KIOnDKgsTHV8NTV1w3qtp1ujfvizYfBZu yyMOA1yZPDpREZtClro7lufwDQ7+LgSdtNLMDAMzapfIjAEPVNVLmJzMgzaHqMsZM8gP8vWAdfc R4mCmWXVotrM6d1rjJGdRADAONYCC4/+d1IMkVGoVfpaej6I -----END SIGNATURE----- $ openssl asn1parse -i < [SIGNATURE] 0:d=0 hl=4 l= 257 prim: BIT STRING webpki-0.21.0/.cargo_vcs_info.json0000644000000001120000000000000124260ustar00{ "git": { "sha1": "482627c40dad2148da8b9bf64c2c781ea30a7e4d" } }