Skip to content

Commit 4d18cc8

Browse files
committed
identifier: Add identifiers package; rename NewDNS & NewIP
Add a new `identifiers` package for functions that handle slices of `ACMEIdentifier`. We plan to add several such functions (e.g. in #7961). Without this change, they'd need a clumsy prefix/suffix to differentiate them from their sibling functions that handle single idents. The current `NewDNS` / `FromDNSNames` are the first example of this. Rename `NewDNS` and `NewIP` to use a more standardized `From` prefix, since they're doing conversions. Move and rename `FromDNSNames`, standardizing `identifier.FromDNS` as the singular and `identifiers.FromDNS` as the plural (i.e. slice). Add a named type `ACMEIdentifiers` so that we can add methods to slices. We will have a lot of slice handling code coming up, which this will make more elegant and readable. Part of #7311
1 parent d045b38 commit 4d18cc8

27 files changed

+239
-222
lines changed

cmd/cert-checker/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ func (c *certChecker) checkCert(ctx context.Context, cert core.Certificate) ([]s
412412
//
413413
// TODO(#7311): We'll need to iterate over IP address identifiers too.
414414
for _, name := range parsedCert.DNSNames {
415-
err = c.pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS(name)})
415+
err = c.pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS(name)})
416416
if err != nil {
417417
problems = append(problems, fmt.Sprintf("Policy Authority isn't willing to issue for '%s': %s", name, err))
418418
} else {

cmd/reversed-hostname-checker/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func main() {
5151
var errors bool
5252
for scanner.Scan() {
5353
n := sa.ReverseName(scanner.Text())
54-
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS(n)})
54+
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS(n)})
5555
if err != nil {
5656
errors = true
5757
fmt.Printf("%s: %s\n", n, err)

csr/csr.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/letsencrypt/boulder/core"
1111
berrors "github.com/letsencrypt/boulder/errors"
1212
"github.com/letsencrypt/boulder/goodkey"
13-
"github.com/letsencrypt/boulder/identifier"
13+
"github.com/letsencrypt/boulder/identifiers"
1414
)
1515

1616
// maxCNLength is the maximum length allowed for the common name as specified in RFC 5280
@@ -82,7 +82,7 @@ func VerifyCSR(ctx context.Context, csr *x509.CertificateRequest, maxNames int,
8282
return berrors.BadCSRError("CSR contains more than %d DNS names", maxNames)
8383
}
8484

85-
err = pa.WillingToIssue(identifier.FromDNSNames(names.SANs))
85+
err = pa.WillingToIssue(identifiers.FromDNS(names.SANs))
8686
if err != nil {
8787
return err
8888
}

