From 558f51a167f5a0b1db7285ee219e563ae45c025d Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 14 Apr 2021 14:56:40 +0200 Subject: [PATCH] make revocation workflow accessible without client Signed-off-by: Wolfgang Bumiller --- src/account.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ src/client.rs | 13 ++----------- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/account.rs b/src/account.rs index 83e01ad9..326bdd2d 100644 --- a/src/account.rs +++ b/src/account.rs @@ -218,6 +218,49 @@ impl Account { .map(Some), } } + + /// Prepare a request to revoke a certificate. + /// + /// The certificate can be either PEM or DER formatted. + /// + /// Note that this uses the account's key for authorization. + /// + /// Revocation using a certificate's private key is not yet implemented. + pub fn revoke_certificate( + &self, + certificate: &[u8], + reason: Option, + ) -> Result { + let cert = if certificate.starts_with(b"-----BEGIN CERTIFICATE-----") { + b64u::encode(&openssl::x509::X509::from_pem(certificate)?.to_der()?) + } else { + b64u::encode(certificate) + }; + + let data = match reason { + Some(reason) => serde_json::json!({ "certificate": cert, "reason": reason }), + None => serde_json::json!({ "certificate": cert }), + }; + + Ok(CertificateRevocation { + account: self, + data, + }) + } +} + +/// Certificate revocation involves converting the certificate to base64url encoded DER and then +/// embedding it in a json structure. Since we also need a nonce and possibly retry the request if +/// a `BadNonce` error happens, this caches the converted data for efficiency. +pub struct CertificateRevocation<'a> { + account: &'a Account, + data: Value, +} + +impl CertificateRevocation<'_> { + pub fn request(&self, directory: &Directory, nonce: &str) -> Result { + self.account.post_request(&directory.data.revoke_cert, nonce, &self.data) + } } #[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)] diff --git a/src/client.rs b/src/client.rs index 56500bd4..58baffad 100644 --- a/src/client.rs +++ b/src/client.rs @@ -548,16 +548,7 @@ impl Client { // TODO: This can also work without an account. let account = Self::need_account(&self.account)?; - let cert = if certificate.starts_with(b"-----BEGIN CERTIFICATE-----") { - b64u::encode(&openssl::x509::X509::from_pem(certificate)?.to_der()?) - } else { - b64u::encode(certificate) - }; - - let data = match reason { - Some(reason) => serde_json::json!({ "certificate": cert, "reason": reason }), - None => serde_json::json!({ "certificate": cert }), - }; + let revocation = account.revoke_certificate(certificate, reason)?; let mut retry = retry(); loop { @@ -566,7 +557,7 @@ impl Client { let directory = Self::get_directory(&mut self.inner, &mut self.directory, &self.directory_url)?; let nonce = Self::nonce(&mut self.inner, directory)?; - let request = account.post_request(&directory.data.revoke_cert, nonce, &data)?; + let request = revocation.request(&directory, nonce)?; match self.inner.run_request(request) { Ok(_response) => return Ok(()), Err(err) if err.is_bad_nonce() => continue,