rustls_acme/
state.rs

1use crate::acceptor::AcmeAcceptor;
2use crate::acme::{Account, AcmeError, Auth, AuthStatus, Directory, Identifier, Order, OrderStatus, ACME_TLS_ALPN_NAME};
3use crate::{any_ecdsa_type, crypto_provider, AcmeConfig, Incoming, ResolvesServerCertAcme, UseChallenge};
4use async_io::Timer;
5use chrono::{DateTime, TimeZone, Utc};
6use core::fmt;
7use futures::prelude::*;
8use futures::ready;
9use futures_rustls::pki_types::{CertificateDer as RustlsCertificate, PrivateKeyDer, PrivatePkcs8KeyDer};
10use futures_rustls::rustls::crypto::CryptoProvider;
11use futures_rustls::rustls::sign::CertifiedKey;
12use futures_rustls::rustls::ServerConfig;
13use rcgen::{CertificateParams, DistinguishedName, KeyPair, PKCS_ECDSA_P256_SHA256};
14use std::convert::Infallible;
15use std::fmt::Debug;
16use std::future::Future;
17use std::pin::Pin;
18use std::sync::Arc;
19use std::task::{Context, Poll};
20use std::time::Duration;
21use thiserror::Error;
22use x509_parser::parse_x509_certificate;
23
24#[cfg(doc)]
25use crate::is_tls_alpn_challenge;
26#[cfg(doc)]
27use crate::rustls;
28
29#[allow(clippy::type_complexity)]
30pub struct AcmeState<EC: Debug = Infallible, EA: Debug = EC> {
31    config: Arc<AcmeConfig<EC, EA>>,
32    resolver: Arc<ResolvesServerCertAcme>,
33    account_key: Option<Vec<u8>>,
34
35    early_action: Option<Pin<Box<dyn Future<Output = Event<EC, EA>> + Send>>>,
36    load_cert: Option<Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, EC>> + Send>>>,
37    load_account: Option<Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, EA>> + Send>>>,
38    order: Option<Pin<Box<dyn Future<Output = Result<Vec<u8>, OrderError>> + Send>>>,
39    backoff_cnt: usize,
40    wait: Option<Timer>,
41}
42
43impl<EC: 'static + Debug, EA: 'static + Debug> fmt::Debug for AcmeState<EC, EA> {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        f.debug_struct("AcmeState").field("config", &self.config).finish_non_exhaustive()
46    }
47}
48
49pub type Event<EC, EA> = Result<EventOk, EventError<EC, EA>>;
50
51#[derive(Debug)]
52pub enum EventOk {
53    DeployedCachedCert,
54    DeployedNewCert,
55    CertCacheStore,
56    AccountCacheStore,
57}
58
59#[derive(Error, Debug)]
60pub enum EventError<EC: Debug, EA: Debug> {
61    #[error("cert cache load: {0}")]
62    CertCacheLoad(EC),
63    #[error("account cache load: {0}")]
64    AccountCacheLoad(EA),
65    #[error("cert cache store: {0}")]
66    CertCacheStore(EC),
67    #[error("account cache store: {0}")]
68    AccountCacheStore(EA),
69    #[error("cached cert parse: {0}")]
70    CachedCertParse(CertParseError),
71    #[error("order: {0}")]
72    Order(OrderError),
73    #[error("new cert parse: {0}")]
74    NewCertParse(CertParseError),
75}
76
77#[derive(Error, Debug)]
78pub enum OrderError {
79    #[error("acme error: {0}")]
80    Acme(#[from] AcmeError),
81    #[error("certificate generation error: {0}")]
82    Rcgen(#[from] rcgen::Error),
83    #[error("bad order object: {0:?}")]
84    BadOrder(Order),
85    #[error("bad auth object: {0:?}")]
86    BadAuth(Auth),
87    #[error("authorization for {0} failed too many times")]
88    TooManyAttemptsAuth(String),
89    #[error("order status stayed on processing too long")]
90    ProcessingTimeout(Order),
91}
92
93#[derive(Error, Debug)]
94pub enum CertParseError {
95    #[error("X509 parsing error: {0}")]
96    X509(#[from] x509_parser::nom::Err<x509_parser::error::X509Error>),
97    #[error("expected 2 or more pem, got: {0}")]
98    Pem(#[from] pem::PemError),
99    #[error("expected 2 or more pem, got: {0}")]
100    TooFewPem(usize),
101    #[error("unsupported private key type")]
102    InvalidPrivateKey,
103}
104
105impl<EC: 'static + Debug, EA: 'static + Debug> AcmeState<EC, EA> {
106    pub fn incoming<TCP: AsyncRead + AsyncWrite + Unpin, ETCP, ITCP: Stream<Item = Result<TCP, ETCP>> + Unpin>(
107        self,
108        tcp_incoming: ITCP,
109        alpn_protocols: Vec<Vec<u8>>,
110    ) -> Incoming<TCP, ETCP, ITCP, EC, EA> {
111        #[allow(deprecated)]
112        let acceptor = self.acceptor();
113        Incoming::new(tcp_incoming, self, acceptor, alpn_protocols)
114    }
115    #[deprecated(note = "please use high-level API via `AcmeState::incoming()` instead or refer to updated low-level API examples")]
116    #[allow(deprecated)]
117    pub fn acceptor(&self) -> AcmeAcceptor {
118        AcmeAcceptor::new(self.resolver())
119    }
120    #[cfg(feature = "tokio")]
121    pub fn tokio_incoming<
122        TokioTCP: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin,
123        ETCP,
124        TokioITCP: Stream<Item = Result<TokioTCP, ETCP>> + Unpin,
125    >(
126        self,
127        tcp_incoming: TokioITCP,
128        alpn_protocols: Vec<Vec<u8>>,
129    ) -> crate::tokio::TokioIncoming<
130        tokio_util::compat::Compat<TokioTCP>,
131        ETCP,
132        crate::tokio::TokioIncomingTcpWrapper<TokioTCP, ETCP, TokioITCP>,
133        EC,
134        EA,
135    > {
136        let tcp_incoming = crate::tokio::TokioIncomingTcpWrapper::from(tcp_incoming);
137        crate::tokio::TokioIncoming::from(self.incoming(tcp_incoming, alpn_protocols))
138    }
139    #[cfg(feature = "axum")]
140    pub fn axum_acceptor(&self, rustls_config: Arc<ServerConfig>) -> crate::axum::AxumAcceptor {
141        #[allow(deprecated)]
142        crate::axum::AxumAcceptor::new(self.acceptor(), rustls_config)
143    }
144
145    #[cfg(feature = "tower")]
146    pub fn http01_challenge_tower_service(&self) -> crate::tower::TowerHttp01ChallengeService {
147        crate::tower::TowerHttp01ChallengeService(self.resolver.clone())
148    }
149
150    pub fn resolver(&self) -> Arc<ResolvesServerCertAcme> {
151        self.resolver.clone()
152    }
153
154    /// Creates a [rustls::ServerConfig] for TLS-ALPN-01 challenge connections. Use this if [is_tls_alpn_challenge] returns `true`.
155    #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
156    pub fn challenge_rustls_config(&self) -> Arc<ServerConfig> {
157        self.challenge_rustls_config_with_provider(crypto_provider().into())
158    }
159    /// Same as [AcmeState::challenge_rustls_config], with a specific [CryptoProvider].
160    pub fn challenge_rustls_config_with_provider(&self, provider: Arc<CryptoProvider>) -> Arc<ServerConfig> {
161        let mut rustls_config = ServerConfig::builder_with_provider(provider)
162            .with_safe_default_protocol_versions()
163            .unwrap()
164            .with_no_client_auth()
165            .with_cert_resolver(self.resolver());
166        rustls_config.alpn_protocols.push(ACME_TLS_ALPN_NAME.to_vec());
167        Arc::new(rustls_config)
168    }
169    /// Creates a default [rustls::ServerConfig] for accepting regular tls connections. Use this if [is_tls_alpn_challenge] returns `false`.
170    /// If you need a [rustls::ServerConfig], which uses the certificates acquired by this [AcmeState],
171    /// you may build your own using the output of [AcmeState::resolver].
172    #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
173    pub fn default_rustls_config(&self) -> Arc<ServerConfig> {
174        self.default_rustls_config_with_provider(crypto_provider().into())
175    }
176    /// Same as [AcmeState::default_rustls_config], with a specific [CryptoProvider].
177    pub fn default_rustls_config_with_provider(&self, provider: Arc<CryptoProvider>) -> Arc<ServerConfig> {
178        let rustls_config = ServerConfig::builder_with_provider(provider)
179            .with_safe_default_protocol_versions()
180            .unwrap()
181            .with_no_client_auth()
182            .with_cert_resolver(self.resolver());
183        Arc::new(rustls_config)
184    }
185    pub fn new(config: AcmeConfig<EC, EA>) -> Self {
186        let config = Arc::new(config);
187        Self {
188            config: config.clone(),
189            resolver: ResolvesServerCertAcme::new(),
190            account_key: None,
191            early_action: None,
192            load_cert: Some(Box::pin({
193                let config = config.clone();
194                async move { config.cache.load_cert(&config.domains, &config.directory_url).await }
195            })),
196            load_account: Some(Box::pin({
197                let config = config.clone();
198                async move { config.cache.load_account(&config.contact, &config.directory_url).await }
199            })),
200            order: None,
201            backoff_cnt: 0,
202            wait: None,
203        }
204    }
205    fn parse_cert(pem: &[u8]) -> Result<(CertifiedKey, [DateTime<Utc>; 2]), CertParseError> {
206        let mut pems = pem::parse_many(pem)?;
207        if pems.len() < 2 {
208            return Err(CertParseError::TooFewPem(pems.len()));
209        }
210        let pk = match any_ecdsa_type(&PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(pems.remove(0).contents()))) {
211            Ok(pk) => pk,
212            Err(_) => return Err(CertParseError::InvalidPrivateKey),
213        };
214        let cert_chain: Vec<RustlsCertificate> = pems.into_iter().map(|p| RustlsCertificate::from(p.into_contents())).collect();
215        let validity = match parse_x509_certificate(&cert_chain[0]) {
216            Ok((_, cert)) => {
217                let validity = cert.validity();
218                [validity.not_before, validity.not_after].map(|t| Utc.timestamp_opt(t.timestamp(), 0).earliest().unwrap())
219            }
220            Err(err) => return Err(CertParseError::X509(err)),
221        };
222        let cert = CertifiedKey::new(cert_chain, pk);
223        Ok((cert, validity))
224    }
225
226    #[allow(clippy::result_large_err)]
227    fn process_cert(&mut self, pem: Vec<u8>, cached: bool) -> Event<EC, EA> {
228        let (cert, validity) = match (Self::parse_cert(&pem), cached) {
229            (Ok(r), _) => r,
230            (Err(err), cached) => {
231                return match cached {
232                    true => Err(EventError::CachedCertParse(err)),
233                    false => Err(EventError::NewCertParse(err)),
234                }
235            }
236        };
237        self.resolver.set_cert(Arc::new(cert));
238        let wait_duration = (validity[1] - (validity[1] - validity[0]) / 3 - Utc::now())
239            .max(chrono::Duration::zero())
240            .to_std()
241            .unwrap_or_default();
242        self.wait = Some(Timer::after(wait_duration));
243        if cached {
244            return Ok(EventOk::DeployedCachedCert);
245        }
246        let config = self.config.clone();
247        self.early_action = Some(Box::pin(async move {
248            match config.cache.store_cert(&config.domains, &config.directory_url, &pem).await {
249                Ok(()) => Ok(EventOk::CertCacheStore),
250                Err(err) => Err(EventError::CertCacheStore(err)),
251            }
252        }));
253        Event::Ok(EventOk::DeployedNewCert)
254    }
255    async fn order(config: Arc<AcmeConfig<EC, EA>>, resolver: Arc<ResolvesServerCertAcme>, key_pair: Vec<u8>) -> Result<Vec<u8>, OrderError> {
256        let directory = Directory::discover(&config.client_config, &config.directory_url).await?;
257        let account = Account::create_with_keypair(&config.client_config, directory, &config.contact, &key_pair).await?;
258
259        let mut params = CertificateParams::new(config.domains.clone())?;
260        params.distinguished_name = DistinguishedName::new();
261        let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?;
262        let csr = params.serialize_request(&key_pair)?;
263
264        let (order_url, mut order) = account.new_order(&config.client_config, config.domains.clone()).await?;
265        loop {
266            match order.status {
267                OrderStatus::Pending => {
268                    // Force in order authorizations to allow single global challenge data state
269                    for url in order.authorizations.iter() {
270                        Self::authorize(&config, &resolver, &account, url).await?
271                    }
272                    log::info!("completed all authorizations");
273                    order = account.order(&config.client_config, &order_url).await?;
274                }
275                OrderStatus::Processing => {
276                    for i in 0u64..10 {
277                        log::info!("order processing");
278                        Timer::after(Duration::from_secs(1u64 << i)).await;
279                        order = account.order(&config.client_config, &order_url).await?;
280                        if order.status != OrderStatus::Processing {
281                            break;
282                        }
283                    }
284                    if order.status == OrderStatus::Processing {
285                        return Err(OrderError::ProcessingTimeout(order));
286                    }
287                }
288                OrderStatus::Ready => {
289                    log::info!("sending csr");
290                    order = account.finalize(&config.client_config, order.finalize, csr.der()).await?
291                }
292                OrderStatus::Valid { certificate } => {
293                    log::info!("download certificate");
294                    let pem = [
295                        &key_pair.serialize_pem(),
296                        "\n",
297                        &account.certificate(&config.client_config, certificate).await?,
298                    ]
299                    .concat();
300                    return Ok(pem.into_bytes());
301                }
302                OrderStatus::Invalid => return Err(OrderError::BadOrder(order)),
303            }
304        }
305    }
306    async fn authorize(config: &AcmeConfig<EC, EA>, resolver: &ResolvesServerCertAcme, account: &Account, url: &String) -> Result<(), OrderError> {
307        let auth = account.auth(&config.client_config, url).await?;
308        let (domain, challenge_url) = match auth.status {
309            AuthStatus::Pending => {
310                let Identifier::Dns(domain) = auth.identifier;
311                log::info!("trigger challenge for {}", &domain);
312                let challenge = match config.challenge_type {
313                    UseChallenge::Http01 => {
314                        let (challenge, key_auth) = account.http_01(&auth.challenges)?;
315                        resolver.set_http_01_challenge_data(challenge.token.clone(), key_auth);
316                        challenge
317                    }
318                    UseChallenge::TlsAlpn01 => {
319                        let (challenge, auth_key) = account.tls_alpn_01(&auth.challenges, domain.clone())?;
320                        resolver.set_tls_alpn_01_challenge_data(domain.clone(), Arc::new(auth_key));
321                        challenge
322                    }
323                };
324                account.challenge(&config.client_config, &challenge.url).await?;
325                (domain, challenge.url.clone())
326            }
327            AuthStatus::Valid => {
328                // clear challenge data when auth validated
329                resolver.clear_challenge_data();
330                return Ok(());
331            }
332            _ => {
333                // clear challenge data when auth invalidated
334                resolver.clear_challenge_data();
335                return Err(OrderError::BadAuth(auth));
336            }
337        };
338        for i in 0u64..5 {
339            Timer::after(Duration::from_secs(1u64 << i)).await;
340            let auth = account.auth(&config.client_config, url).await?;
341            match auth.status {
342                AuthStatus::Pending => {
343                    log::info!("authorization for {} still pending", &domain);
344                    account.challenge(&config.client_config, &challenge_url).await?
345                }
346                AuthStatus::Valid => {
347                    // clear challenge data when auth validated
348                    resolver.clear_challenge_data();
349                    return Ok(());
350                }
351                _ => {
352                    // clear challenge data when auth invalidated
353                    resolver.clear_challenge_data();
354                    return Err(OrderError::BadAuth(auth));
355                }
356            }
357        }
358        Err(OrderError::TooManyAttemptsAuth(domain))
359    }
360    fn poll_next_infinite(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Event<EC, EA>> {
361        loop {
362            // queued early action
363            if let Some(early_action) = &mut self.early_action {
364                let result = ready!(early_action.poll_unpin(cx));
365                self.early_action.take();
366                return Poll::Ready(result);
367            }
368
369            // sleep
370            if let Some(timer) = &mut self.wait {
371                ready!(timer.poll_unpin(cx));
372                self.wait.take();
373            }
374
375            // load from cert cache
376            if let Some(load_cert) = &mut self.load_cert {
377                let result = ready!(load_cert.poll_unpin(cx));
378                self.load_cert.take();
379                match result {
380                    Ok(Some(pem)) => {
381                        return Poll::Ready(Self::process_cert(self.get_mut(), pem, true));
382                    }
383                    Ok(None) => {}
384                    Err(err) => return Poll::Ready(Err(EventError::CertCacheLoad(err))),
385                }
386            }
387
388            // load from account cache
389            if let Some(load_account) = &mut self.load_account {
390                let result = ready!(load_account.poll_unpin(cx));
391                self.load_account.take();
392                match result {
393                    Ok(Some(key_pair)) => self.account_key = Some(key_pair),
394                    Ok(None) => {}
395                    Err(err) => return Poll::Ready(Err(EventError::AccountCacheLoad(err))),
396                }
397            }
398
399            // execute order
400            if let Some(order) = &mut self.order {
401                let result = ready!(order.poll_unpin(cx));
402                self.order.take();
403                match result {
404                    Ok(pem) => {
405                        self.backoff_cnt = 0;
406                        return Poll::Ready(Self::process_cert(self.get_mut(), pem, false));
407                    }
408                    Err(err) => {
409                        // TODO: replace key on some errors or high backoff_cnt?
410                        self.wait = Some(Timer::after(Duration::from_secs(1 << self.backoff_cnt)));
411                        self.backoff_cnt = (self.backoff_cnt + 1).min(16);
412                        return Poll::Ready(Err(EventError::Order(err)));
413                    }
414                }
415            }
416
417            // schedule order
418            let account_key = match &self.account_key {
419                None => {
420                    let account_key = Account::generate_key_pair();
421                    self.account_key = Some(account_key.clone());
422                    let config = self.config.clone();
423                    let account_key_clone = account_key.clone();
424                    self.early_action = Some(Box::pin(async move {
425                        match config
426                            .cache
427                            .store_account(&config.contact, &config.directory_url, &account_key_clone)
428                            .await
429                        {
430                            Ok(()) => Ok(EventOk::AccountCacheStore),
431                            Err(err) => Err(EventError::AccountCacheStore(err)),
432                        }
433                    }));
434                    account_key
435                }
436                Some(account_key) => account_key.clone(),
437            };
438            let config = self.config.clone();
439            let resolver = self.resolver.clone();
440            self.order = Some(Box::pin(Self::order(config.clone(), resolver.clone(), account_key)));
441        }
442    }
443}
444
445impl<EC: 'static + Debug, EA: 'static + Debug> Stream for AcmeState<EC, EA> {
446    type Item = Event<EC, EA>;
447
448    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
449        Poll::Ready(Some(ready!(self.poll_next_infinite(cx))))
450    }
451}