errors/errors_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ func TestWithSubErrors(t *testing.T) {
1717

1818
subErrs := []SubBoulderError{
1919
{
20-
Identifier: identifier.NewDNS("example.com"),
20+
Identifier: identifier.FromDNS("example.com"),
2121
BoulderError: &BoulderError{
2222
Type: RateLimit,
2323
Detail: "everyone uses this example domain",
2424
},
2525
},
2626
{
27-
Identifier: identifier.NewDNS("what about example.com"),
27+
Identifier: identifier.FromDNS("what about example.com"),
2828
BoulderError: &BoulderError{
2929
Type: RateLimit,
3030
Detail: "try a real identifier value next time",
@@ -39,7 +39,7 @@ func TestWithSubErrors(t *testing.T) {
3939
test.AssertDeepEquals(t, outResult.SubErrors, subErrs)
4040
// Adding another suberr shouldn't squash the original sub errors
4141
anotherSubErr := SubBoulderError{
42-
Identifier: identifier.NewDNS("another ident"),
42+
Identifier: identifier.FromDNS("another ident"),
4343
BoulderError: &BoulderError{
4444
Type: RateLimit,
4545
Detail: "another rate limit err",

grpc/errors_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func TestSubErrorWrapping(t *testing.T) {
9797

9898
subErrors := []berrors.SubBoulderError{
9999
{
100-
Identifier: identifier.NewDNS("chillserver.com"),
100+
Identifier: identifier.FromDNS("chillserver.com"),
101101
BoulderError: &berrors.BoulderError{
102102
Type: berrors.RejectedIdentifier,
103103
Detail: "2 ill 2 chill",

grpc/pb-marshalling.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ func PBToAuthz(pb *corepb.Authorization) (core.Authorization, error) {
315315
}
316316
authz := core.Authorization{
317317
ID: pb.Id,
318-
Identifier: identifier.NewDNS(pb.DnsName),
318+
Identifier: identifier.FromDNS(pb.DnsName),
319319
RegistrationID: pb.RegistrationID,
320320
Status: core.AcmeStatus(pb.Status),
321321
Expires: expires,

grpc/pb-marshalling_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ func TestRegistration(t *testing.T) {
227227

228228
func TestAuthz(t *testing.T) {
229229
exp := time.Now().AddDate(0, 0, 1).UTC()
230-
ident := identifier.NewDNS("example.com")
230+
ident := identifier.FromDNS("example.com")
231231
challA := core.Challenge{
232232
Type: core.ChallengeTypeDNS01,
233233
Status: core.StatusPending,

identifier/identifier.go

+8-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// The identifier package defines types for RFC 8555 ACME identifiers.
2-
// It exists as a separate package to prevent an import loop between the core
3-
// and probs packages.
1+
// The identifier package defines types and functions for handling singular RFC
2+
// 8555 ACME identifiers. It exists as a separate package to prevent an import
3+
// loop between the core and probs packages.
44
package identifier
55

66
import (
@@ -50,33 +50,23 @@ func FromProto(ident *corepb.Identifier) ACMEIdentifier {
5050
// RPCs. TODO(#8023)
5151
func FromProtoWithDefault(ident *corepb.Identifier, name string) ACMEIdentifier {
5252
if ident == nil {
53-
return NewDNS(name)
53+
return FromDNS(name)
5454
}
5555
return FromProto(ident)
5656
}
5757

58-
// NewDNS is a convenience function for creating an ACMEIdentifier with Type
58+
// FromDNS is a convenience function for creating an ACMEIdentifier with Type
5959
// "dns" for a given domain name.
60-
func NewDNS(domain string) ACMEIdentifier {
60+
func FromDNS(domain string) ACMEIdentifier {
6161
return ACMEIdentifier{
6262
Type: TypeDNS,
6363
Value: domain,
6464
}
6565
}
6666

67-
// FromDNSNames is a convenience function for creating a slice of ACMEIdentifier
68-
// with Type "dns" for a given slice of domain names.
69-
func FromDNSNames(input []string) []ACMEIdentifier {
70-
var out []ACMEIdentifier
71-
for _, in := range input {
72-
out = append(out, NewDNS(in))
73-
}
74-
return out
75-
}
76-
77-
// NewIP is a convenience function for creating an ACMEIdentifier with Type "ip"
67+
// FromIP is a convenience function for creating an ACMEIdentifier with Type "ip"
7868
// for a given IP address.
79-
func NewIP(ip netip.Addr) ACMEIdentifier {
69+
func FromIP(ip netip.Addr) ACMEIdentifier {
8070
return ACMEIdentifier{
8171
Type: TypeIP,
8272
// RFC 8738, Sec. 3: The identifier value MUST contain the textual form

identifiers/identifiers.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// The identifier package defines types and functions for handling plural RFC
2+
// 8555 ACME identifiers. It exists as a separate package to prevent an import
3+
// loop between the core and probs packages, and to improve code readability so
4+
// that it's clear when you're calling a function to handle/return a slice of
5+
// identifiers, as opposed to a single identifier.
6+
package identifiers
7+
8+
import (
9+
// corepb "github.com/letsencrypt/boulder/core/proto"
10+
"github.com/letsencrypt/boulder/identifier"
11+
)
12+
13+
// ACMEIdentifiers is a named type for a slice of ACME identifiers, so that
14+
// methods can be applied to these slices.
15+
type ACMEIdentifiers []identifier.ACMEIdentifier
16+
17+
// FromDNS is a convenience function for creating a slice of ACMEIdentifier with
18+
// Type "dns" for a given slice of domain names.
19+
func FromDNS(input []string) ACMEIdentifiers {
20+
var out ACMEIdentifiers
21+
for _, in := range input {
22+
out = append(out, identifier.FromDNS(in))
23+
}
24+
return out
25+
}

mocks/sa.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ func (sa *StorageAuthorityReadOnly) GetValidAuthorizations2(ctx context.Context,
450450
Status: core.StatusValid,
451451
RegistrationID: req.RegistrationID,
452452
Expires: &exp,
453-
Identifier: identifier.NewDNS(name),
453+
Identifier: identifier.FromDNS(name),
454454
Challenges: []core.Challenge{
455455
{
456456
Status: core.StatusValid,

policy/pa_test.go

+31-31
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func TestWellFormedIdentifiers(t *testing.T) {
110110

111111
// Test syntax errors
112112
for _, tc := range testCases {
113-
err := WellFormedIdentifiers([]identifier.ACMEIdentifier{identifier.NewDNS(tc.domain)})
113+
err := WellFormedIdentifiers([]identifier.ACMEIdentifier{identifier.FromDNS(tc.domain)})
114114
if tc.err == nil {
115115
test.AssertNil(t, err, fmt.Sprintf("Unexpected error for domain %q, got %s", tc.domain, err))
116116
} else {
@@ -121,7 +121,7 @@ func TestWellFormedIdentifiers(t *testing.T) {
121121
}
122122
}
123123

124-
err := WellFormedIdentifiers([]identifier.ACMEIdentifier{identifier.NewIP(netip.MustParseAddr("9.9.9.9"))})
124+
err := WellFormedIdentifiers([]identifier.ACMEIdentifier{identifier.FromIP(netip.MustParseAddr("9.9.9.9"))})
125125
test.AssertError(t, err, "Expected error for IP, but got none")
126126
var berr *berrors.BoulderError
127127
test.AssertErrorWraps(t, err, &berr)
@@ -183,22 +183,22 @@ func TestWillingToIssue(t *testing.T) {
183183
test.AssertNotError(t, err, "Couldn't load rules")
184184

185185
// Invalid encoding
186-
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS("www.xn--m.com")})
186+
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS("www.xn--m.com")})
187187
test.AssertError(t, err, "WillingToIssue didn't fail on a malformed IDN")
188188
// Invalid identifier type
189-
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewIP(netip.MustParseAddr("1.1.1.1"))})
189+
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromIP(netip.MustParseAddr("1.1.1.1"))})
190190
test.AssertError(t, err, "WillingToIssue didn't fail on an IP address")
191191
// Valid encoding
192-
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS("www.xn--mnich-kva.com")})
192+
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS("www.xn--mnich-kva.com")})
193193
test.AssertNotError(t, err, "WillingToIssue failed on a properly formed IDN")
194194
// IDN TLD
195-
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS("xn--example--3bhk5a.xn--p1ai")})
195+
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS("xn--example--3bhk5a.xn--p1ai")})
196196
test.AssertNotError(t, err, "WillingToIssue failed on a properly formed domain with IDN TLD")
197197
features.Reset()
198198

199199
// Test expected blocked domains
200200
for _, domain := range shouldBeBlocked {
201-
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS(domain)})
201+
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS(domain)})
202202
test.AssertError(t, err, "domain was not correctly forbidden")
203203
var berr *berrors.BoulderError
204204
test.AssertErrorWraps(t, err, &berr)
@@ -207,7 +207,7 @@ func TestWillingToIssue(t *testing.T) {
207207

208208
// Test acceptance of good names
209209
for _, domain := range shouldBeAccepted {
210-
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS(domain)})
210+
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS(domain)})
211211
test.AssertNotError(t, err, "domain was incorrectly forbidden")
212212
}
213213
}
@@ -293,7 +293,7 @@ func TestWillingToIssue_Wildcards(t *testing.T) {
293293

294294
for _, tc := range testCases {
295295
t.Run(tc.Name, func(t *testing.T) {
296-
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS(tc.Domain)})
296+
err := pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS(tc.Domain)})
297297
if tc.ExpectedErr == nil {
298298
test.AssertNil(t, err, fmt.Sprintf("Unexpected error for domain %q, got %s", tc.Domain, err))
299299
} else {
@@ -329,11 +329,11 @@ func TestWillingToIssue_SubErrors(t *testing.T) {
329329

330330
// Test multiple malformed domains and one banned domain; only the malformed ones will generate errors
331331
err = pa.WillingToIssue([]identifier.ACMEIdentifier{
332-
identifier.NewDNS("perfectly-fine.com"), // fine
333-
identifier.NewDNS("letsdecrypt_org"), // malformed
334-
identifier.NewDNS("example.comm"), // malformed
335-
identifier.NewDNS("letsdecrypt.org"), // banned
336-
identifier.NewDNS("also-perfectly-fine.com"), // fine
332+
identifier.FromDNS("perfectly-fine.com"), // fine
333+
identifier.FromDNS("letsdecrypt_org"), // malformed
334+
identifier.FromDNS("example.comm"), // malformed
335+
identifier.FromDNS("letsdecrypt.org"), // banned
336+
identifier.FromDNS("also-perfectly-fine.com"), // fine
337337
})
338338
test.AssertDeepEquals(t, err,
339339
&berrors.BoulderError{
@@ -345,24 +345,24 @@ func TestWillingToIssue_SubErrors(t *testing.T) {
345345
Type: berrors.Malformed,
346346
Detail: "Domain name contains an invalid character",
347347
},
348-
Identifier: identifier.NewDNS("letsdecrypt_org"),
348+
Identifier: identifier.FromDNS("letsdecrypt_org"),
349349
},
350350
{
351351
BoulderError: &berrors.BoulderError{
352352
Type: berrors.Malformed,
353353
Detail: "Domain name does not end with a valid public suffix (TLD)",
354354
},
355-
Identifier: identifier.NewDNS("example.comm"),
355+
Identifier: identifier.FromDNS("example.comm"),
356356
},
357357
},
358358
})
359359

360360
// Test multiple banned domains.
361361
err = pa.WillingToIssue([]identifier.ACMEIdentifier{
362-
identifier.NewDNS("perfectly-fine.com"), // fine
363-
identifier.NewDNS("letsdecrypt.org"), // banned
364-
identifier.NewDNS("example.com"), // banned
365-
identifier.NewDNS("also-perfectly-fine.com"), // fine
362+
identifier.FromDNS("perfectly-fine.com"), // fine
363+
identifier.FromDNS("letsdecrypt.org"), // banned
364+
identifier.FromDNS("example.com"), // banned
365+
identifier.FromDNS("also-perfectly-fine.com"), // fine
366366
})
367367
test.AssertError(t, err, "Expected err from WillingToIssueWildcards")
368368

@@ -376,20 +376,20 @@ func TestWillingToIssue_SubErrors(t *testing.T) {
376376
Type: berrors.RejectedIdentifier,
377377
Detail: "The ACME server refuses to issue a certificate for this domain name, because it is forbidden by policy",
378378
},
379-
Identifier: identifier.NewDNS("letsdecrypt.org"),
379+
Identifier: identifier.FromDNS("letsdecrypt.org"),
380380
},
381381
{
382382
BoulderError: &berrors.BoulderError{
383383
Type: berrors.RejectedIdentifier,
384384
Detail: "The ACME server refuses to issue a certificate for this domain name, because it is forbidden by policy",
385385
},
386-
Identifier: identifier.NewDNS("example.com"),
386+
Identifier: identifier.FromDNS("example.com"),
387387
},
388388
},
389389
})
390390

