Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Identifiers to Authorization & Order structs #7961

Open
wants to merge 32 commits into
base: main
Choose a base branch
from

Conversation

jprenken
Copy link
Contributor

@jprenken jprenken commented Jan 21, 2025

Add identifier fields, which will soon replace the dnsName fields, to:

  • corepb.Authorization
  • corepb.Order
  • rapb.NewOrderRequest
  • sapb.CountFQDNSetsRequest
  • sapb.CountInvalidAuthorizationsRequest
  • sapb.FQDNSetExistsRequest
  • sapb.GetAuthorizationsRequest
  • sapb.GetOrderForNamesRequest
  • sapb.GetValidAuthorizationsRequest
  • sapb.NewOrderRequest

Populate these identifier fields in every function that creates instances of these structs.

Use these identifier fields instead of dnsName fields (at least preferentially) in every function that uses these structs. When crossing component boundaries, don't assume they'll be present, for deployability's sake.

Deployability note: Mismatched cert-checker and sa versions will be incompatible because of a type change in the arguments to sa.SelectAuthzsMatchingIssuance.

Part of #7311

Add `identifier` fields, which will soon replace the `dnsName` fields, to:
- `corepb.Authorization`
- `corepb.Order`
- `rapb.NewOrderRequest`
- `sapb.CountFQDNSetsRequest`
- `sapb.CountInvalidAuthorizationsRequest`
- `sapb.FQDNSetExistsRequest`
- `sapb.GetAuthorizationsRequest`
- `sapb.GetOrderForNamesRequest`
- `sapb.GetValidAuthorizationsRequest`
- `sapb.NewOrderRequest`

Populate these `identifier` fields in every function that creates instances of these structs.

Preferentially use these `identifier` fields in every function that uses these structs - but when crossing component boundaries, don't assume they'll be present, for deployability's sake.

Part of #7311
@jprenken jprenken marked this pull request as ready for review January 26, 2025 01:39
@jprenken jprenken requested a review from a team as a code owner January 26, 2025 01:39
@jprenken jprenken requested a review from aarongable January 27, 2025 18:11
Copy link
Contributor

@aarongable aarongable left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed everything except for ra_test.go and wfe.go, but thought it best to send these comments ASAP. I think I will have further thoughts on the exact names and APIs you've created inside identifier.go, but what you have there is certainly good enough to be getting on with for now.

string dnsName = 2;
string status = 4;
google.protobuf.Timestamp expires = 9;
repeated core.Challenge challenges = 6;
core.Identifier identifier = 10;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly I don't think this needs the core. prefix, because we're in core right here. See for example the use of unqualified ProblemDetails on line 123. I'm not sure why we used core.Challenge on the line above this...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: here and throughout, please put the new identifier(s) field immediately adjacent to the existing dnsName(s) field. This is because the fields (especially in sections prefixed with // Fields specified by RFC 8555) are listed in the same order as the fields are in the RFC.

Comment on lines +343 to +344
// TODO(#7311): Process IP address identifiers appropriately, and
// consistently with how we stringify IPs elsewhere.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this TODO is unnecessary: the .Value field of an ACMEIdentifier is already a string, so no stringification should need to happen inside this function.

@@ -340,30 +340,45 @@ func TestRetryBackoff(t *testing.T) {

}

func TestHashNames(t *testing.T) {
func TestHashIdentifiers(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test case for all identfier.NewIP(), and one or more test cases for a mixes of IP and DNS identifiers in various orders. Might be a good time to turn this into a table-based test, too.

@@ -310,16 +311,16 @@ func (c *certChecker) checkValidations(ctx context.Context, cert core.Certificat

// We may get multiple authorizations for the same name, but that's okay.
// Any authorization for a given name is sufficient.
nameToAuthz := make(map[string]*corepb.Authorization)
identToAuthz := make(map[string]*corepb.Authorization)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identifiers are comparable: they only have two fields, both of which are concrete strings. You should be able to use them directly as map keys, rather than collapsing them into just their values.

@@ -40,7 +41,7 @@ func TestValidAuthzExpires(t *testing.T) {

// The authz should be valid and for the correct identifier
test.AssertEquals(t, authzOb.Status, "valid")
test.AssertEquals(t, authzOb.Identifier.Value, domains[0])
test.AssertEquals(t, authzOb.Identifier.Value, idents[0].Value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check that the identifier type has round-tripped correctly.

@@ -89,7 +91,7 @@ func delHTTP01Response(token string) error {
return nil
}

func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, domains []string, cn bool, certToReplace *x509.Certificate) (*client, *acme.Order, error) {
func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, idents []identifier.ACMEIdentifier, cn bool, certToReplace *x509.Certificate) (*client, *acme.Order, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be acme.Identifiers, not identifier.ACMEIdentifier, since this is client-side code not server-side code. Same with the other functions you've touched in this file.

Comment on lines +202 to +206
// TODO(#7311): Extend this to support IP address identifiers.
names := make([]string, len(idents))
for i, ident := range idents {
names[i] = ident.Value
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can do this right now:

Suggested change
// TODO(#7311): Extend this to support IP address identifiers.
names := make([]string, len(idents))
for i, ident := range idents {
names[i] = ident.Value
}
names := make([]string, 0)
ips := make([]net.IP, 0)
for _, ident := range idents {
switch ident.Type:
case "dns":
names = append(names, ident.Value)
case "ip":
ips = append(ips, ident.Value)
default:
return nil, fmt.Errorf("unrecognized identifier type %q", ident.Type)
}

Comment on lines +53 to +54
for key, ident := range idents {
pbIdents[key] = ident.AsProto()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not quite idiomatic to refer to array indices as "keys", so:

Suggested change
for key, ident := range idents {
pbIdents[key] = ident.AsProto()
for i, ident := range idents {
pbIdents[i] = ident.AsProto()

@@ -48,6 +75,16 @@ func NewDNS(domain string) ACMEIdentifier {
}
}

// SliceNewDNS is a convenience function for creating a slice of ACMEIdentifiers
// with Type "dns" for a given slice of domain names.
func SliceNewDNS(domains []string) []ACMEIdentifier {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you make this

Suggested change
func SliceNewDNS(domains []string) []ACMEIdentifier {
func SliceNewDNS(domains ...string) []ACMEIdentifier {

then everywhere you call it, you can just pass it a bunch of individual strings like identifier.SliceNewDNS("hello", "world") instead of having to package them into a slice like identifier.SliceNewDNS([]string{"hello", "world"}).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From our convo: actually I think this can be almost entirely replaced by the combination of

  • SliceFromProto(idents []ACMEIdentifier, dnsNames []string), for when extracting from the two fields of a proto message;
  • SliceFromCert(x509.Certificate); and
  • csr.IdentsFromCSR(x509.CertificateRequest), upgraded from csr.NamesFromCSR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants