Skip to content

Commit f392a07

Browse files
clauceceLekensteyn
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.
1 parent fae347d commit f392a07

18 files changed

+1771
-33
lines changed

src/crypto/tls/auth.go

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

262+
// signatureSchemeForDelegatedCredential returns the list of supported
263+
// SignatureSchemes for a given delegated credential, based on the public
264+
// key, and optionally filtered by its explicit
265+
// SupportedSignatureAlgorithmsDC.
266+
//
267+
// This function must be kept in sync with supportedSignatureAlgorithmsDC.
268+
func signatureSchemeForDelegatedCredential(version uint16, dc *DelegatedCredential) []SignatureScheme {
269+
pub := dc.cred.publicKey
270+
271+
var sigAlgs []SignatureScheme
272+
switch pub.(type) {
273+
case *ecdsa.PublicKey:
274+
pk, ok := pub.(*ecdsa.PublicKey)
275+
if !ok {
276+
return nil
277+
}
278+
switch pk.Curve {
279+
case elliptic.P256():
280+
sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
281+
case elliptic.P384():
282+
sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
283+
case elliptic.P521():
284+
sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
285+
default:
286+
return nil
287+
}
288+
case ed25519.PublicKey:
289+
sigAlgs = []SignatureScheme{Ed25519}
290+
case circlSign.PublicKey:
291+
pk, ok := pub.(circlSign.PublicKey)
292+
if !ok {
293+
return nil
294+
}
295+
scheme := pk.Scheme()
296+
tlsScheme, ok := scheme.(circlPki.TLSScheme)
297+
if !ok {
298+
return nil
299+
}
300+
sigAlgs = []SignatureScheme{SignatureScheme(tlsScheme.TLSIdentifier())}
301+
default:
302+
return nil
303+
}
304+
305+
return sigAlgs
306+
}
307+
308+
// selectSignatureSchemeDC picks a SignatureScheme from the peer's preference list
309+
// that works with the selected delegated credential. It's only called for protocol
310+
// versions that support delegated credential, so TLS 1.3.
311+
func selectSignatureSchemeDC(vers uint16, dc *DelegatedCredential, peerAlgs []SignatureScheme) (SignatureScheme, error) {
312+
if vers != VersionTLS13 {
313+
return 0, errors.New("unsupported TLS version for dc")
314+
}
315+
316+
supportedAlgs := signatureSchemeForDelegatedCredential(vers, dc)
317+
if len(supportedAlgs) == 0 {
318+
return 0, errors.New("unsupported scheme for dc")
319+
}
320+
// Pick signature scheme in the peer's preference order, as our
321+
// preference order is not configurable.
322+
for _, preferredAlg := range peerAlgs {
323+
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
324+
return preferredAlg, nil
325+
}
326+
}
327+
return 0, errors.New("tls: peer doesn't support any of the delegated credential's signature algorithms")
328+
}
329+
262330
// selectSignatureScheme picks a SignatureScheme from the peer's preference list
263331
// that works with the selected certificate. It's only called for protocol
264332
// 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 supportedSignatureAlgorithms = []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.
@@ -258,6 +269,11 @@ type ConnectionState struct {
258269
// (and the peer provided a certificate) or RequireAndVerifyClientCert.
259270
VerifiedChains [][]*x509.Certificate
260271

272+
// VerifiedDC indicates that the Delegated Credential sent by the peer (if advertised
273+
// and correctly processed), which has been verified against the leaf certificate,
274+
// has been used.
275+
VerifiedDC bool
276+
261277
// SignedCertificateTimestamps is a list of SCTs provided by the peer
262278
// through the TLS handshake for the leaf certificate, if any.
263279
SignedCertificateTimestamps [][]byte
@@ -427,6 +443,13 @@ type ClientHelloInfo struct {
427443
// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
428444
SignatureSchemes []SignatureScheme
429445

446+
// SignatureSchemesDC lists the signature schemes that the client
447+
// is willing to verify when using Delegated Credentials.
448+
// This is and can be different from SignatureSchemes. SignatureSchemesDC
449+
// is set only if the DelegatedCredentials Extension is being used.
450+
// If Delegated Credentials are supported, this list should not be nil.
451+
SignatureSchemesDC []SignatureScheme
452+
430453
// SupportedProtos lists the application protocols supported by the client.
431454
// SupportedProtos is set only if the Application-Layer Protocol
432455
// Negotiation Extension is being used (see RFC 7301, Section 3.1).
@@ -441,6 +464,10 @@ type ClientHelloInfo struct {
441464
// might be rejected if used.
442465
SupportedVersions []uint16
443466

467+
// SupportDelegatedCredential is true if the client indicated willingness
468+
// to negotiate the Delegated Credential extension.
469+
SupportsDelegatedCredential bool
470+
444471
// Conn is the underlying net.Conn for the connection. Do not read
445472
// from, or write to, this connection; that will cause the TLS
446473
// connection to fail.
@@ -471,10 +498,21 @@ type CertificateRequestInfo struct {
471498
// empty slice indicates that the server has no preference.
472499
AcceptableCAs [][]byte
473500

501+
// SupportDelegatedCredential is true if the server indicated willingness
502+
// to negotiate the Delegated Credential extension.
503+
SupportsDelegatedCredential bool
504+
474505
// SignatureSchemes lists the signature schemes that the server is
475506
// willing to verify.
476507
SignatureSchemes []SignatureScheme
477508

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

@@ -742,6 +780,13 @@ type Config struct {
742780
// This feature is unstable and applications MUST NOT depend on it.
743781
CFControl interface{}
744782

783+
// SupportDelegatedCredential is true if the client or server is willing
784+
// to negotiate the delegated credential extension.
785+
// This can only be used with TLS 1.3.
786+
//
787+
// See https://tools.ietf.org/html/draft-ietf-tls-subcerts.
788+
SupportDelegatedCredential bool
789+
745790
// mutex protects sessionTicketKeys and autoSessionTicketKeys.
746791
mutex sync.RWMutex
747792
// sessionTicketKeys contains zero or more ticket keys. If set, it means the
@@ -832,6 +877,7 @@ func (c *Config) Clone() *Config {
832877
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
833878
Renegotiation: c.Renegotiation,
834879
KeyLogWriter: c.KeyLogWriter,
880+
SupportDelegatedCredential: c.SupportDelegatedCredential,
835881
CFEventHandler: c.CFEventHandler,
836882
CFControl: c.CFControl,
837883
sessionTicketKeys: c.sessionTicketKeys,
@@ -1355,6 +1401,16 @@ func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
13551401
// and is only for debugging, so a global mutex saves space.
13561402
var writerMutex sync.Mutex
13571403

1404+
// A DelegatedCredentialPair contains a Delegated Credential and its
1405+
// associated private key.
1406+
type DelegatedCredentialPair struct {
1407+
// DC is the delegated credential.
1408+
DC *DelegatedCredential
1409+
// PrivateKey is the private key used to derive the public key of
1410+
// contained in DC. PrivateKey must implement crypto.Signer.
1411+
PrivateKey crypto.PrivateKey
1412+
}
1413+
13581414
// A Certificate is a chain of one or more certificates, leaf first.
13591415
type Certificate struct {
13601416
Certificate [][]byte
@@ -1372,6 +1428,16 @@ type Certificate struct {
13721428
// SignedCertificateTimestamps contains an optional list of Signed
13731429
// Certificate Timestamps which will be served to clients that request it.
13741430
SignedCertificateTimestamps [][]byte
1431+
// DelegatedCredentials are a list of Delegated Credentials with their
1432+
// corresponding private keys, signed by the leaf certificate.
1433+
// If there are no delegated credentials, this field is nil.
1434+
DelegatedCredentials []DelegatedCredentialPair
1435+
// DelegatedCredential is the delegated credential to be used in the
1436+
// handshake.
1437+
// If there are no delegated credentials, this field is nil.
1438+
// NOTE: Do not fill this field, as it will be filled depending on
1439+
// the provided list of delegated credentials.
1440+
DelegatedCredential []byte
13751441
// Leaf is the parsed form of the leaf certificate, which may be initialized
13761442
// using x509.ParseCertificate to reduce per-handshake processing. If nil,
13771443
// 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
@@ -52,6 +52,9 @@ type Conn struct {
5252
// verifiedChains contains the certificate chains that we built, as
5353
// opposed to the ones presented by the server.
5454
verifiedChains [][]*x509.Certificate
55+
// verifiedDC contains the Delegated Credential sent by the peer (if advertised
56+
// and correctly processed), which has been verified against the leaf certificate.
57+
verifiedDC *DelegatedCredential
5558
// serverName contains the server name indicated by the client, if any.
5659
serverName string
5760
// secureRenegotiation is true if the server echoed the secure
@@ -1476,6 +1479,9 @@ func (c *Conn) connectionStateLocked() ConnectionState {
14761479
state.CipherSuite = c.cipherSuite
14771480
state.PeerCertificates = c.peerCertificates
14781481
state.VerifiedChains = c.verifiedChains
1482+
if c.verifiedDC != nil {
1483+
state.VerifiedDC = true
1484+
}
14791485
state.SignedCertificateTimestamps = c.scts
14801486
state.OCSPResponse = c.ocspResponse
14811487
state.CFControl = c.config.CFControl

0 commit comments

Comments
 (0)