391391
// Test willing to issue with only *one* bad identifier.
392-
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.NewDNS("letsdecrypt.org")})
392+
err = pa.WillingToIssue([]identifier.ACMEIdentifier{identifier.FromDNS("letsdecrypt.org")})
393393
test.AssertDeepEquals(t, err,
394394
&berrors.BoulderError{
395395
Type: berrors.RejectedIdentifier,
@@ -409,21 +409,21 @@ func TestChallengeTypesFor(t *testing.T) {
409409
}{
410410
{
411411
name: "dns",
412-
ident: identifier.NewDNS("example.com"),
412+
ident: identifier.FromDNS("example.com"),
413413
wantChalls: []core.AcmeChallenge{
414414
core.ChallengeTypeHTTP01, core.ChallengeTypeDNS01, core.ChallengeTypeTLSALPN01,
415415
},
416416
},
417417
{
418418
name: "wildcard",
419-
ident: identifier.NewDNS("*.example.com"),
419+
ident: identifier.FromDNS("*.example.com"),
420420
wantChalls: []core.AcmeChallenge{
421421
core.ChallengeTypeDNS01,
422422
},
423423
},
424424
{
425425
name: "other",
426-
ident: identifier.NewIP(netip.MustParseAddr("1.2.3.4")),
426+
ident: identifier.FromIP(netip.MustParseAddr("1.2.3.4")),
427427
wantErr: "unrecognized identifier type",
428428
},
429429
}
@@ -514,23 +514,23 @@ func TestCheckAuthzChallenges(t *testing.T) {
514514
{
515515
name: "no challenges",
516516
authz: core.Authorization{
517-
Identifier: identifier.NewDNS("example.com"),
517+
Identifier: identifier.FromDNS("example.com"),
518518
Challenges: []core.Challenge{},
519519
},
520520
wantErr: "has no challenges",
521521
},
522522
{
523523
name: "no valid challenges",
524524
authz: core.Authorization{
525-
Identifier: identifier.NewDNS("example.com"),
525+
Identifier: identifier.FromDNS("example.com"),
526526
Challenges: []core.Challenge{{Type: core.ChallengeTypeDNS01, Status: core.StatusPending}},
527527
},
528528
wantErr: "not solved by any challenge",
529529
},
530530
{
531531
name: "solved by disabled challenge",
532532
authz: core.Authorization{
533-
Identifier: identifier.NewDNS("example.com"),
533+
Identifier: identifier.FromDNS("example.com"),
534534
Challenges: []core.Challenge{{Type: core.ChallengeTypeDNS01, Status: core.StatusValid}},
535535
},
536536
enabled: map[core.AcmeChallenge]bool{core.ChallengeTypeHTTP01: true},
@@ -539,15 +539,15 @@ func TestCheckAuthzChallenges(t *testing.T) {
539539
{
540540
name: "solved by wrong kind of challenge",
541541
authz: core.Authorization{
542-
Identifier: identifier.NewDNS("*.example.com"),
542+
Identifier: identifier.FromDNS("*.example.com"),
543543
Challenges: []core.Challenge{{Type: core.ChallengeTypeHTTP01, Status: core.StatusValid}},
544544
},
545545
wantErr: "inapplicable challenge type",
546546
},
547547
{
548548
name: "valid authz",
549549
authz: core.Authorization{
550-
Identifier: identifier.NewDNS("example.com"),
550+
Identifier: identifier.FromDNS("example.com"),
551551
Challenges: []core.Challenge{{Type: core.ChallengeTypeTLSALPN01, Status: core.StatusValid}},
552552
},
553553
},

0 commit comments

Comments
 (0)