Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add verify_cert_ip_san (not to merge) #120

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub enum Error {
/// The certificate is not valid for the name it is being validated for.
CertNotValidForName,

/// The certificate is not valid for the ip it is being validated for.
CertNotValidForIp,

/// The certificate is not valid yet; i.e. the time it is being validated
/// for is earlier than the certificate's notBefore time.
CertNotValidYet,
Expand Down
64 changes: 64 additions & 0 deletions src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,43 @@ impl<'a> From<DNSNameRef<'a>> for &'a str {
}
}

/// An ip address
#[derive(Clone, Copy)]
pub enum IPAddress {
/// An ipv4 address
V4(Ipv4),
}

impl From<Ipv4> for IPAddress {
fn from(ipv4: Ipv4) -> IPAddress {
IPAddress::V4(ipv4)
}
}

/// An Ipv4 address
#[derive(Clone, Copy)]
pub struct Ipv4 {
bytes: [u8;4],
}

impl Ipv4 {
/// Create a new Ipv4 address from a byte array
pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4 {
Ipv4 { bytes: [a, b, c, d] }
}

fn matches(&self, ip: untrusted::Input) -> bool {
let mut reader = untrusted::Reader::new(ip);
for i in 0..4 {
if reader.read_byte() != Ok(self.bytes[i]) {
return false
}
}
// TODO: Check at end
return true;
}
}

pub fn verify_cert_dns_name(
cert: &super::EndEntityCert, DNSNameRef(dns_name): DNSNameRef,
) -> Result<(), Error> {
Expand Down Expand Up @@ -154,6 +191,33 @@ pub fn verify_cert_dns_name(
)
}

pub fn verify_cert_ip_san(
cert: &super::EndEntityCert, ip: IPAddress,
) -> Result<(), Error> {
let cert = &cert.inner;
iterate_names(
cert.subject,
cert.subject_alt_name,
Err(Error::CertNotValidForIp),
&|name| {
match name {
GeneralName::IPAddress(ip_addr) => {
match &ip {
IPAddress::V4(ipv4) => {
if ipv4.matches(ip_addr) {
return NameIteration::Stop(Ok(()))
}
}
}
}
_ => (),
}
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,
Expand Down
7 changes: 6 additions & 1 deletion src/webpki.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub mod trust_anchor_util;
mod verify_cert;

pub use error::Error;
pub use name::{DNSNameRef, InvalidDNSNameError};
pub use name::{DNSNameRef, InvalidDNSNameError, IPAddress, Ipv4};

#[cfg(feature = "std")]
pub use name::DNSName;
Expand Down Expand Up @@ -186,6 +186,11 @@ impl<'a> EndEntityCert<'a> {
name::verify_cert_dns_name(&self, dns_name)
}

/// Verifies that the certificate is valid for the given ip address
pub fn verify_is_valid_for_ip(&self, ip: IPAddress) -> Result<(), Error> {
name::verify_cert_ip_san(&self, ip)
}

/// Verifies that the certificate is valid for at least one of the given DNS
/// host names.
///
Expand Down