mirror of
https://github.com/zerotier/coyote.git
synced 2026-05-22 16:26:53 -07:00
Add some documentation
Signed-off-by: Erik Hollensbe <git@hollensbe.org>
This commit is contained in:
@@ -26,6 +26,9 @@ pub(crate) fn st_to_asn1(time: SystemTime) -> Result<Asn1Time, ErrorStack> {
|
||||
)
|
||||
}
|
||||
|
||||
/// CA defines a certificate authority in the standard sense of the word; it is used to sign
|
||||
/// certificate signing requests and return them as fully functional certificates. To create one,
|
||||
/// use the ::new constructor.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CA {
|
||||
certificate: X509,
|
||||
@@ -33,6 +36,7 @@ pub struct CA {
|
||||
}
|
||||
|
||||
impl CA {
|
||||
/// new constructs a new certificate authority with a X.509 certificate and private key.
|
||||
pub fn new(certificate: X509, private_key: PKey<Private>) -> Self {
|
||||
Self {
|
||||
certificate,
|
||||
@@ -40,14 +44,18 @@ impl CA {
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the certificate
|
||||
pub fn certificate(self) -> X509 {
|
||||
self.certificate
|
||||
}
|
||||
|
||||
/// returns the private key
|
||||
pub fn private_key(self) -> PKey<Private> {
|
||||
self.private_key
|
||||
}
|
||||
|
||||
/// signs a CSR with the CA's private key. The not_before and not_after parameters can be used
|
||||
/// to control its lifetime.
|
||||
pub fn generate_and_sign_cert(
|
||||
&self,
|
||||
req: X509Req,
|
||||
@@ -115,6 +123,8 @@ impl CA {
|
||||
Ok(builder.build())
|
||||
}
|
||||
|
||||
/// new_test_ca is a convenience function for creating a quick and dirty CA for use in tests
|
||||
/// and demo applications (such as the examples).
|
||||
pub fn new_test_ca() -> Result<Self, ErrorStack> {
|
||||
let mut builder = X509::builder()?;
|
||||
|
||||
@@ -186,15 +196,21 @@ impl CA {
|
||||
}
|
||||
}
|
||||
|
||||
/// CACollector is an async observer which waits for a CA to arrive, and fosters the creation of
|
||||
/// signed CSRs as certificates. This allows for the rotation of CA certificates, or delayed
|
||||
/// loading, without loss of functionality due to race conditions. Please see the `acmed` example for usage.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CACollector {
|
||||
poll_interval: Duration,
|
||||
ca: SharedCA,
|
||||
}
|
||||
|
||||
/// SharedCA is a simple type for managing the locking around a CA.
|
||||
type SharedCA = Arc<RwLock<Option<CA>>>;
|
||||
|
||||
impl CACollector {
|
||||
/// new is a constructor; the duration provided determines how often the loop will awake and
|
||||
/// process a CA injection.
|
||||
pub fn new(poll_interval: Duration) -> Self {
|
||||
Self {
|
||||
poll_interval,
|
||||
@@ -202,10 +218,13 @@ impl CACollector {
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the CA as a SharedCA.
|
||||
pub fn ca(self) -> SharedCA {
|
||||
self.ca.clone()
|
||||
}
|
||||
|
||||
/// majority of callers will use this function to collect the CA. It takes a closure which
|
||||
/// accepts a CA and returns it to this function so that it can overwrite the previous CA.
|
||||
pub async fn spawn_collector<F>(&mut self, f: F)
|
||||
where
|
||||
F: Fn() -> Result<CA, ErrorStack>,
|
||||
@@ -221,6 +240,8 @@ impl CACollector {
|
||||
}
|
||||
}
|
||||
|
||||
/// similar to CA::generate_and_sign_cert, this signs the CSR through the SharedCA provided by
|
||||
/// the collector.
|
||||
pub async fn sign(
|
||||
self,
|
||||
req: X509Req,
|
||||
|
||||
+15
-2
@@ -14,9 +14,13 @@ use super::handlers::order::OrderStatus;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(into = "String")]
|
||||
/// ChallengeType is an enum describing the challenge types coyote supports. Currently tls-alpn is
|
||||
/// unsupported.
|
||||
pub enum ChallengeType {
|
||||
DNS01, // dns-01 challenge type
|
||||
HTTP01, // http-01 challenge type
|
||||
/// dns-01 challenge type
|
||||
DNS01,
|
||||
/// http-01 challenge type
|
||||
HTTP01,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for ChallengeType {
|
||||
@@ -47,12 +51,16 @@ impl ChallengeType {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Challenger is an async supervisor used to perform challenges on demand. This is a simple
|
||||
/// monitored queue with expiration applied at every loop iteration.
|
||||
pub struct Challenger {
|
||||
list: Arc<Mutex<HashMap<String, Challenge>>>,
|
||||
expiration: Option<chrono::Duration>,
|
||||
}
|
||||
|
||||
impl Challenger {
|
||||
/// Construct a new challenger; challenges will last as long as `expiriation` is set to, or
|
||||
/// forever if Option::None.
|
||||
pub fn new(expiration: Option<chrono::Duration>) -> Self {
|
||||
Self {
|
||||
list: Arc::new(Mutex::new(HashMap::new())),
|
||||
@@ -64,6 +72,9 @@ impl Challenger {
|
||||
self.list.lock().await.insert(c.reference.clone(), c);
|
||||
}
|
||||
|
||||
/// tick should be called in a loop in its own async routine with an interval between
|
||||
/// iterations. This performs each challenge in the queue and invalidates any expired
|
||||
/// challenges. To commit to storage, call reconcile.
|
||||
pub async fn tick<T>(&self, ticker: T)
|
||||
where
|
||||
T: Fn(Challenge) -> Option<()>,
|
||||
@@ -118,6 +129,8 @@ impl Challenger {
|
||||
}
|
||||
}
|
||||
|
||||
/// reconcile should be called after tick. This actually commits the challenge results to the
|
||||
/// backing storage.
|
||||
pub async fn reconcile(&self, db: Postgres) -> Result<(), SaveError> {
|
||||
let mut lock = self.list.lock().await;
|
||||
let mut db_lock = db.client().await?;
|
||||
|
||||
@@ -3,6 +3,8 @@ use std::str::FromStr;
|
||||
use trust_dns_client::rr::Name;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
/// DNSName is used to provide a serde interface to DNS names. It is not frequently consumed by
|
||||
/// external consumers.
|
||||
pub struct DNSName(pub(crate) Name);
|
||||
|
||||
impl DNSName {
|
||||
@@ -15,6 +17,7 @@ impl DNSName {
|
||||
}
|
||||
}
|
||||
|
||||
/// serde codec implementation
|
||||
pub struct DNSNameVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for DNSNameVisitor {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
/// Certificate Authority functionality
|
||||
pub mod ca;
|
||||
/// Challenge management, including supervisory handlers.
|
||||
pub mod challenge;
|
||||
/// Types for managing DNS records
|
||||
pub mod dns;
|
||||
/// ACME HTTP handlers
|
||||
pub mod handlers;
|
||||
/// ACME JOSE implementation
|
||||
pub mod jose;
|
||||
|
||||
use std::{collections::HashSet, convert::TryFrom, sync::Arc};
|
||||
@@ -90,6 +95,9 @@ impl ACMEIdentifier {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
/// NonceValidator is a storage trait that controls the generation and validation of nonces, used
|
||||
/// heavily in ACME and especially in the `Replay-Nonce` HTTP header present in all calls, and the
|
||||
/// `nonce` field in ACME protected headers.
|
||||
pub trait NonceValidator {
|
||||
/// This function must mutate the underlying storage to prune the nonce it's validating after a
|
||||
/// successful fetch. One may use ACMEValidationError::NonceFetchError to specify errors with
|
||||
@@ -134,6 +142,7 @@ impl NonceValidator for SetValidator {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Defines a PostgreSQL-backed nonce validator
|
||||
pub struct PostgresNonceValidator(crate::models::Postgres);
|
||||
|
||||
impl PostgresNonceValidator {
|
||||
|
||||
+20
-1
@@ -1,6 +1,25 @@
|
||||
#![allow(dead_code)]
|
||||
//! Coyote lets you make ACME servers, which are not guaranteed to not explode in
|
||||
//! your face. You have to code that out yourself.
|
||||
//!
|
||||
//! coyote aims to solve a few problems (not all of these are solved yet; see "Task List" below):
|
||||
//!
|
||||
//! - Provide ACME with backing storage you prefer to use, by way of Rust's traits for storage implementation.
|
||||
//! - Provide ACME in non-conforming scenarios (e.g., behind corporate firewalls)
|
||||
//! - Provide ACME services with hooks into the validation system, so you can implement validations however you feel like.
|
||||
//! - It's a library; make it as big or as small as you like. No need for multiple implementations.
|
||||
//! - A FOSS alternative to the letsencrypt canonical implementation that is _also_ tested against LE's test suite.
|
||||
//!
|
||||
//! `acmed` comes as an example with coyote; it is a complete canonical implementation against PostgreSQL for backing storage. It (deliberately) allows all challenges through and is not meant for production usage.
|
||||
//!
|
||||
//! `coyote` is intended to let you build an ACME service without using `acmed` itself, leveraging the traits and tools available in this library for scaffolding. For example, work to implement a Redis based nonce validation system would just be a trait implementation, even though it is not available in this library.
|
||||
//!
|
||||
|
||||
/// Core ACME implementation, including HTTP handlers, JOSE implementation and plenty of crypto
|
||||
pub mod acme;
|
||||
/// Errors and conversions between different Error types
|
||||
pub mod errors;
|
||||
/// Database types and traits
|
||||
pub mod models;
|
||||
pub mod test;
|
||||
pub(crate) mod test;
|
||||
pub(crate) mod util;
|
||||
|
||||
Reference in New Issue
Block a user