forked from TrueCloudLab/lego
Split off validation function.
This is a loop that interacts with the ACME server, not the individual challenges. Also switch to exponential back-off polling for good measure.
This commit is contained in:
parent
237689b0cf
commit
58a2fd2267
3 changed files with 81 additions and 92 deletions
|
@ -670,3 +670,82 @@ func parseLinks(links []string) map[string]string {
|
||||||
|
|
||||||
return linkMap
|
return linkMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate makes the ACME server start validating a
|
||||||
|
// challenge response, only returning once it is done.
|
||||||
|
func validate(j *jws, uri string, chlng challenge) error {
|
||||||
|
var challengeResponse challenge
|
||||||
|
|
||||||
|
if err := postJSON(j, uri, chlng, &challengeResponse); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
interval := 1 * time.Second
|
||||||
|
maxInterval := 15 * time.Minute
|
||||||
|
|
||||||
|
// After the path is sent, the ACME server will access our server.
|
||||||
|
// Repeatedly check the server for an updated status on our request.
|
||||||
|
for {
|
||||||
|
switch challengeResponse.Status {
|
||||||
|
case "valid":
|
||||||
|
logf("The server validated our request")
|
||||||
|
return nil
|
||||||
|
case "pending":
|
||||||
|
break
|
||||||
|
case "invalid":
|
||||||
|
return errors.New("The server could not validate our request.")
|
||||||
|
default:
|
||||||
|
return errors.New("The server returned an unexpected state.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poll with exponential back-off.
|
||||||
|
time.Sleep(interval)
|
||||||
|
interval *= 2
|
||||||
|
if interval > maxInterval {
|
||||||
|
interval = maxInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := getJSON(uri, &challengeResponse); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getJSON performs an HTTP GET request and parses the response body
|
||||||
|
// as JSON, into the provided respBody object.
|
||||||
|
func getJSON(uri string, respBody interface{}) error {
|
||||||
|
resp, err := http.Get(uri)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get %q: %v", uri, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
|
return handleHTTPError(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.NewDecoder(resp.Body).Decode(respBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
// postJSON performs an HTTP POST request and parses the response body
|
||||||
|
// as JSON, into the provided respBody object.
|
||||||
|
func postJSON(j *jws, uri string, reqBody, respBody interface{}) error {
|
||||||
|
jsonBytes, err := json.Marshal(reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("Failed to marshal network message...")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := j.post(uri, jsonBytes)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to post JWS message. -> %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusBadRequest {
|
||||||
|
return handleHTTPError(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.NewDecoder(resp.Body).Decode(respBody)
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type httpChallenge struct {
|
type httpChallenge struct {
|
||||||
|
@ -47,49 +44,7 @@ func (s *httpChallenge) Solve(chlng challenge, domain string) error {
|
||||||
close(s.end)
|
close(s.end)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
jsonBytes, err := json.Marshal(challenge{Resource: "challenge", Type: chlng.Type, Token: chlng.Token, KeyAuthorization: keyAuth})
|
return validate(s.jws, chlng.URI, challenge{Resource: "challenge", Type: chlng.Type, Token: chlng.Token, KeyAuthorization: keyAuth})
|
||||||
if err != nil {
|
|
||||||
return errors.New("Failed to marshal network message...")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the server we handle HTTP-01
|
|
||||||
resp, err := s.jws.post(chlng.URI, jsonBytes)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to post JWS message. -> %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// After the path is sent, the ACME server will access our server.
|
|
||||||
// Repeatedly check the server for an updated status on our request.
|
|
||||||
var challengeResponse challenge
|
|
||||||
Loop:
|
|
||||||
for {
|
|
||||||
if resp.StatusCode >= http.StatusBadRequest {
|
|
||||||
return handleHTTPError(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.NewDecoder(resp.Body).Decode(&challengeResponse)
|
|
||||||
resp.Body.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch challengeResponse.Status {
|
|
||||||
case "valid":
|
|
||||||
logf("The server validated our request")
|
|
||||||
break Loop
|
|
||||||
case "pending":
|
|
||||||
break
|
|
||||||
case "invalid":
|
|
||||||
return errors.New("The server could not validate our request.")
|
|
||||||
default:
|
|
||||||
return errors.New("The server returned an unexpected state.")
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
resp, err = http.Get(chlng.URI)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *httpChallenge) startHTTPServer(domain string, token string, keyAuth string) {
|
func (s *httpChallenge) startHTTPServer(domain string, token string, keyAuth string) {
|
||||||
|
|
|
@ -5,12 +5,9 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tlsSNIChallenge struct {
|
type tlsSNIChallenge struct {
|
||||||
|
@ -57,49 +54,7 @@ func (t *tlsSNIChallenge) Solve(chlng challenge, domain string) error {
|
||||||
close(t.end)
|
close(t.end)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
jsonBytes, err := json.Marshal(challenge{Resource: "challenge", Type: chlng.Type, Token: chlng.Token, KeyAuthorization: keyAuth})
|
return validate(t.jws, chlng.URI, challenge{Resource: "challenge", Type: chlng.Type, Token: chlng.Token, KeyAuthorization: keyAuth})
|
||||||
if err != nil {
|
|
||||||
return errors.New("Failed to marshal network message...")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the server we handle TLS-SNI-01
|
|
||||||
resp, err := t.jws.post(chlng.URI, jsonBytes)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to post JWS message. -> %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// After the path is sent, the ACME server will access our server.
|
|
||||||
// Repeatedly check the server for an updated status on our request.
|
|
||||||
var challengeResponse challenge
|
|
||||||
Loop:
|
|
||||||
for {
|
|
||||||
if resp.StatusCode >= http.StatusBadRequest {
|
|
||||||
return handleHTTPError(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.NewDecoder(resp.Body).Decode(&challengeResponse)
|
|
||||||
resp.Body.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch challengeResponse.Status {
|
|
||||||
case "valid":
|
|
||||||
logf("The server validated our request")
|
|
||||||
break Loop
|
|
||||||
case "pending":
|
|
||||||
break
|
|
||||||
case "invalid":
|
|
||||||
return errors.New("The server could not validate our request.")
|
|
||||||
default:
|
|
||||||
return errors.New("The server returned an unexpected state.")
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
resp, err = http.Get(chlng.URI)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tlsSNIChallenge) generateCertificate(keyAuth string) (tls.Certificate, error) {
|
func (t *tlsSNIChallenge) generateCertificate(keyAuth string) (tls.Certificate, error) {
|
||||||
|
|
Loading…
Reference in a new issue