Go: proposal: crypto/tls: supported certificate types API

Created on 4 Jun 2019  路  5Comments  路  Source: golang/go

Presently there is no simple way to determine whether a client/connection will support a particular TLS certificate type from within a GetCertificate callback.

The logic within crypto/tls is complex, subtle and hard to reason with from without crypto/tls. With the addition of Ed25519 in CL 177698, this is now even harder to get right as there are now three distinct certificate types that may be supported: RSA, ECDSA and Ed25519.

What I'd like to propose is some addition to ClientHelloInfo that would allow the GetCertificate callback to determine which certificate types are supported by the client and server for the connection. I'm not sure what an appropriate API would look like, but perhaps a method (Supports(...) bool) or struct as a field (Supports struct { RSA, ECDSA, Ed25519 bool }) or added fields (SupportsRSA bool; SupportsECDSA bool; SupportsEd25519 bool) on ClientHelloInfo.

An incomplete implementation was added to acme/autocert in CL 114501. This is documented as differing from crypto/tls (see commit message), and could cause handshake failures if there isn't a mutually supported ECDSA cipher suite. I've also tried implementing this myself using just the information in ClientHelloInfo and it is entirely non-trivial[1].

It's impossible to correctly implement this safely without support from crypto/tls because it's dependant on the configured/default cipher suites (which aren't always easily accessible) and internal crypto/tls implementation details.

This is useful for servers that might want to support several certificate types鈥搕o allow for older clients to successful connect鈥搇ike acme/autocert does. For example the server may wish to prioritise Ed25519 over ECDSA and use RSA as a fallback, or more simply prefer ECDSA over RSA.

I'm not sure whether this will conflict with the recently approved proposal for #28660 (https://github.com/golang/go/issues/28660#issuecomment-498609833), but it's likely that will need to be considered.


There's also the presently unsupported RSASSA-PSS algorithms with public key OID RSASSA-PSS block of signature schemes (rsa_pss_pss_*) for RSA certificates with RSA-PSS only public keys. I presume support for that could wind up in crypto/tls one-day. And finally the signature_algorithms_cert extension may be of relevance in some cases.

FrozenDueToAge Proposal Proposal-Accepted Proposal-Crypto

Most helpful comment

I feel like the most future-proof and reusable API here would be

func (*ClientHelloInfo) SupportsCertificate(*Certificate) bool
func (*CertificateRequestInfo) SupportsCertificate(*Certificate) bool

I like this because the logic is getting more complex over time, I heard requests that would be fulfilled by this multiple times, and even the crypto/tls internals would benefit from this API.

All 5 comments

I'm not sure exactly what the protocol for proposals is, but cc @FiloSottile.

I feel like the most future-proof and reusable API here would be

func (*ClientHelloInfo) SupportsCertificate(*Certificate) bool
func (*CertificateRequestInfo) SupportsCertificate(*Certificate) bool

I like this because the logic is getting more complex over time, I heard requests that would be fulfilled by this multiple times, and even the crypto/tls internals would benefit from this API.

Change https://golang.org/cl/205058 mentions this issue: crypto/tls: implement (*CertificateRequestInfo).SupportsCertificate

Change https://golang.org/cl/205057 mentions this issue: crypto/tls: implement (*ClientHelloInfo).SupportsCertificate

Change https://golang.org/cl/205061 mentions this issue: crypto/tls: refactor certificate and signature algorithm logic

Was this page helpful?
0 / 5 - 0 ratings