@@ -42,12 +42,13 @@ const (
4242 ChallengeTypeDNS01 = AcmeChallenge ("dns-01" )
4343 ChallengeTypeTLSALPN01 = AcmeChallenge ("tls-alpn-01" )
4444 ChallengeTypeDNSAccount01 = AcmeChallenge ("dns-account-01" )
45+ ChallengeTypeDNSPersist01 = AcmeChallenge ("dns-persist-01" )
4546)
4647
4748// IsValid tests whether the challenge is a known challenge
4849func (c AcmeChallenge ) IsValid () bool {
4950 switch c {
50- case ChallengeTypeHTTP01 , ChallengeTypeDNS01 , ChallengeTypeTLSALPN01 , ChallengeTypeDNSAccount01 :
51+ case ChallengeTypeHTTP01 , ChallengeTypeDNS01 , ChallengeTypeTLSALPN01 , ChallengeTypeDNSAccount01 , ChallengeTypeDNSPersist01 :
5152 return true
5253 default :
5354 return false
@@ -68,9 +69,12 @@ var OCSPStatusToInt = map[OCSPStatus]int{
6869 OCSPStatusRevoked : ocsp .Revoked ,
6970}
7071
71- // DNSPrefix is attached to DNS names in DNS challenges
72+ // DNSPrefix is attached to DNS names in dns-01 and dns-account-01 challenges
7273const DNSPrefix = "_acme-challenge"
7374
75+ // DNSPersistPrefix is attached to DNS names in dns-persist-01 challenges.
76+ const DNSPersistPrefix = "_validation-persist"
77+
7478type RawCertificateRequest struct {
7579 CSR JSONBuffer `json:"csr"` // The encoded CSR
7680}
@@ -156,9 +160,13 @@ type Challenge struct {
156160 Error * probs.ProblemDetails `json:"error,omitempty"`
157161
158162 // Token is a random value that uniquely identifies the challenge. It is used
159- // by all current challenges (http-01, tls-alpn -01, and dns-01) .
163+ // by all challenges except dns-persist -01.
160164 Token string `json:"token,omitempty"`
161165
166+ // IssuerDomainNames contains the list of issuer domain name values accepted
167+ // during dns-persist-01 challenge validation.
168+ IssuerDomainNames []string `json:"issuer-domain-names,omitempty"`
169+
162170 // Contains information about URLs used or redirected to and IPs resolved and
163171 // used
164172 ValidationRecord []ValidationRecord `json:"validationRecord,omitempty"`
@@ -209,7 +217,7 @@ func (ch Challenge) RecordsSane() bool {
209217 (ch .ValidationRecord [0 ].AddressUsed == netip.Addr {}) || len (ch .ValidationRecord [0 ].AddressesResolved ) == 0 {
210218 return false
211219 }
212- case ChallengeTypeDNS01 , ChallengeTypeDNSAccount01 :
220+ case ChallengeTypeDNS01 , ChallengeTypeDNSAccount01 , ChallengeTypeDNSPersist01 :
213221 if len (ch .ValidationRecord ) > 1 {
214222 return false
215223 }
@@ -226,14 +234,20 @@ func (ch Challenge) RecordsSane() bool {
226234 return true
227235}
228236
229- // CheckPending ensures that a challenge object is pending and has a token.
230- // This is used before offering the challenge to the client, and before actually
231- // validating a challenge.
237+ // CheckPending ensures that a challenge object is pending and, for challenge
238+ // types that require one, has a token. This is used before offering the
239+ // challenge to the client, and before actually validating a challenge.
232240func (ch Challenge ) CheckPending () error {
233241 if ch .Status != StatusPending {
234242 return fmt .Errorf ("challenge is not pending" )
235243 }
236244
245+ // dns-persist-01 does not use a token; validation relies on persistent
246+ // DNS TXT records containing the issuer-domain-name and accounturi.
247+ if ch .Type == ChallengeTypeDNSPersist01 {
248+ return nil
249+ }
250+
237251 if ! looksLikeAToken (ch .Token ) {
238252 return fmt .Errorf ("token is missing or malformed" )
239253 }
0 commit comments