Skip to content

Commit

Permalink
Adds DNS-01 challenge type support. (#19)
Browse files Browse the repository at this point in the history
This commit adds DNS-01 challenges as a supported challenge type for
Pebble. The WFE is modified to construct a DNS-01 challenge along with
the HTTP-01 and TLS-SNI-02 challenges for every new pending authz.
A new configuration parameter is added to the config file for the
upstream DNS resolvers to use.

The validation implementation is very close to Boulder's VA & `bdns`
implementation, but simplified for just TXT records & a simple DNS-01
challenge mechanism. Note: this commit adds a dependency on miekg/dns
and you may need to `go get ./...` since we don't do any sort of godeps
magic/vendoring at present.
  • Loading branch information
cpu authored and jsha committed Apr 19, 2017
1 parent 2e83f77 commit 60690c1
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
1 change: 1 addition & 0 deletions acme/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (

ChallengeHTTP01 = "http-01"
ChallengeTLSSNI02 = "tls-sni-02"
ChallengeDNS01 = "dns-01"

HTTP01BaseURL = ".well-known/acme-challenge/"
)
Expand Down
48 changes: 46 additions & 2 deletions va/va.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/subtle"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -71,7 +72,11 @@ type VAImpl struct {
ca *ca.CAImpl
}

func New(log *log.Logger, clk clock.Clock, httpPort, tlsPort int, ca *ca.CAImpl) *VAImpl {
func New(
log *log.Logger,
clk clock.Clock,
httpPort, tlsPort int,
ca *ca.CAImpl) *VAImpl {
va := &VAImpl{
log: log,
clk: clk,
Expand Down Expand Up @@ -199,17 +204,56 @@ func (va VAImpl) performValidation(task *vaTask, results chan<- *core.Validation
va.log.Printf("Sleeping for %s seconds before validating", time.Second*len)
va.clk.Sleep(time.Second * len)

// TODO(@cpu): Implement validation for DNS-01
switch task.Challenge.Type {
case acme.ChallengeHTTP01:
results <- va.validateHTTP01(task)
case acme.ChallengeTLSSNI02:
results <- va.validateTLSSNI02(task)
case acme.ChallengeDNS01:
results <- va.validateDNS01(task)
default:
va.log.Printf("Error: performValidation(): Invalid challenge type: %q", task.Challenge.Type)
}
}

func (va VAImpl) validateDNS01(task *vaTask) *core.ValidationRecord {
const dns01Prefix = "_acme-challenge"
challengeSubdomain := fmt.Sprintf("%s.%s", dns01Prefix, task.Identifier)

result := &core.ValidationRecord{
URL: challengeSubdomain,
ValidatedAt: va.clk.Now(),
}

txts, err := net.LookupTXT(challengeSubdomain)
if err != nil {
result.Error = acme.UnauthorizedProblem("Error retrieving TXT records for DNS challenge")
return result
}

if len(txts) == 0 {
msg := fmt.Sprintf("No TXT records found for DNS challenge")
result.Error = acme.UnauthorizedProblem(msg)
return result
}

h := sha256.New()
task.Challenge.RLock()
h.Write([]byte(task.Challenge.KeyAuthorization))
task.Challenge.RUnlock()
authorizedKeysDigest := base64.RawURLEncoding.EncodeToString(h.Sum(nil))

for _, element := range txts {
if subtle.ConstantTimeCompare([]byte(element), []byte(authorizedKeysDigest)) == 1 {
return result
}
}

msg := fmt.Sprintf("Correct value not found for DNS challenge")
result.Error = acme.UnauthorizedProblem(msg)
return result
}

func (va VAImpl) validateTLSSNI02(task *vaTask) *core.ValidationRecord {
portString := strconv.Itoa(va.tlsPort)
hostPort := net.JoinHostPort(task.Identifier, portString)
Expand Down
4 changes: 2 additions & 2 deletions wfe/wfe.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,8 @@ func (wfe *WebFrontEndImpl) makeChallenge(
func (wfe *WebFrontEndImpl) makeChallenges(authz *core.Authorization, request *http.Request) error {
var chals []*core.Challenge

// TODO(@cpu): construct challenges for DNS-01
for _, chalType := range []string{acme.ChallengeHTTP01, acme.ChallengeTLSSNI02} {
enabledChallenges := []string{acme.ChallengeHTTP01, acme.ChallengeTLSSNI02, acme.ChallengeDNS01}
for _, chalType := range enabledChallenges {
chal, err := wfe.makeChallenge(chalType, authz, request)
if err != nil {
return err
Expand Down

0 comments on commit 60690c1

Please sign in to comment.