Skip to content

Commit

Permalink
crypto/tls: implement draft-ietf-tls-subcerts-10
Browse files Browse the repository at this point in the history
* Define API for delegated credentials so they are fetched using the
  same mechanisms used to fetch certificates
* Allow the usage of other keyUsage when checking for the DC extension.
* Add tool for generating delegated credentials.

Co-authored-by: Jonathan Hoyland <jhoyland@cloudflare.com>
  • Loading branch information
2 people authored and bwesterb committed Dec 6, 2023
1 parent dc1c0c7 commit 6a50b3d
Show file tree
Hide file tree
Showing 19 changed files with 1,872 additions and 34 deletions.
22 changes: 22 additions & 0 deletions src/crypto/tls/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,28 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
return sigAlgs
}

// selectSignatureSchemeDC picks a SignatureScheme from the peer's preference list
// that works with the selected delegated credential. It's only called for protocol
// versions that support delegated credential, so TLS 1.3.
func selectSignatureSchemeDC(vers uint16, dc *DelegatedCredential, peerAlgs []SignatureScheme, peerAlgsDC []SignatureScheme) (SignatureScheme, error) {
if vers != VersionTLS13 {
return 0, errors.New("unsupported TLS version for dc")
}

if !isSupportedSignatureAlgorithm(dc.algorithm, peerAlgs) {
return undefinedSignatureScheme, errors.New("tls: peer doesn't support the delegated credential's signature")
}

// Pick signature scheme in the peer's preference order, as our
// preference order is not configurable.
for _, preferredAlg := range peerAlgsDC {
if preferredAlg == dc.cred.expCertVerfAlgo {
return preferredAlg, nil
}
}
return 0, errors.New("tls: peer doesn't support the delegated credential's signature algorithm")
}

