Skip to content

Commit c8f4a7e

Browse files
claucecejhoyla
authored andcommitted
crypto/tls: implement draft-ietf-tls-subcerts-10
* 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. Fixes issues in earlier patch, addressing #127, #128, #129, #130, and #131. Add tool for generating delegated credentials. Co-authored-by: Jonathan Hoyland <jhoyland@cloudflare.com>
1 parent 40b3758 commit c8f4a7e

19 files changed

+1873
-34
lines changed

src/crypto/tls/auth.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,28 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
260260
return sigAlgs
261261
}
262262

263+
// selectSignatureSchemeDC picks a SignatureScheme from the peer's preference list
264+
// that works with the selected delegated credential. It's only called for protocol
265+
// versions that support delegated credential, so TLS 1.3.
266+
func selectSignatureSchemeDC(vers uint16, dc *DelegatedCredential, peerAlgs []SignatureScheme, peerAlgsDC []SignatureScheme) (SignatureScheme, error) {
267+
if vers != VersionTLS13 {
268+
return 0, errors.New("unsupported TLS version for dc")
269+
}
270+
271+
if !isSupportedSignatureAlgorithm(dc.algorithm, peerAlgs) {
272+
return undefinedSignatureScheme, errors.New("tls: peer doesn't support the delegated credential's signature")
273+
}
274+
275+
// Pick signature scheme in the peer's preference order, as our
276+
// preference order is not configurable.
277+
for _, preferredAlg := range peerAlgsDC {
278+
if preferredAlg == dc.cred.expCertVerfAlgo {
279+
return preferredAlg, nil
280+
}
281+
}
282+
return 0, errors.New("tls: peer doesn't support the delegated credential's signature algorithm")
283+
}
284+
263285
// selectSignatureScheme picks a SignatureScheme from the peer's preference list
264286
// that works with the selected certificate. It's only called for protocol
265287
// versions that support signature algorithms, so TLS 1.2 and 1.3.

