Skip to content

Commit

Permalink
Drop dependency on the time crate; use std::time::SystemTime.
Browse files Browse the repository at this point in the history
  • Loading branch information
briansmith committed Aug 18, 2017
1 parent 83e767f commit edbbb81
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 52 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ trust_anchor_util = []

[dependencies]
ring = "0.11"
time = "0.1"
untrusted = "0.5"

[dev-dependencies]
Expand Down
51 changes: 8 additions & 43 deletions src/der.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,21 @@ pub fn small_nonnegative_integer<'a>(input: &'a mut untrusted::Reader)


pub fn time_choice<'a>(input: &mut untrusted::Reader<'a>)
-> Result<time::Timespec, Error> {
-> Result<time::Time, Error> {
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<i32, Error> {
fn read_digit(inner: &mut untrusted::Reader) -> Result<u64, Error> {
let b = try!(inner.read_byte().map_err(|_| Error::BadDERTime));
if b < b'0' || b > b'9' {
return Err(Error::BadDERTime);
}
Ok((b - b'0') as i32)
Ok((b - b'0') as u64)
}

fn read_two_digits(inner: &mut untrusted::Reader, min: i32, max: i32)
-> Result<i32, Error> {
fn read_two_digits(inner: &mut untrusted::Reader, min: u64, max: u64)
-> Result<u64, Error> {
let hi = try!(read_digit(inner));
let lo = try!(read_digit(inner));
let value = (hi * 10) + lo;
Expand All @@ -144,27 +144,8 @@ pub fn time_choice<'a>(input: &mut untrusted::Reader<'a>)
};

let year = (year_hi * 100) + year_lo;
// 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 month = try!(read_two_digits(value, 1, 12));
let days_in_month = match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 =>
if (year % 4 == 0) &&
((year % 100 != 0) || (year % 400 == 0)) {
29
} else {
28
},
_ => unreachable!() // `read_two_digits` already bounds-checked it.
};

let days_in_month = time::days_in_month(year, month);
let day_of_month = try!(read_two_digits(value, 1, days_in_month));
let hours = try!(read_two_digits(value, 0, 23));
let minutes = try!(read_two_digits(value, 0, 59));
Expand All @@ -175,24 +156,8 @@ pub fn time_choice<'a>(input: &mut untrusted::Reader<'a>)
return Err(Error::BadDERTime);
}

// XXX: We need to audit the `time` crate for correctness.
let tm = time::Tm {
tm_year: year - 1900,
tm_mon: month - 1,
tm_mday: day_of_month,
tm_hour: hours,
tm_min: minutes,
tm_sec: seconds,
tm_nsec: 0,

// These should all be ignored by `to_timespec`.
tm_wday: 0,
tm_yday: 0,
tm_isdst: 0,
tm_utcoff: 0,
};

Ok(tm.to_timespec())
time::time_from_ymdhms_utc(year, month, day_of_month, hours, minutes,
seconds)
})
}

Expand Down
114 changes: 114 additions & 0 deletions src/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// 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.

// XXX: This depends on the `std` modulue. TODO: Create a `#![no_std]`
// interface.

use std;
use super::Error;

pub type Time = std::time::SystemTime;

pub fn time_from_ymdhms_utc(year: u64, month: u64, day_of_month: u64,
hours: u64, minutes: u64, seconds: u64)
-> Result<Time, Error> {
let days_before_year_since_unix_epoch =
try!(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(std::time::UNIX_EPOCH +
std::time::Duration::from_secs(seconds_since_unix_epoch))
}

fn days_before_year_since_unix_epoch(year: u64) -> Result<u64, Error> {
// 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 {
use super::{DAYS_BEFORE_UNIX_EPOCH_AD, days_before_year_ad};

#[test]
fn test_days_before_unix_epoch() {
assert_eq!(DAYS_BEFORE_UNIX_EPOCH_AD, days_before_year_ad(1970));
}
}
11 changes: 5 additions & 6 deletions src/verify_cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use untrusted;
use {cert, der, Error, name, signed_data, SignatureAlgorithm, TrustAnchor};
use {cert, der, Error, name, signed_data, SignatureAlgorithm, time,
TrustAnchor};
use cert::{Cert, EndEntityOrCA};
use time;

pub fn build_chain<'a>(required_eku_if_present: KeyPurposeId,
supported_sig_algs: &[&SignatureAlgorithm],
trust_anchors: &'a [TrustAnchor],
intermediate_certs: &[untrusted::Input<'a>],
cert: &Cert<'a>, time: time::Timespec,
sub_ca_count: usize)
cert: &Cert<'a>, time: time::Time, sub_ca_count: usize)
-> Result<(), Error> {
let used_as_ca = used_as_ca(&cert.ee_or_ca);

Expand Down Expand Up @@ -138,7 +137,7 @@ fn check_signatures(supported_sig_algs: &[&SignatureAlgorithm],
}

fn check_issuer_independent_properties<'a>(
cert: &Cert<'a>, time: time::Timespec, used_as_ca: UsedAsCA,
cert: &Cert<'a>, time: time::Time, used_as_ca: UsedAsCA,
sub_ca_count: usize, required_eku_if_present: KeyPurposeId)
-> Result<(), Error> {
// TODO: try!(check_distrust(trust_anchor_subject,
Expand All @@ -163,7 +162,7 @@ fn check_issuer_independent_properties<'a>(
}

// https://tools.ietf.org/html/rfc5280#section-4.1.2.5
fn check_validity(input: &mut untrusted::Reader, time: time::Timespec)
fn check_validity(input: &mut untrusted::Reader, time: time::Time)
-> Result<(), Error> {
let not_before = try!(der::time_choice(input));
let not_after = try!(der::time_choice(input));
Expand Down
4 changes: 2 additions & 2 deletions src/webpki.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
extern crate std;

extern crate ring;
extern crate time;

#[cfg(test)]
extern crate base64;
Expand All @@ -95,6 +94,7 @@ mod der;
mod cert;
mod name;
mod signed_data;
mod time;

#[cfg(feature = "trust_anchor_util")]
pub mod trust_anchor_util;
Expand Down Expand Up @@ -167,7 +167,7 @@ impl <'a> EndEntityCert<'a> {
pub fn verify_is_valid_tls_server_cert(
&self, supported_sig_algs: &[&SignatureAlgorithm],
trust_anchors: &[TrustAnchor],
intermediate_certs: &[untrusted::Input], time: time::Timespec)
intermediate_certs: &[untrusted::Input], time: time::Time)
-> Result<(), Error> {
verify_cert::build_chain(verify_cert::EKU_SERVER_AUTH,
supported_sig_algs, trust_anchors,
Expand Down

0 comments on commit edbbb81

Please sign in to comment.