Refactor features.

Test all feature configurations in CI.

Remove the `trust_anchor_utils` feature flag.

Guard all features that directly require allocation with a new `alloc` feature.
The RSA features will be handled separately.

Document the features. Tell docs.rs to document all features.

Adjust some tests so that tests are run in more configurations.
This commit is contained in:
Brian Smith 2021-01-06 13:44:05 -08:00
parent 64708f1b6a
commit 2deeb79c74
10 changed files with 51 additions and 27 deletions

View File

@ -128,6 +128,7 @@ jobs:
matrix:
features:
- # Default
- --features=alloc
- --all-features
target:

View File

@ -56,13 +56,16 @@ include = [
"third-party/chromium/**/*",
]
[package.metadata.docs.rs]
all-features = true
[lib]
name = "webpki"
path = "src/webpki.rs"
[features]
trust_anchor_util = ["std"]
std = []
alloc = []
std = ["alloc"]
[dependencies]
ring = { version = "0.16.19", default-features = false, features = ["alloc"] }

View File

@ -93,5 +93,6 @@ impl fmt::Display for Error {
}
}
/// Requires the `std` feature.
#[cfg(feature = "std")]
impl ::std::error::Error for Error {}

View File

@ -15,7 +15,8 @@
mod dns_name;
pub use dns_name::{DnsNameRef, InvalidDnsNameError};
#[cfg(feature = "std")]
/// Requires the `alloc` feature.
#[cfg(feature = "alloc")]
pub use dns_name::DnsName;
mod ip_address;

View File

@ -12,6 +12,9 @@
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#[cfg(feature = "alloc")]
use alloc::string::String;
/// 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.
@ -28,11 +31,14 @@
/// 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")]
///
/// Requires the `alloc` feature.
#[cfg(feature = "alloc")]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct DnsName(String);
#[cfg(feature = "std")]
/// Requires the `alloc` feature.
#[cfg(feature = "alloc")]
impl DnsName {
/// Returns a `DnsNameRef` that refers to this `DnsName`.
pub fn as_ref(&self) -> DnsNameRef {
@ -40,15 +46,17 @@ impl DnsName {
}
}
#[cfg(feature = "std")]
/// Requires the `alloc` feature.
#[cfg(feature = "alloc")]
impl AsRef<str> for DnsName {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
/// Requires the `alloc` feature.
// Deprecated
#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl From<DnsNameRef<'_>> for DnsName {
fn from(dns_name: DnsNameRef) -> Self {
dns_name.to_owned()
@ -89,6 +97,7 @@ impl core::fmt::Display for InvalidDnsNameError {
}
}
/// Requires the `std` feature.
#[cfg(feature = "std")]
impl ::std::error::Error for InvalidDnsNameError {}
@ -110,7 +119,9 @@ impl<'a> DnsNameRef<'a> {
}
/// Constructs a `DnsName` from this `DnsNameRef`
#[cfg(feature = "std")]
///
/// Requires the `alloc` feature.
#[cfg(feature = "alloc")]
pub fn to_owned(&self) -> DnsName {
// DnsNameRef is already guaranteed to be valid ASCII, which is a
// subset of UTF-8.
@ -119,7 +130,8 @@ impl<'a> DnsNameRef<'a> {
}
}
#[cfg(feature = "std")]
/// Requires the `alloc` feature.
#[cfg(feature = "alloc")]
impl core::fmt::Debug for DnsNameRef<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
let lowercase = self.clone().to_owned();
@ -768,8 +780,6 @@ mod tests {
#[test]
fn presented_matches_reference_test() {
for &(presented, reference, expected_result) in PRESENTED_MATCHES_REFERENCE {
use std::string::String;
let actual_result = presented_id_matches_reference_id(
untrusted::Input::from(presented),
untrusted::Input::from(reference),
@ -777,9 +787,9 @@ mod tests {
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)
"presented_dns_id_matches_reference_dns_id(\"{:?}\", IDRole::ReferenceID, \"{:?}\")",
presented,
reference
);
}
}

View File

@ -348,8 +348,8 @@ const ED_25519: AlgorithmIdentifier = AlgorithmIdentifier {
#[cfg(test)]
mod tests {
use crate::{der, signed_data, Error};
use std::{self, io::BufRead, string::String, vec::Vec};
use alloc::{string::String, vec::Vec};
use std::io::BufRead as _;
// TODO: The expected results need to be modified for SHA-1 deprecation.

View File

@ -14,9 +14,6 @@
//! 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
@ -45,6 +42,8 @@ impl Time {
/// # Ok(())
/// # }
/// ```
///
/// Requires the `std` feature.
#[cfg(feature = "std")]
pub fn try_from(time: std::time::SystemTime) -> Result<Time, ring::error::Unspecified> {
time.duration_since(std::time::UNIX_EPOCH)

View File

@ -14,6 +14,9 @@
//! Utilities for efficiently embedding trust anchors in programs.
#[cfg(feature = "alloc")]
use alloc::string::String;
use super::der;
use crate::{
cert::{certificate_serial_number, parse_cert_internal, Cert, EndEntityOrCA},
@ -60,6 +63,9 @@ fn possibly_invalid_certificate_serial_number(input: &mut untrusted::Reader) ->
/// 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.
///
/// Requires the `alloc` feature.
#[cfg(feature = "alloc")]
pub fn generate_code_for_trust_anchors(name: &str, trust_anchors: &[TrustAnchor]) -> String {
let decl = format!(
"static {}: [TrustAnchor<'static>; {}] = ",

View File

@ -16,13 +16,23 @@
//!
//! See `EndEntityCert`'s documentation for a description of the certificate
//! processing steps necessary for a TLS connection.
//!
//! # Features
//!
//! | Feature | Description |
//! | ------- | ----------- |
//! | `alloc` | Enable features that require use of the heap. |
//! | `std` | Enable features that require libstd. Implies `alloc`. |
#![doc(html_root_url = "https://briansmith.org/rustdoc/")]
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::single_match)]
#[cfg(all(test, not(feature = "std")))]
#[cfg(any(test, feature = "alloc"))]
#[macro_use]
extern crate alloc;
#[cfg(test)]
extern crate std;
#[macro_use]
@ -35,7 +45,6 @@ mod name;
mod signed_data;
mod time;
#[cfg(feature = "trust_anchor_util")]
pub mod trust_anchor_util;
mod verify_cert;

View File

@ -12,10 +12,8 @@
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#[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,
@ -30,7 +28,6 @@ static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[
/* Checks we can verify netflix's cert chain. This is notable
* because they're rooted at a Verisign v1 root. */
#[cfg(feature = "trust_anchor_util")]
#[test]
pub fn netflix() {
let ee = include_bytes!("netflix/ee.der");
@ -50,7 +47,6 @@ pub fn netflix() {
);
}
#[cfg(feature = "trust_anchor_util")]
#[test]
pub fn ed25519() {
let ee = include_bytes!("ed25519/ee.der");
@ -69,7 +65,6 @@ pub fn ed25519() {
);
}
#[cfg(feature = "trust_anchor_util")]
#[test]
fn read_root_with_zero_serial() {
let ca = include_bytes!("misc/serial_zero.der");
@ -77,7 +72,6 @@ fn read_root_with_zero_serial() {
.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");