Skip to content

Commit

Permalink
Merge 78c451c into 9e92828
Browse files Browse the repository at this point in the history
  • Loading branch information
Demi-Marie committed Mar 13, 2020
2 parents 9e92828 + 78c451c commit 4bd4aab
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 2 deletions.
1 change: 1 addition & 0 deletions rustls/Cargo.toml
Expand Up @@ -17,6 +17,7 @@ log = { version = "0.4.4", optional = true }
ring = "0.16.11"
sct = "0.6.0"
webpki = "0.21.0"
untrusted = "0.7.0"

[features]
default = ["logging"]
Expand Down
22 changes: 22 additions & 0 deletions rustls/src/verify/data/LICENSE
@@ -0,0 +1,22 @@
The files in this directory are taken from webpki. The license of webpki
is below:

Except 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.
1 change: 1 addition & 0 deletions rustls/src/verify/data/alg-ecdsa-p256.der
@@ -0,0 +1 @@
*�H�=*�H�=
Binary file added rustls/src/verify/data/alg-ecdsa-p384.der
Binary file not shown.
1 change: 1 addition & 0 deletions rustls/src/verify/data/alg-ed25519.der
@@ -0,0 +1 @@
+ep
Binary file added rustls/src/verify/data/alg-rsa-pkcs1-sha256.der
Binary file not shown.
Binary file added rustls/src/verify/data/alg-rsa-pkcs1-sha384.der
Binary file not shown.
Binary file added rustls/src/verify/data/alg-rsa-pkcs1-sha512.der
Binary file not shown.
Binary file added rustls/src/verify/data/alg-rsa-pss-sha256.der
Binary file not shown.
Binary file added rustls/src/verify/data/alg-rsa-pss-sha384.der
Binary file not shown.
Binary file added rustls/src/verify/data/alg-rsa-pss-sha512.der
Binary file not shown.
178 changes: 178 additions & 0 deletions rustls/src/verify/x509.rs
@@ -0,0 +1,178 @@
//! A non-validating X.509 certificate parser

#![deny(
exceeding_bitshifts,
invalid_type_param_default,
missing_fragment_specifier,
mutable_transmutes,
no_mangle_const_items,
overflowing_literals,
patterns_in_fns_without_body,
pub_use_of_private_extern_crate,
unknown_crate_types,
const_err,
order_dependent_trait_objects,
illegal_floating_point_literal_pattern,
improper_ctypes,
late_bound_lifetime_arguments,
non_camel_case_types,
non_shorthand_field_patterns,
non_snake_case,
non_upper_case_globals,
no_mangle_generic_items,
private_in_public,
stable_features,
type_alias_bounds,
tyvar_behind_raw_pointer,
unconditional_recursion,
unused_comparisons,
unreachable_pub,
anonymous_parameters,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_qualifications,
clippy::all
)]
#![forbid(
unsafe_code,
intra_doc_link_resolution_failure,
safe_packed_borrows,
while_true,
elided_lifetimes_in_paths,
bare_trait_objects
)]

use crate::SignatureScheme;
use ring::{error::Unspecified, io::der, signature};
use webpki::Error;

/// Extracts the subject public key info from a certificate
fn parse_certificate(certificate: &[u8]) -> Result<untrusted::Input<'_>, Unspecified> {
let (tbs, signature_algorithm) = untrusted::Input::from(certificate)
.read_all(Unspecified, |mut reader| {
der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)
})?
.read_all(Unspecified, |mut reader| {
// tbsCertificate
let tbs = der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)?;
// signatureAlgorithm
let signature_algorithm =
der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)?;
// signatureValue
der::bit_string_with_no_unused_bits(&mut reader)?;
Ok((tbs, signature_algorithm))
})?;
tbs.read_all(Unspecified, |mut reader| {
if reader.read_bytes(5)?.as_slice_less_safe() != [160, 3, 2, 1, 2] {
return Err(Unspecified);
}
// we already parsed the version above
// serialNumber
der::expect_tag_and_get_value(&mut reader, der::Tag::Integer)?;
// signature
if der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)? != signature_algorithm {
// signature algorithms don’t match
return Err(Unspecified);
}
// issuer
der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)?;
// validity
der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)?;
// subject
der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)?;
// subjectPublicKeyInfo
let spki = der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)?;
// subjectUniqueId and issuerUniqueId are unsupported
// We require extensions, as any use case we can think of needs them.
der::expect_tag_and_get_value(&mut reader, der::Tag::ContextSpecificConstructed3)?;
Ok(spki)
})
}

