acme2_eab/
order.rs

1use crate::account::Account;
2use crate::error::*;
3use crate::helpers::*;
4use openssl::hash::MessageDigest;
5use openssl::pkey::PKey;
6use openssl::pkey::Private;
7use openssl::stack::Stack;
8use openssl::x509::extension::SubjectAlternativeName;
9use openssl::x509::X509Name;
10use openssl::x509::X509Req;
11use openssl::x509::X509;
12use serde::Deserialize;
13use serde_json::json;
14use std::sync::Arc;
15use std::time::Duration;
16use tracing::debug;
17use tracing::field;
18use tracing::instrument;
19use tracing::Level;
20use tracing::Span;
21
22/// The status of this order.
23///
24/// Possible values are "pending", "ready", processing", "valid", and "invalid".
25#[derive(Deserialize, Debug, Eq, PartialEq)]
26#[serde(rename_all = "camelCase")]
27pub enum OrderStatus {
28    Pending,
29    Ready,
30    Processing,
31    Valid,
32    Invalid,
33}
34
35/// An order represents a subscribers's request for a certificate from the
36/// ACME server, and is used to track the progress of that order through to
37/// issuance.
38///
39/// This must be created through an [`OrderBuilder`].
40#[derive(Deserialize, Debug)]
41#[serde(rename_all = "camelCase")]
42pub struct Order {
43    #[serde(skip)]
44    pub(crate) account: Option<Arc<Account>>,
45    #[serde(skip)]
46    pub(crate) url: String,
47
48    /// The status of this order.
49    pub status: OrderStatus,
50    /// The timestamp after which the server will consider this order
51    /// invalid.
52    pub expires: Option<String>,
53    /// An array of identifier objects that the order pertains to.
54    pub identifiers: Vec<Identifier>,
55    /// The requested value of the notBefore field in the certificate.
56    pub not_before: Option<String>,
57    /// The requested value of the notAfter field in the certificate.
58    pub not_after: Option<String>,
59
60    /// The error that occurred while processing the order, if any.
61    pub error: Option<ServerError>,
62
63    #[serde(rename = "authorizations")]
64    /// For pending orders, the authorizations that the client needs to
65    /// complete before the requested certificate can be issued. For
66    /// final orders (in the "valid" or "invalid" state), the
67    /// authorizations that were completed.
68    pub(crate) authorization_urls: Vec<String>,
69    #[serde(rename = "finalize")]
70    /// A URL that a CSR must be POSTed to once all of the order's
71    /// authorizations are satisfied to finalize the order.
72    pub(crate) finalize_url: String,
73    #[serde(rename = "certificate")]
74    /// A URL for the certificate that has been issued in response to
75    /// this order.
76    pub(crate) certificate_url: Option<String>,
77}
78
79/// A builder used to create a new [`Order`].
80#[derive(Debug)]
81pub struct OrderBuilder {
82    account: Arc<Account>,
83
84    identifiers: Vec<Identifier>,
85    // TODO(lucacasonato): externalAccountBinding
86}
87
88impl OrderBuilder {
89    pub fn new(account: Arc<Account>) -> Self {
90        OrderBuilder {
91            account,
92            identifiers: vec![],
93        }
94    }
95
96    /// Set the identifiers for an order.
97    ///
98    /// In most cases, you can use [`OrderBuilder::add_dns_identifier`]
99    pub fn set_identifiers(&mut self, identifiers: Vec<Identifier>) -> &mut Self {
100        self.identifiers = identifiers;
101        self
102    }
103
104    /// Add a type `dns` identifier to the list of identifiers for this
105    /// order.
106    pub fn add_dns_identifier(&mut self, fqdn: String) -> &mut Self {
107        self.identifiers.push(Identifier {
108            r#type: "dns".to_string(),
109            value: fqdn,
110        });
111        self
112    }
113
114    /// This will request a new [`Order`] from the ACME server.
115    #[instrument(level = Level::INFO, name = "acme2::OrderBuilder::build", err, skip(self), fields(identifiers = ?self.identifiers, order_url = field::Empty))]
116    pub async fn build(&mut self) -> Result<Order, Error> {
117        let dir = self.account.directory.clone().unwrap();
118
119        let (res, headers) = dir
120            .authenticated_request::<_, Order>(
121                &dir.new_order_url,
122                json!({
123                  "identifiers": self.identifiers,
124                }),
125                self.account.private_key.clone().unwrap(),
126                Some(self.account.id.clone()),
127            )
128            .await?;
129
130        let res: Result<Order, Error> = res.into();
131        let mut order = res?;
132
133        let order_url = map_transport_err(
134            headers
135                .get(reqwest::header::LOCATION)
136                .ok_or_else(|| {
137                    transport_err("mandatory location header in newOrder response not present")
138                })?
139                .to_str(),
140        )?
141        .to_string();
142        Span::current().record("order_url", &field::display(&order_url));
143
144        order.account = Some(self.account.clone());
145        order.url = order_url;
146
147        Ok(order)
148    }
149}
150
151/// A certificate signing request.
152pub enum Csr {
153    /// Automatic signing takes just a private key. The other details of
154    /// the CSR (identifiers, common name, etc), will be automatically
155    /// retrieved from the order this is used with.
156    Automatic(PKey<Private>),
157    /// A custom CSR will not be modified, and will be passed to the ACME
158    /// server as is.
159    Custom(X509Req),
160}
161
162fn gen_csr(pkey: &PKey<openssl::pkey::Private>, domains: Vec<String>) -> Result<X509Req, Error> {
163    if domains.is_empty() {
164        return Err(Error::Validation(
165            "at least one domain name needs to be supplied",
166        ));
167    }
168
169    let mut builder = X509Req::builder()?;
170    let name = {
171        let mut name = X509Name::builder()?;
172        name.append_entry_by_text("CN", &domains[0])?;
173        name.build()
174    };
175    builder.set_subject_name(&name)?;
176
177    // Add all domains as SANs
178    let san_extension = {
179        let mut san = SubjectAlternativeName::new();
180        for domain in domains.iter() {
181            san.dns(domain);
182        }
183        san.build(&builder.x509v3_context(None))?
184    };
185    let mut stack = Stack::new()?;
186    stack.push(san_extension)?;
187    builder.add_extensions(&stack)?;
188
189    builder.set_pubkey(pkey)?;
190    builder.sign(pkey, MessageDigest::sha256())?;
191
192    Ok(builder.build())
193}
194
195impl Order {
196    /// Finalize an order (request the final certificate).
197    ///
198    /// For finalization to complete, the state of the order must be in the
199    /// [`OrderStatus::Ready`] state. You can use [`Order::wait_ready`] to wait
200    /// until this is the case.
201    ///
202    /// In most cases this will not complete immediately. You should always
203    /// call [`Order::wait_done`] after this operation to wait until the
204    /// ACME server has finished finalization, and the certificate is ready
205    /// for download.
206    #[instrument(level = Level::INFO, name = "acme2::Order::finalize", err, skip(self, csr), fields(order_url = %self.url, status = field::Empty))]
207    pub async fn finalize(&self, csr: Csr) -> Result<Order, Error> {
208        let csr = match csr {
209            Csr::Automatic(pkey) => gen_csr(
210                &pkey,
211                self.identifiers
212                    .iter()
213                    .map(|f| f.value.clone())
214                    .collect::<Vec<_>>(),
215            )?,
216            Csr::Custom(csr) => csr,
217        };
218
219        let csr_b64 = b64(&csr.to_der()?);
220
221        let account = self.account.clone().unwrap();
222        let directory = account.directory.clone().unwrap();
223
224        let (res, _) = directory
225            .authenticated_request::<_, Order>(
226                &self.finalize_url,
227                json!({ "csr": csr_b64 }),
228                account.private_key.clone().unwrap(),
229                Some(account.id.clone()),
230            )
231            .await?;
232        let res: Result<Order, Error> = res.into();
233        let mut order = res?;
234        Span::current().record("status", &field::debug(&order.status));
235        order.account = Some(account.clone());
236        order.url = self.url.clone();
237        Ok(order)
238    }
239
240    /// Download the certificate. The order must be in the [`OrderStatus::Valid`]
241    /// state for this to complete.
242    #[instrument(level = Level::INFO, name = "acme2::Order::certificate", err, skip(self), fields(order_url = %self.url, has_certificate = field::Empty))]
243    pub async fn certificate(&self) -> Result<Option<Vec<X509>>, Error> {
244        Span::current().record("has_certificate", self.certificate_url.is_some());
245        let certificate_url = match self.certificate_url.clone() {
246            Some(certificate_url) => certificate_url,
247            None => return Ok(None),
248        };
249
250        let account = self.account.clone().unwrap();
251        let directory = account.directory.clone().unwrap();
252
253        let bytes = directory
254            .authenticated_request_bytes(
255                &certificate_url,
256                "",
257                &account.private_key.clone().unwrap(),
258                &Some(account.id.clone()),
259            )
260            .await?
261            .0?;
262
263        Ok(Some(X509::stack_from_pem(&bytes)?))
264    }
265
266    /// Update the order to match the current server state.
267    ///
268    /// Most users should use [`Order::wait_ready`] or [`Order::wait_done`].
269    #[instrument(level = Level::DEBUG, name = "acme2::Order::poll", err, skip(self), fields(order_url = %self.url, status = field::Empty))]
270    pub async fn poll(&self) -> Result<Order, Error> {
271        let account = self.account.clone().unwrap();
272        let directory = account.directory.clone().unwrap();
273
274        let (res, _) = directory
275            .authenticated_request::<_, Order>(
276                &self.url,
277                json!(""),
278                account.private_key.clone().unwrap(),
279                Some(account.id.clone()),
280            )
281            .await?;
282        let res: Result<Order, Error> = res.into();
283        let mut order = res?;
284        Span::current().record("status", &field::debug(&order.status));
285        order.account = Some(account.clone());
286        order.url = self.url.clone();
287        Ok(order)
288    }
289
290    /// Wait for this order to go into a state other than [`OrderStatus::Pending`].
291    ///
292    /// This happens when all [`crate::Authorization`]s in this order have been completed
293    /// (have the [`crate::AuthorizationStatus::Valid`] state).
294    ///
295    /// Will complete immediately if the order is already
296    /// in one of these states.
297    ///
298    /// Specify the interval at which to poll the acme server, and how often to
299    /// attempt polling before timing out. Polling should not happen faster than
300    /// about every 5 seconds to avoid rate limits in the acme server.
301    #[instrument(level = Level::INFO, name = "acme2::Order::wait_ready", err, skip(self), fields(order_url = %self.url))]
302    pub async fn wait_ready(
303        self,
304        poll_interval: Duration,
305        attempts: usize,
306    ) -> Result<Order, Error> {
307        let mut order = self;
308
309        let mut i: usize = 0;
310
311        while order.status == OrderStatus::Pending {
312            if i >= attempts {
313                return Err(Error::MaxAttemptsExceeded);
314            }
315            debug!(
316              { delay = ?poll_interval },
317              "Order still pending. Waiting to poll."
318            );
319            tokio::time::sleep(poll_interval).await;
320            order = order.poll().await?;
321            i += 1;
322        }
323
324        Ok(order)
325    }
326
327    /// Wait for the order to go into the [`OrderStatus::Valid`]
328    /// or [`OrderStatus::Invalid`] state.
329    ///
330    /// This will happen after the order has gone into the [`OrderStatus::Ready`]
331    /// state, and the order has been requested to be finalized.
332    ///
333    /// Will complete immediately if the order is already
334    /// in one of these states.
335    ///
336    /// Specify the interval at which to poll the acme server, and how often to
337    /// attempt polling before timing out. Polling should not happen faster than
338    /// about every 5 seconds to avoid rate limits in the acme server.
339    #[instrument(level = Level::INFO, name = "acme2::Order::wait_ready", err, skip(self), fields(order_url = %self.url))]
340    pub async fn wait_done(self, poll_interval: Duration, attempts: usize) -> Result<Order, Error> {
341        let mut order = self;
342
343        let mut i: usize = 0;
344
345        while order.status == OrderStatus::Pending
346            || order.status == OrderStatus::Ready
347            || order.status == OrderStatus::Processing
348        {
349            if i >= attempts {
350                return Err(Error::MaxAttemptsExceeded);
351            }
352            debug!(
353              { delay = ?poll_interval, status = ?order.status },
354              "Order not done. Waiting to poll."
355            );
356            tokio::time::sleep(poll_interval).await;
357            order = order.poll().await?;
358            i += 1;
359        }
360
361        Ok(order)
362    }
363}