diff --git a/Cargo.toml b/Cargo.toml index 41f8f4d..375b4de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,17 +11,17 @@ categories = ["web-programming", "api-bindings"] edition = "2018" [dependencies] -base64 = "0.21.5" +base64 = "0.22.1" lazy_static = "1" log = "0.4" openssl = "0.10" serde = { version = "1", features = ["derive"] } serde_json = "1" -time = { version = "0.1.45" } +time = { version = "0.3.36", features = ["parsing", "formatting", "macros"] } ureq = "2" [dev-dependencies] -env_logger = { version = "0.7", default-features = false } +env_logger = { version = "0.11.3", default-features = false } futures = "0.1.25" hyper = "0.12" regex = "1.3" diff --git a/src/acc/mod.rs b/src/acc/mod.rs index 6870a84..37d258a 100644 --- a/src/acc/mod.rs +++ b/src/acc/mod.rs @@ -99,7 +99,8 @@ impl Account

{ .and_then(|s| String::from_utf8(s).ok()); Ok(match (private_key, certificate) { - (Some(k), Some(c)) => Some(Certificate::new(k, c)), + // TODO: add chain + (Some(k), Some(c)) => Some(Certificate::new(k, c, vec![])), _ => None, }) } @@ -134,6 +135,7 @@ impl Account

{ let res = self.inner.transport.call(new_order_url, &order)?; let order_url = req_expect_header(&res, "location")?; + let api_order: ApiOrder = read_json(res)?; let order = Order::new(&self.inner, api_order, order_url); diff --git a/src/cert.rs b/src/cert.rs index c32551a..10bf09d 100644 --- a/src/cert.rs +++ b/src/cert.rs @@ -7,12 +7,17 @@ use openssl::rsa::Rsa; use openssl::stack::Stack; use openssl::x509::extension::SubjectAlternativeName; use openssl::x509::{X509Req, X509ReqBuilder, X509}; +use time::macros::format_description; use crate::Result; lazy_static! { pub(crate) static ref EC_GROUP_P256: EcGroup = ec_group(Nid::X9_62_PRIME256V1); pub(crate) static ref EC_GROUP_P384: EcGroup = ec_group(Nid::SECP384R1); + + pub(self) static ref TIME_FORMAT: &'static [time::format_description::BorrowedFormatItem<'static>] = format_description!( + "[month repr:short] [day padding:none] [hour padding:zero]:[minute padding:zero]:[second padding:zero] [year] GMT" + ); } fn ec_group(nid: Nid) -> EcGroup { @@ -77,13 +82,15 @@ pub(crate) fn create_csr(pkey: &PKey, domains: &[&str]) -> Result pub struct Certificate { private_key: String, certificate: String, + chain: Vec, } impl Certificate { - pub(crate) fn new(private_key: String, certificate: String) -> Self { + pub(crate) fn new(private_key: String, certificate: String, chain: Vec) -> Self { Certificate { private_key, certificate, + chain, } } @@ -103,6 +110,10 @@ impl Certificate { &self.certificate } + pub fn chain(&self) -> &Vec { + &self.chain + } + /// The issued certificate as DER. pub fn certificate_der(&self) -> Vec { let x509 = X509::from_pem(self.certificate.as_bytes()).expect("from_pem"); @@ -130,24 +141,30 @@ impl Certificate { // Display trait produces this format, which is kinda dumb. // Apr 19 08:48:46 2019 GMT let expires = parse_date(¬_after); - let dur = expires - time::now(); + let dur = expires - time::OffsetDateTime::now_utc(); - dur.num_days() + dur.whole_days() } } -fn parse_date(s: &str) -> time::Tm { +fn parse_date(s: &str) -> time::OffsetDateTime { debug!("Parse date/time: {}", s); - time::strptime(s, "%h %e %H:%M:%S %Y %Z").expect("strptime") + + time::PrimitiveDateTime::parse(s, &TIME_FORMAT) + .expect("OffsetDateTime") + .assume_utc() } #[cfg(test)] mod test { + use time::macros::datetime; + use super::*; #[test] fn test_parse_date() { - let x = parse_date("May 3 07:40:15 2019 GMT"); - assert_eq!(time::strftime("%F %T", &x).unwrap(), "2019-05-03 07:40:15"); + let x = parse_date("May 3 07:40:15 2019 GMT"); + + assert_eq!(x, datetime!(2019-05-03 07:40:15 +00:00)); } } diff --git a/src/order/mod.rs b/src/order/mod.rs index b1841c5..23c97b3 100644 --- a/src/order/mod.rs +++ b/src/order/mod.rs @@ -310,7 +310,8 @@ impl CertOrder

{ debug!("Save certificate: {}", pk_crt); persist.put(&pk_crt, cert.as_bytes())?; - Ok(Certificate::new(pkey_pem.to_string(), cert)) + // TODO add chain + Ok(Certificate::new(pkey_pem.to_string(), cert, vec![])) } /// Access the underlying JSON object for debugging. diff --git a/src/req.rs b/src/req.rs index a2fff1a..d9ab7db 100644 --- a/src/req.rs +++ b/src/req.rs @@ -67,6 +67,7 @@ pub(crate) fn req_handle_error( Err(problem) } +/// Extract a header from a response. pub(crate) fn req_expect_header(res: &ureq::Response, name: &str) -> ReqResult { res.header(name) .map(|v| v.to_string())