make revocation workflow accessible without client

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2021-04-14 14:56:40 +02:00
parent b624fa1f3c
commit 558f51a167
2 changed files with 45 additions and 11 deletions

View File

@ -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<u32>,
) -> Result<CertificateRevocation, Error> {
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<Request, Error> {
self.account.post_request(&directory.data.revoke_cert, nonce, &self.data)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]

View File

@ -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,