crypto/tls: Profiles
tls.Config has a lot of knobs. Each allow for an extra dimension of configuration that places the burden of decision and maintenance on the user. Over time, we have moved towards reducing this surface area in pointed ways (#45430, #69393).
These changes brought us closer to a safe-by-default API; however, this still does not alleviate the N independent choices a user must make. Instead, a safe-by-default crypto/tls configuration API should express a posture over a precommitted universe of parameters, namely crypto/tls.Config.
In general, we should aim to provide useful defaults over the N-dimensional configuration space such that evolution does not conflict with language and ecosystem needs.
I propose we add TLS Profiles: named, opaque security configurations that define the maximal set of acceptable parameters for a connection. All existing Config fields continue to work; subsequent mutations of the Config cannot weaken the security posture given by active Profile.
This proposal explicitly makes no statements about the contents of each profile; where necessary, examples referencing parameters are illustrative only and do not reflect opinions about which profiles should contain which parameters. @FiloSottile will own a different proposal that addresses these points.
Profile Shape
type Config struct {
// Profile describes the maximal set of parameters
// that the Config is allowed to use; mutating any
// fields within Config cannot weaken the properties
// guaranteed by the Profile.
Profile Profile
// ... existing fields ...
}
// Profile describes a security posture that applies to
// all TLS connections. By definition, no operation is
// permitted to weaken the security properties of a Profile.
//
// [ProfileDefault] is safe-by-default, and it is recommended
// for use in most applications.
type Profile int
const (
// ProfileDefault is the default profile safe for general purpose
// use and can evolve with each Go release.
ProfileDefault Profile = iota
// ProfileCompatibility includes a more permissive set of legacy
// parameters that are generally discouraged for use outside
// of deployments with demonstrated interoperability needs.
ProfileCompatibility
// ProfileModern includes a more restrictive set of parameters
// that generally foreshadow what future [ProfileDefault] might
// look like.
ProfileModern
// ProfileFIPS140 exactly matches GODEBUG=fips140=on.
ProfileFIPS140
)
Profiles guarantee a minimum security posture that is enforced at runtime. All knobs exposed by crypto/tls.Config can only intersect with a given Profile; unions are impossible by definition.
Profiles are not given version numbers. Their behavior and configuration are bound to the version of Go that is used to compile a given program. Any set of behaviors that can be expressed through a versioned Profile are equivalently expressible by narrowing the crypto/tls.Config beyond its default or application-selected Profile.
In addition to providing a safe-by-default TLS configuration, Profiles naturally provide a mechanism for quickly and safely disabling parameters that may be obsoleted by CRQCs.
For example, applications setting CurvePreferences today will, in effect, opt out of future PQ functionality. With Profiles, any such application will now be using ProfileDefault which provides PQ-inclusive parameters.
ProfileCompatibility replaces the accumulating non-feature GODEBUGs. Instead of knowing which combination of tlsrsakex=1, tls3des=1, tlssha1=1, and tls10server=1 you need, you select one profile which includes them all. If an application desires to further narrow this set to restore previous behavior, it may do so by setting the appropriate fields in Config.
Regarding X.509 certificates, profiles will narrow the set of acceptable certificates through their stated security posture similarly to how TLS 1.3 implies a set of invalid and valid X.509 certificates.
Somewhat notably, Profiles imply that session resumption can fail if a tightened server profile encounters a more relaxed client session. For example, a future release of Go may trigger a renegotiation of a session without application code changes. This behavior is considered to be working as intended under profiles.
Profiles are not made to be observable in ConnectionState.
Open Questions
- Further considerations about the behavior of X.509 certificates with Profiles?
/cc @FiloSottile @golang/security @golang/proposal-review
crypto/tls: Profiles
tls.Confighas a lot of knobs. Each allow for an extra dimension of configuration that places the burden of decision and maintenance on the user. Over time, we have moved towards reducing this surface area in pointed ways (#45430, #69393).These changes brought us closer to a safe-by-default API; however, this still does not alleviate the N independent choices a user must make. Instead, a safe-by-default
crypto/tlsconfiguration API should express a posture over a precommitted universe of parameters, namelycrypto/tls.Config.In general, we should aim to provide useful defaults over the N-dimensional configuration space such that evolution does not conflict with language and ecosystem needs.
I propose we add TLS Profiles: named, opaque security configurations that define the maximal set of acceptable parameters for a connection. All existing
Configfields continue to work; subsequent mutations of theConfigcannot weaken the security posture given by active Profile.This proposal explicitly makes no statements about the contents of each profile; where necessary, examples referencing parameters are illustrative only and do not reflect opinions about which profiles should contain which parameters. @FiloSottile will own a different proposal that addresses these points.
Profile Shape
Profiles guarantee a minimum security posture that is enforced at runtime. All knobs exposed by
crypto/tls.Configcan only intersect with a given Profile; unions are impossible by definition.Profiles are not given version numbers. Their behavior and configuration are bound to the version of Go that is used to compile a given program. Any set of behaviors that can be expressed through a versioned Profile are equivalently expressible by narrowing the
crypto/tls.Configbeyond its default or application-selected Profile.In addition to providing a safe-by-default TLS configuration, Profiles naturally provide a mechanism for quickly and safely disabling parameters that may be obsoleted by CRQCs.
For example, applications setting
CurvePreferencestoday will, in effect, opt out of future PQ functionality. With Profiles, any such application will now be usingProfileDefaultwhich provides PQ-inclusive parameters.ProfileCompatibilityreplaces the accumulating non-feature GODEBUGs. Instead of knowing which combination oftlsrsakex=1,tls3des=1,tlssha1=1, andtls10server=1you need, you select one profile which includes them all. If an application desires to further narrow this set to restore previous behavior, it may do so by setting the appropriate fields inConfig.Regarding X.509 certificates, profiles will narrow the set of acceptable certificates through their stated security posture similarly to how TLS 1.3 implies a set of invalid and valid X.509 certificates.
Somewhat notably, Profiles imply that session resumption can fail if a tightened server profile encounters a more relaxed client session. For example, a future release of Go may trigger a renegotiation of a session without application code changes. This behavior is considered to be working as intended under profiles.
Profiles are not made to be observable in
ConnectionState.Open Questions
/cc @FiloSottile @golang/security @golang/proposal-review