Add certificate revocation (#38)
This commit is contained in:
parent
a800b1bff7
commit
8290a95649
|
@ -19,6 +19,7 @@ base64 = "0.21.0"
|
|||
hyper = { version = "0.14.18", features = ["client", "http1", "http2"] }
|
||||
hyper-rustls = { version = "0.24", default-features = false, features = ["http1", "http2", "native-tokio", "tls12"], optional = true }
|
||||
ring = { version = "0.17", features = ["std"] }
|
||||
rustls-pki-types = "1.1.0"
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
serde_json = "1.0.78"
|
||||
thiserror = "1.0.30"
|
||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -24,7 +24,8 @@ use serde::Serialize;
|
|||
mod types;
|
||||
pub use types::{
|
||||
AccountCredentials, Authorization, AuthorizationStatus, Challenge, ChallengeType, Error,
|
||||
Identifier, LetsEncrypt, NewAccount, NewOrder, OrderState, OrderStatus, Problem, ZeroSsl,
|
||||
Identifier, LetsEncrypt, NewAccount, NewOrder, OrderState, OrderStatus, Problem,
|
||||
RevocationReason, RevocationRequest, ZeroSsl,
|
||||
};
|
||||
use types::{
|
||||
DirectoryUrls, Empty, FinalizeRequest, Header, JoseJson, Jwk, KeyOrKeyId, NewAccountPayload,
|
||||
|
@ -362,6 +363,17 @@ impl Account {
|
|||
url: order_url.ok_or("no order URL found")?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Revokes a previously issued certificate
|
||||
pub async fn revoke<'a>(&'a self, payload: &RevocationRequest<'a>) -> Result<(), Error> {
|
||||
let rsp = self
|
||||
.inner
|
||||
.post(Some(payload), None, &self.inner.client.urls.revoke_cert)
|
||||
.await?;
|
||||
// The body is empty if the request was successful
|
||||
let _ = Problem::from_response(rsp).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct AccountInner {
|
||||
|
@ -697,7 +709,7 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn deserialize_old_credentials() -> Result<(), Error> {
|
||||
const CREDENTIALS: &str = r#"{"id":"id","key_pkcs8":"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgJVWC_QzOTCS5vtsJp2IG-UDc8cdDfeoKtxSZxaznM-mhRANCAAQenCPoGgPFTdPJ7VLLKt56RxPlYT1wNXnHc54PEyBg3LxKaH0-sJkX0mL8LyPEdsfL_Oz4TxHkWLJGrXVtNhfH","urls":{"newNonce":"new-nonce","newAccount":"new-acct","newOrder":"new-order"}}"#;
|
||||
const CREDENTIALS: &str = r#"{"id":"id","key_pkcs8":"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgJVWC_QzOTCS5vtsJp2IG-UDc8cdDfeoKtxSZxaznM-mhRANCAAQenCPoGgPFTdPJ7VLLKt56RxPlYT1wNXnHc54PEyBg3LxKaH0-sJkX0mL8LyPEdsfL_Oz4TxHkWLJGrXVtNhfH","urls":{"newNonce":"new-nonce","newAccount":"new-acct","newOrder":"new-order", "revokeCert": "revoke-cert"}}"#;
|
||||
Account::from_credentials(serde_json::from_str::<AccountCredentials>(CREDENTIALS)?).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
49
src/types.rs
49
src/types.rs
|
@ -4,7 +4,9 @@ use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
|
|||
use hyper::{Body, Response};
|
||||
use ring::digest::{digest, Digest, SHA256};
|
||||
use ring::signature::{EcdsaKeyPair, KeyPair};
|
||||
use rustls_pki_types::CertificateDer;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::ser::SerializeMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -271,6 +273,52 @@ pub struct NewOrder<'a> {
|
|||
pub identifiers: &'a [Identifier],
|
||||
}
|
||||
|
||||
/// Payload for a certificate revocation request
|
||||
/// Defined in <https://datatracker.ietf.org/doc/html/rfc8555#section-7.6>
|
||||
#[derive(Debug)]
|
||||
pub struct RevocationRequest<'a> {
|
||||
/// The certificate to revoke
|
||||
pub certificate: &'a CertificateDer<'a>,
|
||||
/// Reason for revocation
|
||||
pub reason: Option<RevocationReason>,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for RevocationRequest<'a> {
|
||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let base64 = BASE64_URL_SAFE_NO_PAD.encode(self.certificate);
|
||||
let mut map = serializer.serialize_map(Some(2))?;
|
||||
map.serialize_entry("certificate", &base64)?;
|
||||
if let Some(reason) = &self.reason {
|
||||
map.serialize_entry("reason", reason)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// The reason for a certificate revocation
|
||||
/// Defined in <https://datatracker.ietf.org/doc/html/rfc5280#section-5.3.1>
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum RevocationReason {
|
||||
Unspecified = 0,
|
||||
KeyCompromise = 1,
|
||||
CaCompromise = 2,
|
||||
AffiliationChanged = 3,
|
||||
Superseded = 4,
|
||||
CessationOfOperation = 5,
|
||||
CertificateHold = 6,
|
||||
RemoveFromCrl = 8,
|
||||
PrivilegeWithdrawn = 9,
|
||||
AaCompromise = 10,
|
||||
}
|
||||
|
||||
impl Serialize for RevocationReason {
|
||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_u8(self.clone() as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct NewAccountPayload<'a> {
|
||||
|
@ -302,6 +350,7 @@ pub(crate) struct DirectoryUrls {
|
|||
pub(crate) new_nonce: String,
|
||||
pub(crate) new_account: String,
|
||||
pub(crate) new_order: String,
|
||||
pub(crate) revoke_cert: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
Loading…
Reference in New Issue