When configuring TLS in Go applications, you’ll often come across the recommendation to set Renegotiation: tls.RenegotiateNever
in your TLS configuration. But what exactly does this mean, and why is it recommended? Let’s dive deep into TLS renegotiation, its implications, and when you might want to use different settings.
What is TLS Renegotiation?
TLS renegotiation is a feature that allows clients and servers to update their TLS session parameters (like cipher suites or client certificates) without interrupting the existing connection. While this sounds useful, it comes with its own set of challenges.
The Three Options in Go
Go’s crypto/tls package provides three options for handling TLS renegotiation:
tlsConfig := &tls.Config{
Renegotiation: tls.RenegotiateNever, // Option 1
// or tls.RenegotiateOnceAsClient // Option 2
// or tls.RenegotiateFreelyAsClient // Option 3
}
1. RenegotiateNever
This option completely disables renegotiation. It’s often the recommended choice for modern systems.
2. RenegotiateOnceAsClient
This is Go’s default setting. It allows a single renegotiation per connection.
3. RenegotiateFreelyAsClient
This allows unlimited renegotiations, but it’s generally not recommended.
Why Choose RenegotiateNever?
Security Benefits
TLS renegotiation has a history of security vulnerabilities. The most notable was discovered in 2009, leading to the TLS Renegotiation Attack. While modern TLS implementations have addressed these specific vulnerabilities, disabling renegotiation altogether eliminates an entire class of potential security risks.
Performance Advantages
TLS renegotiation is computationally expensive. Each renegotiation requires:
- New key exchange
- New cryptographic computations
- Additional network roundtrips
By disabling renegotiation, you avoid these performance impacts.
Simplified Security Model
With renegotiation disabled, the TLS connection model becomes simpler and more predictable. This makes it easier to:
- Reason about security properties
- Debug connection issues
- Maintain consistent behavior
When Might You Need Renegotiation?
Despite the advantages of RenegotiateNever
, there are legitimate use cases for TLS renegotiation:
- Legacy System Integration: Some older systems require renegotiation for certain operations.
- Client Certificate Updates: In systems where client certificates need to be updated mid-session.
- Long-lived Connections: When security parameters need to be updated without dropping the connection.
Best Practices
Default to RenegotiateNever
- Start with renegotiation disabled
- Only enable it if you have a specific need
Monitor for Issues
- Watch for connection failures with legacy systems
- Be prepared to adjust if needed
Consider Alternatives
- Instead of renegotiation, consider establishing new connections
- Use modern protocols that handle parameter updates differently
Example Configuration
Here’s a modern, secure TLS configuration in Go:
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
},
Renegotiation: tls.RenegotiateNever,
NextProtos: []string{"h2", "http/1.1"},
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
}
Conclusion
While TLS renegotiation can be useful in specific scenarios, disabling it with RenegotiateNever
is often the right choice for modern applications. It provides better security, performance, and simplicity. However, always consider your specific use case and requirements when making this decision.
Remember that security is never one-size-fits-all. While RenegotiateNever
is a good default, the best configuration for your application depends on your specific requirements, constraints, and the systems you need to interact with.