// selectSignatureScheme picks a SignatureScheme from the peer's preference list
// that works with the selected certificate. It's only called for protocol
// versions that support signature algorithms, so TLS 1.2 and 1.3.
Expand Down
66 changes: 66 additions & 0 deletions src/crypto/tls/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const (
extensionALPN uint16 = 16
extensionSCT uint16 = 18
extensionExtendedMasterSecret uint16 = 23
extensionDelegatedCredentials uint16 = 34
extensionSessionTicket uint16 = 35
extensionPreSharedKey uint16 = 41
extensionEarlyData uint16 = 42
Expand Down Expand Up @@ -213,6 +214,16 @@ var defaultSupportedSignatureAlgorithms = []SignatureScheme{
ECDSAWithSHA1,
}

// supportedSignatureAlgorithmsDC contains the signature and hash algorithms that
// the code advertises as supported in a TLS 1.3 ClientHello and in a TLS 1.3
// CertificateRequest. This excludes 'rsa_pss_rsae_' algorithms.
var supportedSignatureAlgorithmsDC = []SignatureScheme{
ECDSAWithP256AndSHA256,
Ed25519,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
}

// helloRetryRequestRandom is set as the Random value of a ServerHello
// to signal that the message is actually a HelloRetryRequest.
var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3.
Expand Down Expand Up @@ -284,6 +295,11 @@ type ConnectionState struct {
// VerifiedChains and its contents should not be modified.
VerifiedChains [][]*x509.Certificate

// VerifiedDC indicates that the Delegated Credential sent by the peer (if advertised
// and correctly processed), which has been verified against the leaf certificate,
// has been used.
VerifiedDC bool

// SignedCertificateTimestamps is a list of SCTs provided by the peer
// through the TLS handshake for the leaf certificate, if any.
SignedCertificateTimestamps [][]byte
Expand Down Expand Up @@ -427,6 +443,13 @@ type ClientHelloInfo struct {
// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
SignatureSchemes []SignatureScheme

// SignatureSchemesDC lists the signature schemes that the client
// is willing to verify when using Delegated Credentials.
// This is and can be different from SignatureSchemes. SignatureSchemesDC
// is set only if the DelegatedCredentials Extension is being used.
// If Delegated Credentials are supported, this list should not be nil.
SignatureSchemesDC []SignatureScheme

// SupportedProtos lists the application protocols supported by the client.
// SupportedProtos is set only if the Application-Layer Protocol
// Negotiation Extension is being used (see RFC 7301, Section 3.1).
Expand All @@ -441,6 +464,10 @@ type ClientHelloInfo struct {
// might be rejected if used.
SupportedVersions []uint16

// SupportDelegatedCredential is true if the client indicated willingness
// to negotiate the Delegated Credential extension.
SupportsDelegatedCredential bool

// Conn is the underlying net.Conn for the connection. Do not read
// from, or write to, this connection; that will cause the TLS
// connection to fail.
Expand Down Expand Up @@ -471,10 +498,21 @@ type CertificateRequestInfo struct {
// empty slice indicates that the server has no preference.
AcceptableCAs [][]byte

// SupportDelegatedCredential is true if the server indicated willingness
// to negotiate the Delegated Credential extension.
SupportsDelegatedCredential bool

// SignatureSchemes lists the signature schemes that the server is
// willing to verify.
SignatureSchemes []SignatureScheme

// SignatureSchemesDC lists the signature schemes that the server
// is willing to verify when using Delegated Credentials.
// This is and can be different from SignatureSchemes. SignatureSchemesDC
// is set only if the DelegatedCredentials Extension is being used.
// If Delegated Credentials are supported, this list should not be nil.
SignatureSchemesDC []SignatureScheme

// Version is the TLS version that was negotiated for this connection.
Version uint16

Expand Down Expand Up @@ -778,6 +816,13 @@ type Config struct {
// used for debugging.
KeyLogWriter io.Writer

// SupportDelegatedCredential is true if the client or server is willing
// to negotiate the delegated credential extension.
// This can only be used with TLS 1.3.
//
// See https://tools.ietf.org/html/draft-ietf-tls-subcerts.
SupportDelegatedCredential bool

// mutex protects sessionTicketKeys and autoSessionTicketKeys.
mutex sync.RWMutex
// sessionTicketKeys contains zero or more ticket keys. If set, it means
Expand Down Expand Up @@ -866,6 +911,7 @@ func (c *Config) Clone() *Config {
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
Renegotiation: c.Renegotiation,
KeyLogWriter: c.KeyLogWriter,
SupportDelegatedCredential: c.SupportDelegatedCredential,
sessionTicketKeys: c.sessionTicketKeys,
autoSessionTicketKeys: c.autoSessionTicketKeys,
}
Expand Down Expand Up @@ -1405,6 +1451,16 @@ func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
// and is only for debugging, so a global mutex saves space.
var writerMutex sync.Mutex

// A DelegatedCredentialPair contains a Delegated Credential and its
// associated private key.
type DelegatedCredentialPair struct {
// DC is the delegated credential.
DC *DelegatedCredential
// PrivateKey is the private key used to derive the public key of
// contained in DC. PrivateKey must implement crypto.Signer.
PrivateKey crypto.PrivateKey
}

// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
Expand All @@ -1422,6 +1478,16 @@ type Certificate struct {
// SignedCertificateTimestamps contains an optional list of Signed
// Certificate Timestamps which will be served to clients that request it.
SignedCertificateTimestamps [][]byte
// DelegatedCredentials are a list of Delegated Credentials with their
// corresponding private keys, signed by the leaf certificate.
// If there are no delegated credentials, this field is nil.
DelegatedCredentials []DelegatedCredentialPair
// DelegatedCredential is the delegated credential to be used in the
// handshake.
// If there are no delegated credentials, this field is nil.
// NOTE: Do not fill this field, as it will be filled depending on
// the provided list of delegated credentials.
DelegatedCredential []byte
// Leaf is the parsed form of the leaf certificate, which may be initialized
// using x509.ParseCertificate to reduce per-handshake processing. If nil,
// the leaf certificate will be parsed as needed.
Expand Down
6 changes: 6 additions & 0 deletions src/crypto/tls/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ type Conn struct {
// verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
// verifiedDC contains the Delegated Credential sent by the peer (if advertised
// and correctly processed), which has been verified against the leaf certificate.
verifiedDC *DelegatedCredential
// serverName contains the server name indicated by the client, if any.
serverName string
// secureRenegotiation is true if the server echoed the secure
Expand Down Expand Up @@ -1618,6 +1621,9 @@ func (c *Conn) connectionStateLocked() ConnectionState {
state.CipherSuite = c.cipherSuite
state.PeerCertificates = c.peerCertificates
state.VerifiedChains = c.verifiedChains
if c.verifiedDC != nil {
state.VerifiedDC = true
}
state.SignedCertificateTimestamps = c.scts
state.OCSPResponse = c.ocspResponse
if (!c.didResume || c.extMasterSecret) && c.vers != VersionTLS13 {
Expand Down
Loading

0 comments on commit 6a50b3d

Please sign in to comment.