From df066f8f9def8467cfb1ce291ec74d1a01c4ac7d Mon Sep 17 00:00:00 2001 From: Seo Suchan Date: Tue, 13 Oct 2026 16:49:52 +0900 Subject: [PATCH] Update dns-persist-01 impl to newest draft use calculate account hash format, as defined in draft-ietf-acme-dns-persist-02 , instead of using accounturi as is. --- cmd/pebble/main.go | 12 ++++- va/va.go | 79 ++++++++++++++++++++++++++++++-- va/va_test.go | 110 ++++++++++++++++++++++++++++++++------------- wfe/wfe.go | 2 + 4 files changed, 169 insertions(+), 34 deletions(-) diff --git a/cmd/pebble/main.go b/cmd/pebble/main.go index 45ffaa7d..4da318d4 100644 --- a/cmd/pebble/main.go +++ b/cmd/pebble/main.go @@ -32,6 +32,7 @@ type config struct { ExternalAccountBindingRequired bool ExternalAccountMACKeys map[string]string CAAIdentities []string + AccountHashPrefix string // Configure policies to deny certain domains DomainBlocklist []string KeyAlgorithm string @@ -125,9 +126,18 @@ func main() { } } + accountHashPrefix := c.Pebble.AccountHashPrefix + if accountHashPrefix == "" { + logger.Println("No AccountHashPrefix configured, using default [https://pebble.letsencrypt.org/hashed-accountsz/]") + accountHashPrefix = "https://pebble.letsencrypt.org/hashed-accounts/" + } + if !strings.HasSuffix(accountHashPrefix, "/") { + accountHashPrefix = accountHashPrefix + "/" // make it in dir format + } + db := db.NewMemoryStore() ca := ca.New(logger, db, c.Pebble.OCSPResponderURL, keyAlg, alternateRoots, chainLength, profiles) - va := va.New(logger, c.Pebble.HTTPPort, c.Pebble.TLSPort, *strictMode, *resolverAddress, db) + va := va.New(logger, c.Pebble.HTTPPort, c.Pebble.TLSPort, *strictMode, *resolverAddress, db, accountHashPrefix) for keyID, key := range c.Pebble.ExternalAccountMACKeys { err := db.AddExternalAccountKeyByID(keyID, key) diff --git a/va/va.go b/va/va.go index 33c3fb93..4b0ad5dc 100644 --- a/va/va.go +++ b/va/va.go @@ -2,6 +2,7 @@ package va import ( "context" + "crypto" "crypto/sha256" "crypto/subtle" "crypto/tls" @@ -11,6 +12,7 @@ import ( "encoding/base64" "errors" "fmt" + "hash" "io" "log" "math/rand" @@ -111,6 +113,7 @@ type VAImpl struct { strict bool customResolverAddr string dnsClient *dns.Client + AccountHashPrefix string // exported so wfe can publish it in meta // The VA having a DB client is indeed strange. This is only used to // facilitate va.setOrderError changing the ARI related order replacement @@ -123,6 +126,7 @@ func New( httpPort, tlsPort int, strict bool, customResolverAddr string, db *db.MemoryStore, + accountHashPrefix string, ) *VAImpl { va := &VAImpl{ log: log, @@ -134,6 +138,7 @@ func New( strict: strict, customResolverAddr: customResolverAddr, db: db, + AccountHashPrefix: accountHashPrefix, } if customResolverAddr != "" { @@ -702,10 +707,78 @@ func (va VAImpl) validateDNSPersist01(task *vaTask) *core.ValidationRecord { "Error parsing DNS-PERSIST-01 challenge TXT record with issuer-domain-name %q: missing mandatory accountURI parameter", receivedIssuer)) continue } - if params.accountURI != task.AccountURL { + + if params.accountURI == task.AccountURL { + syntaxErrs = append(syntaxErrs, fmt.Sprintf( + "Error parsing DNS-PERSIST-01 challenge TXT record with issuer-domain-name %q: this record uses raw AcccountURI, Please use hashed format", + receivedIssuer)) + continue + } + + if !strings.HasPrefix(params.accountURI, va.AccountHashPrefix) { + syntaxErrs = append(syntaxErrs, fmt.Sprintf( + "Error parsing DNS-PERSIST-01 challenge TXT record with issuer-domain-name %q: accountHashPrefix does not match, expexted %s", + receivedIssuer, va.AccountHashPrefix)) + continue + } + // calculate account hash format, as defined in draft-ietf-acme-dns-persist-02 + temp := strings.Split(strings.TrimPrefix(params.accountURI, va.AccountHashPrefix), "/") + if len(temp) != 2 { + syntaxErrs = append(syntaxErrs, fmt.Sprintf( + "Error parsing DNS-PERSIST-01 challenge TXT record with issuer-domain-name %q: accounthash does not contain hash algorithm.", + receivedIssuer)) + continue + } + + var hashalg hash.Hash + hashalgstring := temp[0] // hash alg: keep mind IANA have names in lowercase + observedhash := temp[1] + + switch hashalgstring { // use a bunch of allowed hash algs + case "sha-256": + hashalg = crypto.SHA256.New() + case "sha-384": + hashalg = crypto.SHA384.New() + case "sha-512": + hashalg = crypto.SHA512.New() + case "sha3-256": + hashalg = crypto.SHA3_256.New() + case "sha3-384": + hashalg = crypto.SHA3_384.New() + case "sha3-512": + hashalg = crypto.SHA3_512.New() + default: + syntaxErrs = append(syntaxErrs, fmt.Sprintf( + "Error parsing DNS-PERSIST-01 challenge TXT record with issuer-domain-name %q: accounthash has unsupported hash algorithm %s.", + receivedIssuer, temp[0])) + continue + } + // building account hash + thumbprint, _ := task.Account.Key.Thumbprint(crypto.SHA256) + key := []byte(base64.RawURLEncoding.EncodeToString(thumbprint)) + accountidentsurfix := append(key, []byte(task.AccountURL)...) + + globalAccHashIn := []byte{0x1, '*'} // global accounthash, see Section 4.1 + globalAccHashIn = append(globalAccHashIn, accountidentsurfix...) + hashalg.Write(globalAccHashIn) + globalAccHashStr := base64.RawURLEncoding.EncodeToString(hashalg.Sum(nil)) + + hashalg.Reset() + perdomainAcchashIn := []byte{byte(len(task.Identifier.Value))} // per domain accounthash value + perdomainAcchashIn = append(perdomainAcchashIn, []byte(task.Identifier.Value)...) + perdomainAcchashIn = append(perdomainAcchashIn, accountidentsurfix...) + hashalg.Write(perdomainAcchashIn) + perdomainAcchashStr := base64.RawURLEncoding.EncodeToString(hashalg.Sum(nil)) + + validAccountURIs := []string{globalAccHashStr, perdomainAcchashStr} + + if !slices.ContainsFunc(validAccountURIs, func(sttr string) bool { + return subtle.ConstantTimeCompare([]byte(sttr), []byte(observedhash)) == 1 + }) { authorizationErrs = append(authorizationErrs, fmt.Sprintf( - "Error parsing DNS-PERSIST-01 challenge TXT record with issuer-domain-name %q: accounturi mismatch: expected %q, got %q", - receivedIssuer, task.AccountURL, params.accountURI)) + "Error parsing DNS-PERSIST-01 challenge TXT record with issuer-domain-name %q: "+ + "accounthash mismatch: expected %s for domain %s, %s for domain-correlation opt-out, got %q", + receivedIssuer, validAccountURIs[0], task.Identifier.Value, validAccountURIs[1], observedhash)) continue } // Per the dns-persist-01 specification, if the policy tag is present diff --git a/va/va_test.go b/va/va_test.go index f9a6cb25..9ee3b5cc 100644 --- a/va/va_test.go +++ b/va/va_test.go @@ -1,6 +1,7 @@ package va import ( + "encoding/json" "log" "net" "os" @@ -8,6 +9,7 @@ import ( "sync" "testing" + "github.com/go-jose/go-jose/v4" "github.com/miekg/dns" "github.com/letsencrypt/pebble/v2/acme" @@ -35,7 +37,7 @@ func TestAuthzRace(_ *testing.T) { // This whole test can be removed if/when the MemoryStore becomes 100% by value ms := db.NewMemoryStore() - va := New(log.New(os.Stdout, "Pebble/TestRace", log.LstdFlags), 14000, 15000, false, "", ms) + va := New(log.New(os.Stdout, "Pebble/TestRace", log.LstdFlags), 14000, 15000, false, "", ms, "https://ca.example/account-hash/") authz := &core.Authorization{ ID: "auth-id", @@ -60,9 +62,11 @@ func TestValidateDNSPersist01(t *testing.T) { t.Parallel() const ( - domain = "example.com" - txtName = "_validation-persist.example.com" - accountURL = "https://ca.example/acct/123" + domain = "example.com" + txtName = "_validation-persist.example.com" + accountURL = "https://ca.example/acct/123" + hashalg = "sha-256" + accountHashPrefix = "https://ca.example/account-hash/" ) testCases := []struct { @@ -75,12 +79,33 @@ func TestValidateDNSPersist01(t *testing.T) { expectDetailSubstr string }{ // Success test cases: + { + name: "using per domain hash succeeds", + challIssuerNames: []string{"authority.example"}, + challTXTRecords: []string{ + "authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw", + }, + }, + { + name: "opt out of the domain-correlation mitigation, set domain as '*', should succeed", + challIssuerNames: []string{"authority.example"}, + challTXTRecords: []string{ + "authority.example;accounturi=https://ca.example/account-hash/sha-256/NpDnSwUthQK8zCgFdefYxAdAVPnygMLbs9US6oO-5ug", + }, + }, + { + name: "using sha3-256 for account hash, but key still need to be sha-256", + challIssuerNames: []string{"authority.example"}, + challTXTRecords: []string{ + "authority.example;accounturi=https://ca.example/account-hash/sha3-256/sDsI2tmNNk0xwo0LLJbtVc0U4FIgVkPHAflH9BWn7Sw", + }, + }, { name: "matching malformed and matching valid record succeeds", challIssuerNames: []string{"authority.example"}, challTXTRecords: []string{ - "authority.example;accounturi=https://ca.example/acct/123;accounturi=https://ca.example/acct/456", - "authority.example;accounturi=https://ca.example/acct/123", + "authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;accounturi=https://ca.example/acct/456", + "authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw", }, }, { @@ -88,47 +113,47 @@ func TestValidateDNSPersist01(t *testing.T) { challIssuerNames: []string{"authority.example"}, challTXTRecords: []string{ "authority.example;accounturi=https://ca.example/acct/999", - "authority.example;accounturi=https://ca.example/acct/123", + "authority.example;accounturi=https://ca.example/account-hash/sha-256/NpDnSwUthQK8zCgFdefYxAdAVPnygMLbs9US6oO-5ug", }, }, { name: "unknown tag with empty value succeeds", challIssuerNames: []string{"authority.example"}, challTXTRecords: []string{ - "authority.example;accounturi=https://ca.example/acct/123;foo=", + "authority.example;accounturi=https://ca.example/account-hash/sha-256/NpDnSwUthQK8zCgFdefYxAdAVPnygMLbs9US6oO-5ug;foo=", }, }, { name: "unknown tags are ignored", challIssuerNames: []string{"authority.example"}, challTXTRecords: []string{ - "authority.example;accounturi=https://ca.example/acct/123;bad tag=value;\nweird=\\x01337", + "authority.example;accounturi=https://ca.example/account-hash/sha-256/NpDnSwUthQK8zCgFdefYxAdAVPnygMLbs9US6oO-5ug;bad tag=value;\nweird=\\x01337", }, }, { name: "all known fields with heavy whitespace succeeds", challIssuerNames: []string{"authority.example"}, challTXTRecords: []string{ - " authority.example ; accounturi = https://ca.example/acct/123 ; policy = wildcard ; persistUntil = 4102444800 ", + " authority.example ; accounturi = https://ca.example/account-hash/sha-256/NpDnSwUthQK8zCgFdefYxAdAVPnygMLbs9US6oO-5ug ; policy = wildcard ; persistUntil = 4102444800 ", }, }, { name: "wildcard accepts case-insensitive policy value", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;policy=wIlDcArD"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;policy=wIlDcArD"}, challWildcard: true, }, { name: "wildcard accepts case-insensitive policy tag", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;pOlIcY=wildcard"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;pOlIcY=wildcard"}, challWildcard: true, }, // Failure test cases: { name: "only matching malformed record returns malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;accounturi=https://ca.example/acct/456"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;accounturi=https://ca.example/acct/456"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `duplicate parameter`, @@ -144,15 +169,23 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "only matching unauthorized record returns unauthorized", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/999"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/0000000000000000000000000000000000000000000"}, expectErr: true, expectHTTPStatus: 403, - expectDetailSubstr: `accounturi mismatch`, + expectDetailSubstr: `accounthash mismatch`, + }, + { + name: "using unsupported hash algorithm is malformed", + challIssuerNames: []string{"authority.example"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/someotherhash/0000000000000000"}, + expectErr: true, + expectHTTPStatus: 400, + expectDetailSubstr: `unsupported hash`, }, { name: "non-matching malformed record is ignored", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"other.example;accounturi=https://ca.example/acct/123;accounturi=https://ca.example/acct/456"}, + challTXTRecords: []string{"other.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;accounturi=https://ca.example/acct/456"}, expectErr: true, expectHTTPStatus: 403, expectDetailSubstr: `No valid TXT record found`, @@ -160,7 +193,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "non-matching issuer-domain-name record is ignored", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"other.example;accounturi=https://ca.example/acct/123"}, + challTXTRecords: []string{"other.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw"}, expectErr: true, expectHTTPStatus: 403, expectDetailSubstr: `No valid TXT record found`, @@ -168,7 +201,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "missing equals is malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;invalidparam"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;invalidparam"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `malformed parameter "invalidparam" should be tag=value pair`, @@ -176,7 +209,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "empty tag is malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;=abc"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;=abc"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `malformed parameter "=abc", empty tag`, @@ -192,7 +225,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "invalid value character is malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;policy=wild card"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;policy=wild card"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `malformed value "wild card" for tag "policy"`, @@ -200,7 +233,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "persistUntil non unix timestamp is malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;persistUntil=not-a-unix-timestamp"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;persistUntil=not-a-unix-timestamp"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `malformed persistUntil timestamp "not-a-unix-timestamp"`, @@ -208,7 +241,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "duplicate unknown parameter is malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;foo=bar;foo=baz"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;foo=bar;foo=baz"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `duplicate parameter "foo"`, @@ -216,7 +249,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "duplicate parameter is case-insensitive", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;ACCOUNTURI=https://ca.example/acct/123;accounturi=https://ca.example/acct/456"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;accounturi=https://ca.example/acct/456"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `duplicate parameter "accounturi"`, @@ -224,7 +257,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "missing issuer-domain-name record is ignored", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{";accounturi=https://ca.example/acct/123"}, + challTXTRecords: []string{";accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw"}, expectErr: true, expectHTTPStatus: 403, expectDetailSubstr: `No valid TXT record found`, @@ -232,7 +265,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "wildcard policy mismatch returns unauthorized", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;policy=notwildcard"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;policy=notwildcard"}, challWildcard: true, expectErr: true, expectHTTPStatus: 403, @@ -249,7 +282,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "empty persistUntil returns malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;persistUntil="}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;persistUntil="}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `malformed persistUntil timestamp`, @@ -257,7 +290,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "trailing semicolon in matching record returns malformed", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;"}, expectErr: true, expectHTTPStatus: 400, expectDetailSubstr: `empty parameter or trailing semicolon provided`, @@ -265,7 +298,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "expired persistUntil returns unauthorized", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;persistUntil=1"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;persistUntil=1"}, expectErr: true, expectHTTPStatus: 403, expectDetailSubstr: `validation time`, @@ -273,7 +306,7 @@ func TestValidateDNSPersist01(t *testing.T) { { name: "negative persistUntil returns unauthorized", challIssuerNames: []string{"authority.example"}, - challTXTRecords: []string{"authority.example;accounturi=https://ca.example/acct/123;persistUntil=-1"}, + challTXTRecords: []string{"authority.example;accounturi=https://ca.example/account-hash/sha-256/5SQm7n6tPh2-PlLbCKGnViTXX5z19SCN4cPGQHSk-kw;persistUntil=-1"}, expectErr: true, expectHTTPStatus: 403, expectDetailSubstr: `validation time`, @@ -291,9 +324,18 @@ func TestValidateDNSPersist01(t *testing.T) { va := VAImpl{ customResolverAddr: addr, + AccountHashPrefix: accountHashPrefix, dnsClient: new(dns.Client), } + jwkJSON := `{ + "kty": "RSA", + "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "e": "AQAB", + "alg": "RS256", + "kid": "2011-04-29" + }` // example jwk to get thumbprint + task := &vaTask{ Identifier: acme.Identifier{ Type: acme.IdentifierDNS, @@ -306,7 +348,15 @@ func TestValidateDNSPersist01(t *testing.T) { }, }, AccountURL: accountURL, - Wildcard: tc.challWildcard, + Account: &core.Account{ + Key: &jose.JSONWebKey{}, + }, + Wildcard: tc.challWildcard, + } + + err := json.Unmarshal([]byte(jwkJSON), task.Account.Key) + if err != nil { + log.Fatalf("failed to fill jwk %v", err) } result := va.validateDNSPersist01(task) diff --git a/wfe/wfe.go b/wfe/wfe.go index f4ebbe8c..83e7a03d 100644 --- a/wfe/wfe.go +++ b/wfe/wfe.go @@ -618,6 +618,8 @@ func (wfe *WebFrontEndImpl) relativeDirectory(request *http.Request, directory m "externalAccountRequired": wfe.requireEAB, "profiles": wfe.ca.GetProfiles(), "caaIdentities": wfe.caaIdentities, + "issuerDomainNames": wfe.caaIdentities, // should be same as caaIdentites for public CA. + "accountHashPrefix": wfe.va.AccountHashPrefix, // read from VA to fill this } directoryJSON, err := marshalIndent(relativeDir)