Add preliminary support for TLS-ALPN-01 challenge for IP identifiers

This commit is contained in:
Herman Slatman 2021-05-29 00:19:14 +02:00
parent 848b5202a5
commit 3e36522329
No known key found for this signature in database
GPG key ID: F4D8A44EA0A75A4F
3 changed files with 26 additions and 14 deletions

View file

@ -275,15 +275,14 @@ func (h *Handler) FinalizeOrder(w http.ResponseWriter, r *http.Request) {
func challengeTypes(az *acme.Authorization) []string {
chTypes := []string{}
// DNS challenge can not be used for identifiers with type IP
if az.Identifier.Type != "ip" {
// DNS challenge can only be used for identifiers with type dns
if az.Identifier.Type == "dns" {
chTypes = append(chTypes, "dns-01") // TODO: make these types consts/enum?
}
// HTTP and TLS challenges can only be used for identifiers without wildcards.
if !az.Wildcard {
//chTypes = append(chTypes, []string{"http-01", "tls-alpn-01"}...)
chTypes = append(chTypes, []string{"http-01"}...) // TODO: fix tls-alpn-01
chTypes = append(chTypes, []string{"http-01", "tls-alpn-01"}...)
}
return chTypes

View file

@ -119,8 +119,14 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON
hostPort := net.JoinHostPort(ch.Value, "443")
fmt.Println(hostPort)
fmt.Println(fmt.Sprintf("%#+v", config))
time.Sleep(5 * time.Second) // TODO: remove this; client seems to take a while to start serving; the server does not seem to retry the conn
conn, err := vo.TLSDial("tcp", hostPort, config)
if err != nil {
fmt.Println(err)
return storeError(ctx, db, ch, false, WrapError(ErrorConnectionType, err,
"error doing TLS dial for %s", hostPort))
}
@ -129,6 +135,9 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON
cs := conn.ConnectionState()
certs := cs.PeerCertificates
fmt.Println(fmt.Sprintf("%#+v", cs))
fmt.Println(fmt.Sprintf("%#+v", certs))
if len(certs) == 0 {
return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType,
"%s challenge for %s resulted in no certificates", ch.Type, ch.Value))
@ -140,10 +149,19 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON
}
leafCert := certs[0]
fmt.Println(fmt.Sprintf("%#+v", leafCert))
if len(leafCert.DNSNames) != 1 || !strings.EqualFold(leafCert.DNSNames[0], ch.Value) {
return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType,
"incorrect certificate for tls-alpn-01 challenge: leaf certificate must contain a single DNS name, %v", ch.Value))
// if no DNS names present, look for IP address and verify that exactly one exists
if len(leafCert.DNSNames) == 0 {
if len(leafCert.IPAddresses) != 1 || !strings.EqualFold(leafCert.IPAddresses[0].String(), ch.Value) {
return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType,
"incorrect certificate for tls-alpn-01 challenge: leaf certificate must contain a single IP address, %v", ch.Value))
}
} else {
if len(leafCert.DNSNames) != 1 || !strings.EqualFold(leafCert.DNSNames[0], ch.Value) {
return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType,
"incorrect certificate for tls-alpn-01 challenge: leaf certificate must contain a single DNS name, %v", ch.Value))
}
}
idPeAcmeIdentifier := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}

View file

@ -207,17 +207,12 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ
orderNames = uniqueSortedLowerNames(orderNames)
orderIPs = uniqueSortedIPs(orderIPs)
// TODO: check whether this order was requested with identifier-type IP,
// if so, handle it as an IP order; not as a DNSName order, so the logic
// for verifying the contents MAY not be necessary.
// TODO: limit what IP addresses can be used? Only private? Only certain ranges
// based on configuration? Public vs. private range? That logic should be configurable somewhere.
// TODO: how to handler orders that have DNSNames AND IPs? I guess it could
// happen in cases where there are multiple "identifiers" to order a cert for
// and http or tls-alpn-1 is used (NOT DNS, because that can't be used for IPs).
// TODO: ensure that DNSNames indeed MUST NEVER have an IP
// TODO: only allow IP based identifier based on configuration?
// TODO: validation of the input (if IP; should be valid IPv4/v6)
// TODO: validation of the input (if IP; should be valid IPv4/v6; Incoming request should have Host header set / ALPN IN-ADDR.ARPA)
// TODO: limit the IP address identifier to a single IP address? RFC _can_ be read like that, but there can be multiple identifiers, of course
// Determine if DNS names or IPs should be processed.
// At this time, orders in which DNS names and IPs are mixed are not supported. // TODO: ensure that's OK and/or should we support more, RFC-wise