1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Well-known endpoint handlers for domain verification.
use crateSaasState;
use cratehost_matches;
use ;
/// What an unknown, expired, resolved, or wrong-host token gets.
///
/// The same answer for all of them on purpose: distinguishing "no such token"
/// from "that token is for another domain" would confirm a token's existence
/// to whoever is probing.
const NOT_FOUND: = ;
/// Serve an HTTP domain-verification challenge.
///
/// Responds at `/.well-known/postrust-verification/{token}` with the content
/// recorded when the challenge was issued, and only for the domain it was
/// issued for.
///
/// This used to compute `postrust-verify={token}` from whatever token was in
/// the path and return it, with no database lookup and no host check -- so
/// every token verified, for every domain, and the check proved nothing. It
/// now answers only for a challenge that is in the database, is not expired,
/// is not already resolved, and whose domain matches the request's `Host`.
///
/// The host check is what keeps a token scoped. A token is a bearer secret for
/// exactly one domain; answering with it on some other host hands that secret
/// to whoever asked for it.
///
/// A caveat worth stating plainly, because no amount of care here removes it:
/// HTTP verification asks the claimant to serve content at a path on the
/// domain, and once that domain's DNS points at this proxy, this proxy is what
/// serves that path. Passing therefore shows the domain resolves here and a
/// challenge was issued for it -- not that the claimant controls the domain.
/// DNS verification does show that, which is why it is the default
/// (`verification_method` defaults to `dns`). Prefer it.
pub async
/// Serve an ACME HTTP-01 challenge.
///
/// Responds at `/.well-known/acme-challenge/{token}` with the key
/// authorization the issuer recorded when it placed the order. The CA fetches
/// this over plain HTTP -- it is how it decides the requester controls the
/// domain -- so the route is public and unauthenticated by necessity.
///
/// Answering is safe because the value is not a secret we are being tricked
/// into revealing: it is `{token}.{account_key_thumbprint}`, which we wrote
/// ourselves, for a token the CA has just told us it will ask for. A token
/// nobody stored gets a 404.
///
/// The lookup goes to `proxy_acme_challenges` rather than to memory on purpose:
/// the CA resolves the domain and reaches whichever instance DNS sends it to,
/// which is usually not the one that placed the order.
///
/// Unlike the domain-verification endpoint, this deliberately does **not**
/// match on `Host`. RFC 8555 lets the CA validate from several vantage points
/// and follow redirects, and the token already scopes the response to one
/// order; requiring a `Host` match here would fail validation for a domain
/// served under an alias, and buy nothing -- the value is not sensitive.
///
/// Requires the `acme` feature: without the issuer there is nothing to write a
/// challenge, so the route is not mounted at all rather than answering 404 to
/// every CA that asks.
pub async