src/crypto/tls/common.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ const (
9090
extensionSignatureAlgorithms uint16 = 13
9191
extensionALPN uint16 = 16
9292
extensionSCT uint16 = 18
93+
extensionDelegatedCredentials uint16 = 34
9394
extensionSessionTicket uint16 = 35
9495
extensionPreSharedKey uint16 = 41
9596
extensionEarlyData uint16 = 42
@@ -191,6 +192,16 @@ var defaultSupportedSignatureAlgorithms = []SignatureScheme{
191192
ECDSAWithSHA1,
192193
}
193194

195+
// supportedSignatureAlgorithmsDC contains the signature and hash algorithms that
196+
// the code advertises as supported in a TLS 1.3 ClientHello and in a TLS 1.3
197+
// CertificateRequest. This excludes 'rsa_pss_rsae_' algorithms.
198+
var supportedSignatureAlgorithmsDC = []SignatureScheme{
199+
ECDSAWithP256AndSHA256,
200+
Ed25519,
201+
ECDSAWithP384AndSHA384,
202+
ECDSAWithP521AndSHA512,
203+
}
204+
194205
// helloRetryRequestRandom is set as the Random value of a ServerHello
195206
// to signal that the message is actually a HelloRetryRequest.
196207
var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3.
@@ -262,6 +273,11 @@ type ConnectionState struct {
262273
// VerifiedChains and its contents should not be modified.
263274
VerifiedChains [][]*x509.Certificate
264275

276+
// VerifiedDC indicates that the Delegated Credential sent by the peer (if advertised
277+
// and correctly processed), which has been verified against the leaf certificate,
278+
// has been used.
279+
VerifiedDC bool
280+
265281
// SignedCertificateTimestamps is a list of SCTs provided by the peer
266282
// through the TLS handshake for the leaf certificate, if any.
267283
SignedCertificateTimestamps [][]byte
@@ -424,6 +440,13 @@ type ClientHelloInfo struct {
424440
// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
425441
SignatureSchemes []SignatureScheme
426442

443+
// SignatureSchemesDC lists the signature schemes that the client
444+
// is willing to verify when using Delegated Credentials.
445+
// This is and can be different from SignatureSchemes. SignatureSchemesDC
446+
// is set only if the DelegatedCredentials Extension is being used.
447+
// If Delegated Credentials are supported, this list should not be nil.
448+
SignatureSchemesDC []SignatureScheme
449+
427450
// SupportedProtos lists the application protocols supported by the client.
428451
// SupportedProtos is set only if the Application-Layer Protocol
429452
// Negotiation Extension is being used (see RFC 7301, Section 3.1).
@@ -438,6 +461,10 @@ type ClientHelloInfo struct {
438461
// might be rejected if used.
439462
SupportedVersions []uint16
440463

464+
// SupportDelegatedCredential is true if the client indicated willingness
465+
// to negotiate the Delegated Credential extension.
466+
SupportsDelegatedCredential bool
467+
441468
// Conn is the underlying net.Conn for the connection. Do not read
442469
// from, or write to, this connection; that will cause the TLS
443470
// connection to fail.
@@ -468,10 +495,21 @@ type CertificateRequestInfo struct {
468495
// empty slice indicates that the server has no preference.
469496
AcceptableCAs [][]byte
470497

498+
// SupportDelegatedCredential is true if the server indicated willingness
499+
// to negotiate the Delegated Credential extension.
500+
SupportsDelegatedCredential bool
501+
471502
// SignatureSchemes lists the signature schemes that the server is
472503
// willing to verify.
473504
SignatureSchemes []SignatureScheme
474505

506+
// SignatureSchemesDC lists the signature schemes that the server
507+
// is willing to verify when using Delegated Credentials.
508+
// This is and can be different from SignatureSchemes. SignatureSchemesDC
509+
// is set only if the DelegatedCredentials Extension is being used.
510+
// If Delegated Credentials are supported, this list should not be nil.
511+
SignatureSchemesDC []SignatureScheme
512+
475513
// Version is the TLS version that was negotiated for this connection.
476514
Version uint16
477515

@@ -739,6 +777,13 @@ type Config struct {
739777
// used for debugging.
740778
KeyLogWriter io.Writer
741779

780+
// SupportDelegatedCredential is true if the client or server is willing
781+
// to negotiate the delegated credential extension.
782+
// This can only be used with TLS 1.3.
783+
//
784+
// See https://tools.ietf.org/html/draft-ietf-tls-subcerts.
785+
SupportDelegatedCredential bool
786+
742787
// mutex protects sessionTicketKeys and autoSessionTicketKeys.
743788
mutex sync.RWMutex
744789
// sessionTicketKeys contains zero or more ticket keys. If set, it means
@@ -829,6 +874,7 @@ func (c *Config) Clone() *Config {
829874
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
830875
Renegotiation: c.Renegotiation,
831876
KeyLogWriter: c.KeyLogWriter,
877+
SupportDelegatedCredential: c.SupportDelegatedCredential,
832878
sessionTicketKeys: c.sessionTicketKeys,
833879
autoSessionTicketKeys: c.autoSessionTicketKeys,
834880
}
@@ -1368,6 +1414,16 @@ func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
13681414
// and is only for debugging, so a global mutex saves space.
13691415
var writerMutex sync.Mutex
13701416

1417+
// A DelegatedCredentialPair contains a Delegated Credential and its
1418+
// associated private key.
1419+
type DelegatedCredentialPair struct {
1420+
// DC is the delegated credential.
1421+
DC *DelegatedCredential
1422+
// PrivateKey is the private key used to derive the public key of
1423+
// contained in DC. PrivateKey must implement crypto.Signer.
1424+
PrivateKey crypto.PrivateKey
1425+
}
1426+
13711427
// A Certificate is a chain of one or more certificates, leaf first.
13721428
type Certificate struct {
13731429
Certificate [][]byte
@@ -1385,6 +1441,16 @@ type Certificate struct {
13851441
// SignedCertificateTimestamps contains an optional list of Signed
13861442
// Certificate Timestamps which will be served to clients that request it.
13871443
SignedCertificateTimestamps [][]byte
1444+
// DelegatedCredentials are a list of Delegated Credentials with their
1445+
// corresponding private keys, signed by the leaf certificate.
1446+
// If there are no delegated credentials, this field is nil.
1447+
DelegatedCredentials []DelegatedCredentialPair
1448+
// DelegatedCredential is the delegated credential to be used in the
1449+
// handshake.
1450+
// If there are no delegated credentials, this field is nil.
1451+
// NOTE: Do not fill this field, as it will be filled depending on
1452+
// the provided list of delegated credentials.
1453+
DelegatedCredential []byte
13881454
// Leaf is the parsed form of the leaf certificate, which may be initialized
13891455
// using x509.ParseCertificate to reduce per-handshake processing. If nil,
13901456
// the leaf certificate will be parsed as needed.

src/crypto/tls/conn.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ type Conn struct {
5555
// verifiedChains contains the certificate chains that we built, as
5656
// opposed to the ones presented by the server.
5757
verifiedChains [][]*x509.Certificate
58+
// verifiedDC contains the Delegated Credential sent by the peer (if advertised
59+
// and correctly processed), which has been verified against the leaf certificate.
60+
verifiedDC *DelegatedCredential
5861
// serverName contains the server name indicated by the client, if any.
5962
serverName string
6063
// secureRenegotiation is true if the server echoed the secure
@@ -1533,6 +1536,9 @@ func (c *Conn) connectionStateLocked() ConnectionState {
15331536
state.CipherSuite = c.cipherSuite
15341537
state.PeerCertificates = c.peerCertificates
15351538
state.VerifiedChains = c.verifiedChains
1539+
if c.verifiedDC != nil {
1540+
state.VerifiedDC = true
1541+
}
15361542
state.SignedCertificateTimestamps = c.scts
15371543
state.OCSPResponse = c.ocspResponse
15381544
if !c.didResume && c.vers != VersionTLS13 {

0 commit comments

Comments
 (0)