Fix mixed DNS and IP SANs in Order

This commit is contained in:
Herman Slatman 2021-06-03 22:45:24 +02:00
parent af615db6b5
commit 76dcf542d4
No known key found for this signature in database
GPG key ID: F4D8A44EA0A75A4F
2 changed files with 44 additions and 23 deletions

View file

@ -33,7 +33,7 @@ func (n *NewOrderRequest) Validate() error {
return acme.NewError(acme.ErrorMalformedType, "identifier type unsupported: %s", id.Type) return acme.NewError(acme.ErrorMalformedType, "identifier type unsupported: %s", id.Type)
} }
if id.Type == "ip" && net.ParseIP(id.Value) == nil { if id.Type == "ip" && net.ParseIP(id.Value) == nil {
return acme.NewError(acme.ErrorMalformedType, "%s is not a valid IP address", id.Value) return acme.NewError(acme.ErrorMalformedType, "invalid IP address: %s", id.Value)
} }
} }
return nil return nil

View file

@ -192,14 +192,17 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ
var sans []x509util.SubjectAlternativeName var sans []x509util.SubjectAlternativeName
// order the DNS names and IP addresses, so that they can be compared against the canonicalized CSR // order the DNS names and IP addresses, so that they can be compared against the canonicalized CSR
orderNames := make([]string, len(o.Identifiers)) orderNames := make([]string, numberOfIdentifierType("dns", o.Identifiers))
orderIPs := make([]net.IP, len(o.Identifiers)) orderIPs := make([]net.IP, numberOfIdentifierType("ip", o.Identifiers))
for i, n := range o.Identifiers { indexDNS, indexIP := 0, 0
for _, n := range o.Identifiers {
switch n.Type { switch n.Type {
case "dns": case "dns":
orderNames[i] = n.Value orderNames[indexDNS] = n.Value
indexDNS++
case "ip": case "ip":
orderIPs[i] = net.ParseIP(n.Value) // NOTE: this assumes are all valid IPs at this time; or will result in nil entries orderIPs[indexIP] = net.ParseIP(n.Value) // NOTE: this assumes are all valid IPs at this time; or will result in nil entries
indexIP++
default: default:
return sans, NewErrorISE("unsupported identifier type in order: %s", n.Type) return sans, NewErrorISE("unsupported identifier type in order: %s", n.Type)
} }
@ -209,6 +212,7 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ
totalNumberOfSANs := len(csr.DNSNames) + len(csr.IPAddresses) totalNumberOfSANs := len(csr.DNSNames) + len(csr.IPAddresses)
sans = make([]x509util.SubjectAlternativeName, totalNumberOfSANs) sans = make([]x509util.SubjectAlternativeName, totalNumberOfSANs)
index := 0
// TODO: limit what IP addresses can be used? Only private? Only certain ranges (i.e. only allow the specific ranges by default, configuration for all?) // TODO: limit what IP addresses can be used? Only private? Only certain ranges (i.e. only allow the specific ranges by default, configuration for all?)
// TODO: can DNS already be limited to a certain domain? That would probably be nice to have too, but maybe not as part of this PR // TODO: can DNS already be limited to a certain domain? That would probably be nice to have too, but maybe not as part of this PR
@ -221,22 +225,6 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ
// Note that with certificate templates we are not going to check for the // Note that with certificate templates we are not going to check for the
// absence of other SANs as they will only be set if the templates allows // absence of other SANs as they will only be set if the templates allows
// them. // them.
if len(csr.IPAddresses) != len(orderIPs) {
return sans, NewError(ErrorBadCSRType, "number of CSR IPs do not match identifiers exactly: "+
"CSR IPs = %v, Order IPs = %v", csr.IPAddresses, orderIPs)
}
for i := range csr.IPAddresses {
if !ipsAreEqual(csr.IPAddresses[i], orderIPs[i]) {
return sans, NewError(ErrorBadCSRType, "CSR IPs do not match identifiers exactly: "+
"CSR IPs = %v, Order IPs = %v", csr.IPAddresses, orderIPs)
}
sans[i] = x509util.SubjectAlternativeName{
Type: x509util.IPType,
Value: csr.IPAddresses[i].String(),
}
}
if len(csr.DNSNames) != len(orderNames) { if len(csr.DNSNames) != len(orderNames) {
return sans, NewError(ErrorBadCSRType, "CSR names do not match identifiers exactly: "+ return sans, NewError(ErrorBadCSRType, "CSR names do not match identifiers exactly: "+
"CSR names = %v, Order names = %v", csr.DNSNames, orderNames) "CSR names = %v, Order names = %v", csr.DNSNames, orderNames)
@ -247,15 +235,48 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ
return sans, NewError(ErrorBadCSRType, "CSR names do not match identifiers exactly: "+ return sans, NewError(ErrorBadCSRType, "CSR names do not match identifiers exactly: "+
"CSR names = %v, Order names = %v", csr.DNSNames, orderNames) "CSR names = %v, Order names = %v", csr.DNSNames, orderNames)
} }
sans[i] = x509util.SubjectAlternativeName{ sans[index] = x509util.SubjectAlternativeName{
Type: x509util.DNSType, Type: x509util.DNSType,
Value: csr.DNSNames[i], Value: csr.DNSNames[i],
} }
index++
}
if len(csr.IPAddresses) != len(orderIPs) {
return sans, NewError(ErrorBadCSRType, "number of CSR IPs do not match identifiers exactly: "+
"CSR IPs = %v, Order IPs = %v", csr.IPAddresses, orderIPs)
}
for i := range csr.IPAddresses {
if !ipsAreEqual(csr.IPAddresses[i], orderIPs[i]) {
return sans, NewError(ErrorBadCSRType, "CSR IPs do not match identifiers exactly: "+
"CSR IPs = %v, Order IPs = %v", csr.IPAddresses, orderIPs)
}
sans[index] = x509util.SubjectAlternativeName{
Type: x509util.IPType,
Value: csr.IPAddresses[i].String(),
}
index++
} }
return sans, nil return sans, nil
} }
// numberOfIdentifierType returns the number of Identifiers that
// are of type typ.
func numberOfIdentifierType(typ string, ids []Identifier) int {
c := 0
for _, id := range ids {
if id.Type == typ {
c++
}
}
return c
}
// canonicalize canonicalizes a CSR so that it can be compared against an Order
// NOTE: this effectively changes the order of SANs in the CSR, which may be OK,
// but may not be expected.
func canonicalize(csr *x509.CertificateRequest) (canonicalized *x509.CertificateRequest) { func canonicalize(csr *x509.CertificateRequest) (canonicalized *x509.CertificateRequest) {
// for clarity only; we're operating on the same object by pointer // for clarity only; we're operating on the same object by pointer