diff --git a/README.md b/README.md index 25817e08..355b8fc6 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,18 @@ run: `PEBBLE_VA_ALWAYS_VALID=1 pebble` +### Just-in-Time Validation + +When creating a new order, Pebble MAY perform an immediate DNS lookup +for _validation-persist TXT records at the Validation Domain Name +corresponding to the requested domain identifier. If this check succeed, +Auth for that domain will move to valid state directly without client +request asking to do so. + +To make pebble to try dns-persist-01 challenge at order creation time: + +`PEBBLE_WFE_JITVALIDATION=1 pebble` + ### Invalid Anti-Replay Nonce Errors The `urn:ietf:params:acme:error:badNonce` error type is meant to be retry-able. diff --git a/va/va.go b/va/va.go index 33c3fb93..a2c1aa73 100644 --- a/va/va.go +++ b/va/va.go @@ -183,6 +183,27 @@ func (va VAImpl) ValidateChallenge(ident acme.Identifier, chal *core.Challenge, va.tasks <- task } +func (va VAImpl) JITValidateChallenge(ident acme.Identifier, chal *core.Challenge, acct *core.Account, acctURL string, wildcard bool) { + task := &vaTask{ + Identifier: ident, + Challenge: chal, + Account: acct, + AccountURL: acctURL, + Wildcard: wildcard, + } + va.log.Printf("try Just-in-time validation for identifier %s", ident) + result := va.validateDNSPersist01(task) + va.log.Print(result) + if va.alwaysValid || result.Error == nil { + va.log.Printf("JIT validation succied for identifier %s", ident) + va.setAuthzValid(chal.Authz, chal) + } else { + chal.Lock() + chal.Validated = "" + chal.Unlock() + } +} + func (va VAImpl) processTasks() { for task := range va.tasks { go va.process(task) diff --git a/wfe/wfe.go b/wfe/wfe.go index 54f65e19..68ec6594 100644 --- a/wfe/wfe.go +++ b/wfe/wfe.go @@ -110,6 +110,10 @@ const ( // valid authorization exists or not for each identifier in an order. authzReuseEnvVar = "PEBBLE_AUTHZREUSE" + // jitEnvVar defines an environment variable name used to wether if wfe + // should ask VA if there is valid dns-persist-01 record at order creation time + jitEnvVar = "PEBBLE_WFE_JITVALIDATION" + // The default value when PEBBLE_WFE_AUTHZREUSE is not set, how often to try // and reuse valid authorizations. defaultAuthzReuse = 50 @@ -173,6 +177,7 @@ type WebFrontEndImpl struct { caaIdentities []string strict bool requireEAB bool + jitValidation bool retryAfterAuthz int retryAfterOrder int } @@ -218,6 +223,14 @@ func New( log.Printf("Configured to attempt authz reuse for each identifier %d%% of the time", authzReusePercent) + jitvalidation := false + jitvar := os.Getenv(jitEnvVar) + switch jitvar { + case "1", "true", "True", "TRUE": + jitvalidation = true + log.Printf("enabling JIT validation requests. WFE will request dns-persist-01 lookup at order creation time") + } + // Read the number of orders per page that should be returned. ordersPerPageVal := os.Getenv(ordersPerPageEnvVar) var ordersPerPage int @@ -241,6 +254,7 @@ func New( ordersPerPage: ordersPerPage, va: va, ca: ca, + jitValidation: jitvalidation, strict: strict, requireEAB: requireEAB, retryAfterAuthz: retryAfterAuthz, @@ -1584,6 +1598,16 @@ func (wfe *WebFrontEndImpl) makeAuthorizations(order *core.Order, request *http. if err != nil { return err } + + wfe.log.Print("trying jit validation for ", ident) + // try dns-persist-01 JIT validation + for _, chal := range authz.Challenges { + if chal.Type == acme.ChallengeDNSPersist01 { + wfe.va.JITValidateChallenge(ident, chal, nil, order.AccountID, authz.Wildcard) + // dns-persist-01 validation doesn't care about account key so we can leave it emmpty + } + } + wfe.log.Printf("There are now %d authorizations in the db\n", count) }