Skip to content

Commit b3790b8

Browse files
cpugopherbot
authored andcommitted
acme: fix TLSALPN01ChallengeCert for IP address identifiers
When creating a TLS-ALPN-01 challenge response certificate for an IP address identifier we need to configure the template IPAddresses field, not the DNSNames/Subject.CommonName. Along the way we can do some small tidying: * Updating the draft TLS-ALPN-01 reference to the finalized RFC * Adding a reference to the IP address identifier ACME RFC * Adding a mention of the form the challenge validation request's SNI will take when verifying an IP address identifier * Tidying the private tlsChallengeCert() function to take a single identifier as arg since the only call-sites provide singular values since the removal of the TLS-SNI-[01|02] challenge helpers. This allows enabling an IP address identifier in the Pebble integration tests that otherwise caused a validation failure for TLS-ALPN-01 challenge types because the IP address was used as a DNS SAN. Updates golang/go#73914 Cq-Include-Trybots: luci.golang.try:x_crypto-gotip-linux-amd64-longtest Change-Id: Ic671e41b585f424f821db65206c7ffcc6dd386a0 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/677576 Reviewed-by: Ian Stapleton Cordasco <[email protected]> Auto-Submit: Daniel McCarney <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 1dc4269 commit b3790b8

File tree

3 files changed

+29
-20
lines changed

3 files changed

+29
-20
lines changed

acme/acme.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"errors"
3636
"fmt"
3737
"math/big"
38+
"net"
3839
"net/http"
3940
"strings"
4041
"sync"
@@ -589,18 +590,23 @@ func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (tls.Cer
589590

590591
// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response.
591592
// Servers can present the certificate to validate the challenge and prove control
592-
// over a domain name. For more details on TLS-ALPN-01 see
593-
// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3
593+
// over an identifier (either a DNS name or the textual form of an IPv4 or IPv6
594+
// address). For more details on TLS-ALPN-01 see
595+
// https://www.rfc-editor.org/rfc/rfc8737 and https://www.rfc-editor.org/rfc/rfc8738
594596
//
595597
// The token argument is a Challenge.Token value.
596598
// If a WithKey option is provided, its private part signs the returned cert,
597599
// and the public part is used to specify the signee.
598600
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
599601
//
600602
// The returned certificate is valid for the next 24 hours and must be presented only when
601-
// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol
603+
// the server name in the TLS ClientHello matches the identifier, and the special acme-tls/1 ALPN protocol
602604
// has been specified.
603-
func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) {
605+
//
606+
// Validation requests for IP address identifiers will use the reverse DNS form in the server name
607+
// in the TLS ClientHello since the SNI extension is not supported for IP addresses.
608+
// See RFC 8738 Section 6 for more information.
609+
func (c *Client) TLSALPN01ChallengeCert(token, identifier string, opt ...CertOption) (cert tls.Certificate, err error) {
604610
ka, err := keyAuth(c.Key.Public(), token)
605611
if err != nil {
606612
return tls.Certificate{}, err
@@ -630,7 +636,7 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption)
630636
}
631637
tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension)
632638
newOpt = append(newOpt, WithTemplate(tmpl))
633-
return tlsChallengeCert([]string{domain}, newOpt)
639+
return tlsChallengeCert(identifier, newOpt)
634640
}
635641

636642
// popNonce returns a nonce value previously stored with c.addNonce
@@ -749,10 +755,14 @@ func defaultTLSChallengeCertTemplate() *x509.Certificate {
749755
}
750756

751757
// tlsChallengeCert creates a temporary certificate for TLS-ALPN challenges
752-
// with the given SANs and auto-generated public/private key pair.
753-
// The Subject Common Name is set to the first SAN to aid debugging.
758+
// for the given identifier, using an auto-generated public/private key pair.
759+
//
760+
// If the provided identifier is a domain name, it will be used as a DNS type SAN and for the
761+
// subject common name. If the provided identifier is an IP address it will be used as an IP type
762+
// SAN.
763+
//
754764
// To create a cert with a custom key pair, specify WithKey option.
755-
func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
765+
func tlsChallengeCert(identifier string, opt []CertOption) (tls.Certificate, error) {
756766
var key crypto.Signer
757767
tmpl := defaultTLSChallengeCertTemplate()
758768
for _, o := range opt {
@@ -776,9 +786,12 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
776786
return tls.Certificate{}, err
777787
}
778788
}
779-
tmpl.DNSNames = san
780-
if len(san) > 0 {
781-
tmpl.Subject.CommonName = san[0]
789+
790+
if ip := net.ParseIP(identifier); ip != nil {
791+
tmpl.IPAddresses = []net.IP{ip}
792+
} else {
793+
tmpl.DNSNames = []string{identifier}
794+
tmpl.Subject.CommonName = identifier
782795
}
783796

784797
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key)

acme/pebble_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -334,14 +334,10 @@ func testIssuance(t *testing.T, env *environment, challSrv challengeServer) {
334334
Type: "dns",
335335
Value: "www.example.com",
336336
},
337-
// TODO(@cpu): enable this identifier once IP addresses are handled correctly
338-
// by acme.TLSALPN01ChallengeCert
339-
/*
340-
{
341-
Type: "ip",
342-
Value: "127.0.0.1",
343-
},
344-
*/
337+
{
338+
Type: "ip",
339+
Value: "127.0.0.1",
340+
},
345341
}
346342
order, err := client.AuthorizeOrder(ctx, identifiers)
347343
if err != nil {

acme/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ func (*certOptKey) privateCertOpt() {}
619619
//
620620
// In TLS ChallengeCert methods, the template is also used as parent,
621621
// resulting in a self-signed certificate.
622-
// The DNSNames field of t is always overwritten for tls-sni challenge certs.
622+
// The DNSNames or IPAddresses fields of t are always overwritten for tls-alpn challenge certs.
623623
func WithTemplate(t *x509.Certificate) CertOption {
624624
return (*certOptTemplate)(t)
625625
}

0 commit comments

Comments
 (0)