/// Parse a SubjectPublicKeyInfo into a “stripped” AlgorithmId and public key
fn parse_spki(spki: untrusted::Input<'_>) -> Result<(&[u8], &[u8]), Unspecified> {
spki.read_all(Unspecified, |mut reader| {
let stripped_algid = der::expect_tag_and_get_value(&mut reader, der::Tag::Sequence)?;
let pkey = der::bit_string_with_no_unused_bits(&mut reader)?;
Ok((
stripped_algid.as_slice_less_safe(),
pkey.as_slice_less_safe(),
))
})
}

/// Verify a signature, SPKI, message, and scheme.
fn verify_spki_signature(
signature: &[u8],
message: &[u8],
spki: untrusted::Input<'_>,
scheme: SignatureScheme,
) -> Result<(), Error> {
let (stripped_algid, pkey) = parse_spki(spki).map_err(|Unspecified| Error::BadDER)?;
verify_stripped_algid_signature(signature, message, stripped_algid, pkey, scheme)
}

/// Verify that `signature` was made by signing `message` with the private key
/// corresponding to the public key for `certificate`, using `scheme`.
pub(crate) fn verify_certificate_signature(
signature: &[u8],
message: &[u8],
certificate: &[u8],
scheme: SignatureScheme,
) -> Result<(), Error> {
let spki = parse_certificate(certificate).map_err(|Unspecified| Error::BadDER)?;
verify_spki_signature(signature, message, spki, scheme)
}

/// Verify a signature and signature scheme against a public key, message, and
/// “stripped” AlgorithmId
fn verify_stripped_algid_signature(
signature: &[u8],
message: &[u8],
stripped_algid: &[u8],
pkey: &[u8],
scheme: SignatureScheme,
) -> Result<(), Error> {
let algorithm: &dyn signature::VerificationAlgorithm = match (scheme, stripped_algid) {
(SignatureScheme::RSA_PKCS1_SHA256, include_bytes!("data/alg-rsa-pkcs1-sha256.der")) => {
&signature::RSA_PKCS1_2048_8192_SHA256
}
(SignatureScheme::RSA_PKCS1_SHA384, include_bytes!("data/alg-rsa-pkcs1-sha384.der")) => {
&signature::RSA_PKCS1_2048_8192_SHA384
}
(SignatureScheme::RSA_PKCS1_SHA512, include_bytes!("data/alg-rsa-pkcs1-sha384.der")) => {
&signature::RSA_PKCS1_2048_8192_SHA512
}
(SignatureScheme::ECDSA_NISTP256_SHA256, include_bytes!("data/alg-ecdsa-p256.der")) => {
&signature::ECDSA_P256_SHA256_ASN1
}
(SignatureScheme::ECDSA_NISTP384_SHA384, include_bytes!("data/alg-ecdsa-p384.der")) => {
&signature::ECDSA_P384_SHA384_ASN1
}
(SignatureScheme::ECDSA_NISTP384_SHA384, include_bytes!("data/alg-ecdsa-p256.der")) => {
&signature::ECDSA_P256_SHA384_ASN1
}
(SignatureScheme::ECDSA_NISTP256_SHA256, include_bytes!("data/alg-ecdsa-p384.der")) => {
&signature::ECDSA_P384_SHA256_ASN1
}
(SignatureScheme::ED25519, include_bytes!("data/alg-ed25519.der")) => &signature::ED25519,
(SignatureScheme::RSA_PSS_SHA256, include_bytes!("data/alg-rsa-pss-sha256.der")) => {
&signature::RSA_PSS_2048_8192_SHA256
}
(SignatureScheme::RSA_PSS_SHA384, include_bytes!("data/alg-rsa-pss-sha384.der")) => {
&signature::RSA_PSS_2048_8192_SHA384
}
(SignatureScheme::RSA_PSS_SHA512, include_bytes!("data/alg-rsa-pss-sha512.der")) => {
&signature::RSA_PSS_2048_8192_SHA512
}
_ => return Err(Error::UnsupportedSignatureAlgorithmForPublicKey),
};
signature::UnparsedPublicKey::new(algorithm, pkey)
.verify(message, signature)
.map_err(|Unspecified| Error::InvalidSignatureForPublicKey)
}
3 changes: 1 addition & 2 deletions rustls/tests/api.rs
Expand Up @@ -5,7 +5,6 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::mem;
use std::fmt;
use std::env;
use std::error::Error;
use std::io::{self, Write, Read};

use rustls;
Expand Down Expand Up @@ -1221,7 +1220,7 @@ fn stream_write_reports_underlying_io_error_before_plaintext_processed() {
assert!(rc.is_err());
let err = rc.err().unwrap();
assert_eq!(err.kind(), io::ErrorKind::WouldBlock);
assert_eq!(err.description(), "oops");
assert_eq!(err.to_string(), "oops");
}

#[test]
Expand Down

0 comments on commit 4bd4aab

Please sign in to comment.