Browse Source

Correctly handle certificate expiration on openssl

The `openssl` crate now include methods to manipulate Asn1Time objects.
Before this improvement, the certificate had to be parsed from the DER
format using the `x509-parser` crate (which is therefore no longer
required).
https://github.com/sfackler/rust-openssl/pull/1173
https://github.com/sfackler/rust-openssl/issues/687
pull/31/head
Rodolphe Breard 5 years ago
parent
commit
a4e0ccfa51
  1. 7
      CONTRIBUTING.md
  2. 1
      acme_common/Cargo.toml
  3. 16
      acme_common/src/crypto/openssl_certificate.rs
  4. 6
      acme_common/src/error.rs

7
CONTRIBUTING.md

@ -15,12 +15,7 @@ Since the author is not a native English speaker, some of the texts used in this
### rust-openssl ### rust-openssl
The [openssl](https://crates.io/crates/openssl) crate does not expose the Asn1Time in a usable way, which requires ACMEd to parse certificates using an external library in order to get the `not after` field. This is sub-optimal.
- https://github.com/sfackler/rust-openssl/issues/687
- https://github.com/sfackler/rust-openssl/pull/673
An other improvement that would be appreciable is to add Curve 25519 support.
An improvement that would be appreciable is to add Curve 25519 support to the [openssl](https://crates.io/crates/openssl) crate.
- https://github.com/sfackler/rust-openssl/issues/947 - https://github.com/sfackler/rust-openssl/issues/947

1
acme_common/Cargo.toml

@ -24,7 +24,6 @@ reqwest = { version = "0.10", features = ["blocking", "default-tls"] }
serde_json = "1.0" serde_json = "1.0"
syslog = "5.0" syslog = "5.0"
toml = "0.5" toml = "0.5"
x509-parser = "0.7"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
nix = "0.17" nix = "0.17"

16
acme_common/src/crypto/openssl_certificate.rs

@ -8,8 +8,7 @@ use openssl::stack::Stack;
use openssl::x509::extension::{BasicConstraints, SubjectAlternativeName}; use openssl::x509::extension::{BasicConstraints, SubjectAlternativeName};
use openssl::x509::{X509Builder, X509Extension, X509NameBuilder, X509Req, X509ReqBuilder, X509}; use openssl::x509::{X509Builder, X509Extension, X509NameBuilder, X509Req, X509ReqBuilder, X509};
use std::collections::HashSet; use std::collections::HashSet;
use std::time::Duration;
use x509_parser::parse_x509_der;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
const APP_ORG: &str = "ACMEd"; const APP_ORG: &str = "ACMEd";
const APP_NAME: &str = "ACMEd"; const APP_NAME: &str = "ACMEd";
@ -67,12 +66,13 @@ impl X509Certificate {
} }
pub fn expires_in(&self) -> Result<Duration, Error> { pub fn expires_in(&self) -> Result<Duration, Error> {
let raw_crt = self.inner_cert.to_der()?;
let (_, crt) = parse_x509_der(&raw_crt).map_err(|_| Error::from("Invalid certificate."))?;
crt.tbs_certificate
.validity
.time_to_expiration()
.ok_or_else(|| Error::from("Invalid certificate validity."))
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() as i64;
let now = Asn1Time::from_unix(timestamp)?;
let not_after = self.inner_cert.not_after();
let diff = now.diff(not_after)?;
let nb_secs = diff.days * 24 * 60 * 60 + diff.secs;
let nb_secs = if nb_secs > 0 { nb_secs as u64 } else { 0 };
Ok(Duration::from_secs(nb_secs))
} }
pub fn subject_alt_names(&self) -> HashSet<String> { pub fn subject_alt_names(&self) -> HashSet<String> {

6
acme_common/src/error.rs

@ -57,6 +57,12 @@ impl From<std::sync::mpsc::RecvError> for Error {
} }
} }
impl From<std::time::SystemTimeError> for Error {
fn from(error: std::time::SystemTimeError) -> Self {
format!("SystemTimeError difference: {:?}", error.duration()).into()
}
}
impl From<syslog::Error> for Error { impl From<syslog::Error> for Error {
fn from(error: syslog::Error) -> Self { fn from(error: syslog::Error) -> Self {
format!("syslog error: {}", error).into() format!("syslog error: {}", error).into()

Loading…
Cancel
Save