Implement DoH for validation queries (#7178)

Fixes: #7141
This commit is contained in:
Jacob Hoffman-Andrews 2023-12-11 10:49:00 -08:00 committed by GitHub
parent 44587c1165
commit c21b376623
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 195 additions and 40 deletions

View File

@ -36,7 +36,7 @@ jobs:
matrix:
# Add additional docker image tags here and all tests will be run with the additional image.
BOULDER_TOOLS_TAG:
- go1.21.5_2023-12-05
- go1.21.5_2023-12-07
# Tests command definitions. Use the entire "docker compose" command you want to run.
tests:
# Run ./test.sh --help for a description of each of the flags.

View File

@ -2,10 +2,13 @@ package bdns
import (
"context"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"io"
"net"
"net/http"
"strconv"
"strings"
"sync"
@ -15,6 +18,7 @@ import (
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
"github.com/letsencrypt/boulder/features"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/metrics"
)
@ -175,6 +179,9 @@ type exchanger interface {
// New constructs a new DNS resolver object that utilizes the
// provided list of DNS servers for resolution.
//
// `tlsConfig` is the configuration used for outbound DoH queries,
// if applicable.
func New(
readTimeout time.Duration,
servers ServerProvider,
@ -182,12 +189,26 @@ func New(
clk clock.Clock,
maxTries int,
log blog.Logger,
tlsConfig *tls.Config,
) Client {
dnsClient := new(dns.Client)
// Set timeout for underlying net.Conn
dnsClient.ReadTimeout = readTimeout
dnsClient.Net = "udp"
var client exchanger
if features.Enabled(features.DOH) {
client = &dohExchanger{
clk: clk,
hc: http.Client{
Timeout: readTimeout,
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
},
}
} else {
client = &dns.Client{
// Set timeout for underlying net.Conn
ReadTimeout: readTimeout,
Net: "udp",
}
}
queryTime := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
@ -220,9 +241,8 @@ func New(
[]string{"qtype", "resolver"},
)
stats.MustRegister(queryTime, totalLookupTime, timeoutCounter, idMismatchCounter)
return &impl{
dnsClient: dnsClient,
dnsClient: client,
servers: servers,
allowRestrictedAddresses: false,
maxTries: maxTries,
@ -244,8 +264,10 @@ func NewTest(
stats prometheus.Registerer,
clk clock.Clock,
maxTries int,
log blog.Logger) Client {
resolver := New(readTimeout, servers, stats, clk, maxTries, log)
log blog.Logger,
tlsConfig *tls.Config,
) Client {
resolver := New(readTimeout, servers, stats, clk, maxTries, log, tlsConfig)
resolver.(*impl).allowRestrictedAddresses = true
return resolver
}
@ -619,3 +641,49 @@ func logDNSError(
underlying)
}
}
type dohExchanger struct {
clk clock.Clock
hc http.Client
}
// Exchange sends a DoH query to the provided DoH server and returns the response.
func (d *dohExchanger) Exchange(query *dns.Msg, server string) (*dns.Msg, time.Duration, error) {
q, err := query.Pack()
if err != nil {
return nil, 0, err
}
// The default Unbound URL template
url := fmt.Sprintf("https://%s/dns-query", server)
req, err := http.NewRequest("POST", url, strings.NewReader(string(q)))
if err != nil {
return nil, 0, err
}
req.Header.Set("Content-Type", "application/dns-message")
req.Header.Set("Accept", "application/dns-message")
start := d.clk.Now()
resp, err := d.hc.Do(req)
if err != nil {
return nil, d.clk.Since(start), err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, d.clk.Since(start), fmt.Errorf("doh: http status %d", resp.StatusCode)
}
b, err := io.ReadAll(resp.Body)
if err != nil {
return nil, d.clk.Since(start), fmt.Errorf("doh: reading response body: %w", err)
}
response := new(dns.Msg)
err = response.Unpack(b)
if err != nil {
return nil, d.clk.Since(start), fmt.Errorf("doh: unpacking response: %w", err)
}
return response, d.clk.Since(start), nil
}

View File

@ -248,7 +248,7 @@ func TestDNSNoServers(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Hour, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Hour, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
_, err = obj.LookupHost(context.Background(), "letsencrypt.org")
test.AssertError(t, err, "No servers")
@ -264,7 +264,7 @@ func TestDNSOneServer(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
_, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org")
@ -275,7 +275,7 @@ func TestDNSDuplicateServers(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr, dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
_, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org")
@ -286,7 +286,7 @@ func TestDNSServFail(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
bad := "servfail.com"
_, err = obj.LookupTXT(context.Background(), bad)
@ -304,7 +304,7 @@ func TestDNSLookupTXT(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
a, err := obj.LookupTXT(context.Background(), "letsencrypt.org")
t.Logf("A: %v", a)
@ -321,7 +321,7 @@ func TestDNSLookupHost(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
ip, err := obj.LookupHost(context.Background(), "servfail.com")
t.Logf("servfail.com - IP: %s, Err: %s", ip, err)
@ -389,7 +389,7 @@ func TestDNSNXDOMAIN(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
hostname := "nxdomain.letsencrypt.org"
_, err = obj.LookupHost(context.Background(), hostname)
@ -405,7 +405,7 @@ func TestDNSLookupCAA(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock())
obj := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, blog.UseMock(), nil)
removeIDExp := regexp.MustCompile(" id: [[:digit:]]+")
caas, resp, err := obj.LookupCAA(context.Background(), "bracewel.net")
@ -639,7 +639,7 @@ func TestRetry(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
testClient := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), tc.maxTries, blog.UseMock())
testClient := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), tc.maxTries, blog.UseMock(), nil)
dr := testClient.(*impl)
dr.dnsClient = tc.te
_, err = dr.LookupTXT(context.Background(), "example.com")
@ -670,7 +670,7 @@ func TestRetry(t *testing.T) {
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
test.AssertNotError(t, err, "Got error creating StaticProvider")
testClient := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 3, blog.UseMock())
testClient := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 3, blog.UseMock(), nil)
dr := testClient.(*impl)
dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}}
ctx, cancel := context.WithCancel(context.Background())
@ -774,7 +774,7 @@ func TestRotateServerOnErr(t *testing.T) {
fmt.Println(staticProvider.servers)
maxTries := 5
client := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), maxTries, blog.UseMock())
client := NewTest(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), maxTries, blog.UseMock(), nil)
// Configure a mock exchanger that will always return a retryable error for
// servers A and B. This will force server "[2606:4700:4700::1111]:53" to do

View File

@ -109,6 +109,8 @@ type dynamicProvider struct {
// service is the service name to look up SRV records for within the domain.
// If this field is left unspecified 'dns' will be used as the service name.
service string
// proto is the IP protocol (tcp or udp) to look up SRV records for.
proto string
// domain is the name to look up SRV records within.
domain string
// A map of IP addresses (results of A record lookups for SRV Targets) to
@ -174,7 +176,9 @@ var _ ServerProvider = &dynamicProvider{}
// at refresh intervals and uses the resulting IP/port combos to populate the
// list returned by Addrs. The update process ignores the Priority and Weight
// attributes of the SRV records.
func StartDynamicProvider(c *cmd.DNSProvider, refresh time.Duration) (*dynamicProvider, error) {
//
// `proto` is the IP protocol (tcp or udp) to look up SRV records for.
func StartDynamicProvider(c *cmd.DNSProvider, refresh time.Duration, proto string) (*dynamicProvider, error) {
if c.SRVLookup.Domain == "" {
return nil, fmt.Errorf("'domain' cannot be empty")
}
@ -200,6 +204,7 @@ func StartDynamicProvider(c *cmd.DNSProvider, refresh time.Duration) (*dynamicPr
dp := dynamicProvider{
dnsAuthority: dnsAuthority,
service: service,
proto: proto,
domain: c.SRVLookup.Domain,
addrs: make(map[string][]uint16),
cancel: make(chan interface{}),
@ -263,9 +268,9 @@ func (dp *dynamicProvider) update() error {
}
// RFC 2782 formatted SRV record being queried e.g. "_service._proto.name."
record := fmt.Sprintf("_%s._udp.%s.", dp.service, dp.domain)
record := fmt.Sprintf("_%s._%s.%s.", dp.service, dp.proto, dp.domain)
_, srvs, err := resolver.LookupSRV(ctx, dp.service, "udp", dp.domain)
_, srvs, err := resolver.LookupSRV(ctx, dp.service, dp.proto, dp.domain)
if err != nil {
return fmt.Errorf("during SRV lookup of %q: %w", record, err)
}

View File

@ -85,10 +85,17 @@ func main() {
}
var servers bdns.ServerProvider
servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second)
proto := "udp"
if features.Enabled(features.DOH) {
proto = "tcp"
}
servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second, proto)
cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver")
defer servers.Stop()
tlsConfig, err := c.VA.TLS.Load(scope)
cmd.FailOnError(err, "tlsConfig config")
var resolver bdns.Client
if !c.VA.DNSAllowLoopbackAddresses {
resolver = bdns.New(
@ -97,7 +104,8 @@ func main() {
scope,
clk,
dnsTries,
logger)
logger,
tlsConfig)
} else {
resolver = bdns.NewTest(
c.VA.DNSTimeout.Duration,
@ -105,12 +113,10 @@ func main() {
scope,
clk,
dnsTries,
logger)
logger,
tlsConfig)
}
tlsConfig, err := c.VA.TLS.Load(scope)
cmd.FailOnError(err, "tlsConfig config")
var remotes []va.RemoteVA
if len(c.VA.RemoteVAs) > 0 {
for _, rva := range c.VA.RemoteVAs {

View File

@ -29,11 +29,12 @@ func _() {
_ = x[AllowNoCommonName-18]
_ = x[CAAAfterValidation-19]
_ = x[SHA256SubjectKeyIdentifier-20]
_ = x[DOH-21]
}
const _FeatureFlag_name = "unusedStoreRevokerInfoROCSPStage6ROCSPStage7StoreLintingCertificateInsteadOfPrecertificateCAAValidationMethodsCAAAccountURILeaseCRLShardsEnforceMultiVAMultiVAFullResultsECDSAForAllServeRenewalInfoAllowUnrecognizedFeaturesExpirationMailerUsesJoinCertCheckerChecksValidationsCertCheckerRequiresValidationsCertCheckerRequiresCorrespondenceAsyncFinalizeAllowNoCommonNameCAAAfterValidationSHA256SubjectKeyIdentifier"
const _FeatureFlag_name = "unusedStoreRevokerInfoROCSPStage6ROCSPStage7StoreLintingCertificateInsteadOfPrecertificateCAAValidationMethodsCAAAccountURILeaseCRLShardsEnforceMultiVAMultiVAFullResultsECDSAForAllServeRenewalInfoAllowUnrecognizedFeaturesExpirationMailerUsesJoinCertCheckerChecksValidationsCertCheckerRequiresValidationsCertCheckerRequiresCorrespondenceAsyncFinalizeAllowNoCommonNameCAAAfterValidationSHA256SubjectKeyIdentifierDOH"
var _FeatureFlag_index = [...]uint16{0, 6, 22, 33, 44, 90, 110, 123, 137, 151, 169, 180, 196, 221, 245, 273, 303, 336, 349, 366, 384, 410}
var _FeatureFlag_index = [...]uint16{0, 6, 22, 33, 44, 90, 110, 123, 137, 151, 169, 180, 196, 221, 245, 273, 303, 336, 349, 366, 384, 410, 413}
func (i FeatureFlag) String() string {
if i < 0 || i >= FeatureFlag(len(_FeatureFlag_index)-1) {

View File

@ -86,11 +86,15 @@ const (
// compliant truncated SHA256 Subject Key Identifier in end-entity
// certificates.
SHA256SubjectKeyIdentifier
// DOH enables DNS-over-HTTPS queries for validation
DOH
)
// List of features and their default value, protected by fMu
var features = map[FeatureFlag]bool{
unused: false,
DOH: false,
CAAValidationMethods: false,
CAAAccountURI: false,
EnforceMultiVA: false,

View File

@ -19,7 +19,7 @@ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.0
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0
go install github.com/rubenv/sql-migrate/sql-migrate@v1.1.2
go install golang.org/x/tools/cmd/stringer@latest
go install github.com/letsencrypt/pebble/cmd/pebble-challtestsrv@master
go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@66511d8
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.53.3
go install honnef.co/go/tools/cmd/staticcheck@2023.1.5

View File

@ -5,7 +5,7 @@
"dnsProvider": {
"dnsAuthority": "consul.service.consul",
"srvLookup": {
"service": "dns",
"service": "doh",
"domain": "service.consul"
}
},
@ -33,7 +33,8 @@
}
},
"features": {
"CAAAfterValidation": true
"CAAAfterValidation": true,
"DOH": true
},
"accountURIPrefixes": [
"http://boulder.service.consul:4000/acme/reg/",

View File

@ -5,7 +5,7 @@
"dnsProvider": {
"dnsAuthority": "consul.service.consul",
"srvLookup": {
"service": "dns",
"service": "doh",
"domain": "service.consul"
}
},
@ -33,7 +33,8 @@
}
},
"features": {
"CAAAfterValidation": true
"CAAAfterValidation": true,
"DOH": true
},
"accountURIPrefixes": [
"http://boulder.service.consul:4000/acme/reg/",

View File

@ -5,7 +5,7 @@
"dnsProvider": {
"dnsAuthority": "consul.service.consul",
"srvLookup": {
"service": "dns",
"service": "doh",
"domain": "service.consul"
}
},
@ -40,7 +40,8 @@
"features": {
"EnforceMultiVA": true,
"MultiVAFullResults": true,
"CAAAfterValidation": true
"CAAAfterValidation": true,
"DOH": true
},
"remoteVAs": [
{

View File

@ -115,6 +115,22 @@ services {
tags = ["udp"] // Required for SRV RR support in VA RVA.
}
services {
id = "doh-a"
name = "doh"
address = "10.77.77.77"
port = 8443
tags = ["tcp"]
}
services {
id = "doh-b"
name = "doh"
address = "10.88.88.88"
port = 8443
tags = ["tcp"]
}
services {
id = "nonce-a"
name = "nonce"

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDjCCAfagAwIBAgIIQbFdR2fXsHswDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
AxMVbWluaWNhIHJvb3QgY2EgM2I4YjJjMB4XDTIzMTIwODE4MDkzMloXDTI2MDEw
NzE4MDkzMlowFjEUMBIGA1UEAxMLMTAuNzcuNzcuNzcwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCrE64Z4Yh4E6aQ1zQiNgCvW5LWBI9yZZybZxLV5J1C
yMtpgY3YsCPZ/6JUI4SvabenU5Pa3T407eHjmDCRNce04j4BE6e7psPjRa7hvI2A
+IvLB7eiaCnE+sdAMFsLxraWwTu67tmeRxYxWScMpULlFren3HNNqmtAN3a4yGy5
y2pHMgCnOSE9R53tuF2uqJ8BRW44VLDt4kZ9hwm0dW8EJY8MBCACPGtW2YwBG/5E
zrRKDWSBl9g3mYOwgRdxUMV1h0eVr/llVFb+/UZCLUb5zq/zKKEkYOT4Ihr7wtin
ahLwwVwdUsMNE9NzljMC/aIR74qhBeN2xAJ3ZZQKrqL1AgMBAAGjVjBUMA4GA1Ud
DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
AQH/BAIwADAVBgNVHREEDjAMhwQKTU1NhwQKWFhYMA0GCSqGSIb3DQEBCwUAA4IB
AQCOa5b+zRgQBhlPWiC04K5C/Ys3dUtqKhKrWvPIiraNi792X/T5t1ZL9liV9A6n
b10hHcCDIfyRFIJRyE8G2fyzqNlGwCr8J6puWrg4wMPt8q+6a4r2ZqaXm3aQTfGs
4Tgxz10gOVimeiUshVyrpaceyiboOKxJbBRuLNTTK9Jp74fWRd+F8KAINWN+SpF4
6ggzXNiPYZZTBPGeAOMyf0rnf7CWAbw017uHhCiykJkMy8sZJcmQF49gDZTIN9pt
eI0SeB4ku5lgAOunqrTGyPLeVaevtcU//TdATuukhnCFes6vt/6yC+sWQEhEQw7P
y2Kp8T8KcOlTeKr8Cb07B2M0
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAqxOuGeGIeBOmkNc0IjYAr1uS1gSPcmWcm2cS1eSdQsjLaYGN
2LAj2f+iVCOEr2m3p1OT2t0+NO3h45gwkTXHtOI+AROnu6bD40Wu4byNgPiLywe3
omgpxPrHQDBbC8a2lsE7uu7ZnkcWMVknDKVC5Ra3p9xzTaprQDd2uMhsuctqRzIA
pzkhPUed7bhdrqifAUVuOFSw7eJGfYcJtHVvBCWPDAQgAjxrVtmMARv+RM60Sg1k
gZfYN5mDsIEXcVDFdYdHla/5ZVRW/v1GQi1G+c6v8yihJGDk+CIa+8LYp2oS8MFc
HVLDDRPTc5YzAv2iEe+KoQXjdsQCd2WUCq6i9QIDAQABAoIBACgZH8ifLT5/1J3E
Y0rVf4manCsfvIOiv3dJTIfn4thhehQLsrSkbHLPUTwJazM2Qz6r/07gZpE/ZJ/U
7yVKBromAUR9V+ZK60Uc8yWj7ULafuGiuG8PnSK3aPZpnx1+gROKzTY+f7FylggR
Dm8PWUOa9Icay8fbdvIBTgl3qMxPOCgLyXNXNJHcKIPb71L1T5EL2H9Z5vHF9tFy
TnbpeK0GlmBHIeseVaFzruin3sqxjRftVEgTL5XhTq/9uY3EUutq8SGRoidbpp/+
cr0I1IpFcrJVmJHKdfJkdRI2u3LtMKS3bpqJU7MKn1DRzvQatdSQwn/V8wU3iG8o
04dus60CgYEA3IBOLJRfMFgj6LbMSySoP8JIzVvnBHIMXGd7mzuYUlV2GjVO5oD2
nh4Q3eGDT2TZ1GbaGGHLhpCXIx87oSXHZz+vw+sDh+WHEApLKZMRZLMxAbNcsPQL
fhcmaQVkfxaV78rrt8TYuLDIU//bOTwGJ48Maj92RT1z5hOOiBkdQe8CgYEAxp5p
Au9kiJFEIgHVtEN+1qHfnwZJI0xOkDfsd+a1J6PZLimHAfiYETAHfJq1cMC4Mt/G
4l/WDqwcWXI/9A/gN7NRv0miQ+tDyVHntohaGoU+0hm6QfXag6VloWs/X8mlzCeu
46AXAni4lbW9nNWwImEL1uSC/Oo5vB45OpHR/VsCgYAivfyTPZV58olF43dw54ey
9BOwd6iApM+Zx5xMKymm31xKaNfTrcIty6LwstWTrto7gzEd4lrFCwclO4iTrXYr
qHczMVZPFTUgq96H4Go/KZSxJeeW4fzlkxQ0O+tHsvFQ5PIa9GMJRqFpyshpzjFS
DlHwc6tY4YPfXnl4rCxV9QKBgAsrwbA+kqLzuKdI/yICYdHkjNU+30Iy+oA2BQDB
YxL1rjNgdo1v0+2zi9hAQ1AyJqoF2APHbByrJXUKbfpmIjA/z6s4kv3K76cVCjlD
9f1j3SKn+8fV8hJRbSPlCk1y4/ZVjQqUaHblH0ycSivWAPAOEUJm288pxVGFSaa3
qN3dAoGBAIGSn1PSjIVqypCQBBydedS4WDjqwkLoL0bOOZRLxgk+dtfD2l8wKqWp
Helyqym23d58QPb0ZwMU3g/0pZXDqX+w+bnUvAvjfADmFNe6T1nWYiu9Mn5YHAyO
G5s2aHfB8aSIqQSRASlWgFEmftfpuapRGAmOyZr2JYZuaELkvPmP
-----END RSA PRIVATE KEY-----

View File

@ -21,5 +21,7 @@ for SERVICE in publisher nonce ra ca sa va rva ; do
minica -domains "${SERVICE}.boulder,${SERVICE}1.boulder,${SERVICE}2.boulder"
done
minica -ip-addresses 10.77.77.77,10.88.88.88
# minica sets restrictive directory permissions, but we don't want that
chmod -R go+rX .

View File

@ -258,6 +258,9 @@ def startChallSrv():
'--defaultIPv4', os.environ.get("FAKE_DNS"),
'-defaultIPv6', '',
'--dns01', ':8053,:8054',
'--doh', '10.77.77.77:8443,10.88.88.88:8443',
'--doh-cert', 'test/grpc-creds/10.77.77.77/cert.pem',
'--doh-cert-key', 'test/grpc-creds/10.77.77.77/key.pem',
'--management', ':8055',
'--http01', '10.77.77.77:80',
'-https01', '10.77.77.77:443',

View File

@ -145,7 +145,8 @@ func TestDNSValidationNoServer(t *testing.T) {
metrics.NoopRegisterer,
clock.New(),
1,
log)
log,
nil)
_, prob := va.validateChallenge(ctx, dnsi("localhost"), dnsChallenge())