Update implementation of draft-ietf-tls-subcerts to draft 02 (#108)

Drops support for delegated credentials with TLS 1.2 and adds the
protocol version and signature algorithm to the credential structure.
This commit is contained in:
Christopher Patton 2018-08-09 11:24:40 -07:00 committed by Kris Kwiatkowski
parent 77d1fbf262
commit 174a68a0fb
7 changed files with 190 additions and 224 deletions

36
13.go
View File

@ -405,10 +405,10 @@ func (hs *serverHandshakeState) sendCertificate13() error {
} }
// If hs.delegatedCredential is set (see hs.readClientHello()) then the // If hs.delegatedCredential is set (see hs.readClientHello()) then the
// server is using the delegated credential extension. In TLS 1.3, the DC is // server is using the delegated credential extension. The DC is added as an
// added as an extension to the end-entity certificate, i.e., the last // extension to the end-entity certificate, i.e., the last CertificateEntry
// CertificateEntry of Certificate.certficate_list (see // of Certificate.certficate_list. (For details, see
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-01). // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.)
if len(certEntries) > 0 && hs.clientHello.delegatedCredential && hs.delegatedCredential != nil { if len(certEntries) > 0 && hs.clientHello.delegatedCredential && hs.delegatedCredential != nil {
certEntries[0].delegatedCredential = hs.delegatedCredential certEntries[0].delegatedCredential = hs.delegatedCredential
} }
@ -1051,13 +1051,24 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
return err return err
} }
// Receive CertificateVerify message.
msg, err = c.readHandshake()
if err != nil {
return err
}
certVerifyMsg, ok := msg.(*certificateVerifyMsg)
if !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certVerifyMsg, msg)
}
// Validate the DC if present. The DC is only processed if the extension was // Validate the DC if present. The DC is only processed if the extension was
// indicated by the ClientHello; otherwise this call will result in an // indicated by the ClientHello; otherwise this call will result in an
// "illegal_parameter" alert. The call also asserts that the DC extension // "illegal_parameter" alert.
// did not appear in the ServerHello.
if len(certMsg.certificates) > 0 { if len(certMsg.certificates) > 0 {
if err := hs.processDelegatedCredentialFromServer( if err := hs.processDelegatedCredentialFromServer(
certMsg.certificates[0].delegatedCredential); err != nil { certMsg.certificates[0].delegatedCredential,
certVerifyMsg.signatureAlgorithm); err != nil {
return err return err
} }
} }
@ -1072,16 +1083,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
pk = hs.c.verifiedDc.cred.publicKey pk = hs.c.verifiedDc.cred.publicKey
} }
// Receive CertificateVerify message. // Verify the handshake signature.
msg, err = c.readHandshake()
if err != nil {
return err
}
certVerifyMsg, ok := msg.(*certificateVerifyMsg)
if !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certVerifyMsg, msg)
}
err, alertCode := verifyPeerHandshakeSignature( err, alertCode := verifyPeerHandshakeSignature(
certVerifyMsg, certVerifyMsg,
pk, pk,

View File

@ -620,16 +620,16 @@ type Config struct {
// //
// This value has no meaning for the server. // This value has no meaning for the server.
// //
// See https://tools.ietf.org/html/draft-ietf-tls-subcerts-01. // See https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
AcceptDelegatedCredential bool AcceptDelegatedCredential bool
// GetDelegatedCredential returns a DC and its private key for use in the // GetDelegatedCredential returns a DC and its private key for use in the
// delegated credential extension. The inputs to the callback are some // delegated credential extension. The inputs to the callback are some
// information parsed from the ClientHello, as well as the protocol version // information parsed from the ClientHello, as well as the protocol version
// selected by the server. This is necessary because the DC is bound to // selected by the server. This is necessary because the DC is bound to the
// protocol version in which it's used. The return value is the raw DC // protocol version in which it's used. The return value is the raw DC
// encoded in the wire format specified in // encoded in the wire format specified in
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-01. If the return // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02. If the return
// value is nil, then the server will not offer negotiate the extension. // value is nil, then the server will not offer negotiate the extension.
// //
// This value has no meaning for the client. // This value has no meaning for the client.

View File

@ -415,27 +415,21 @@ func (hs *clientHandshakeState) processCertsFromServer(certificates [][]byte) er
// processDelegatedCredentialFromServer unmarshals the delegated credential // processDelegatedCredentialFromServer unmarshals the delegated credential
// offered by the server (if present) and validates it using the peer // offered by the server (if present) and validates it using the peer
// certificate. // certificate and the signature scheme (`scheme`) indicated by the server in
func (hs *clientHandshakeState) processDelegatedCredentialFromServer(serialized []byte) error { // the "signature_scheme" extension.
func (hs *clientHandshakeState) processDelegatedCredentialFromServer(serialized []byte, scheme SignatureScheme) error {
c := hs.c c := hs.c
var dc *delegatedCredential var dc *delegatedCredential
var err error var err error
if serialized != nil { if serialized != nil {
// Assert that the DC extension was indicated by the client. // Assert that the DC extension was indicated by the client.
if !hs.hello.delegatedCredential { if !hs.hello.delegatedCredential {
c.sendAlert(alertUnexpectedMessage) c.sendAlert(alertUnexpectedMessage)
return errors.New("tls: got delegated credential extension without indication") return errors.New("tls: got delegated credential extension without indication")
} }
// Assert that the DC was sent in the ServerHello in (and only in) // Parse the delegated credential.
// version 1.2.
if hs.serverHello.delegatedCredential != nil && hs.serverHello.vers != VersionTLS12 {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: ServerHello with delegated credential extension in TLS != 1.2")
}
dc, err = unmarshalDelegatedCredential(serialized) dc, err = unmarshalDelegatedCredential(serialized)
if err != nil { if err != nil {
c.sendAlert(alertDecodeError) c.sendAlert(alertDecodeError)
@ -444,12 +438,18 @@ func (hs *clientHandshakeState) processDelegatedCredentialFromServer(serialized
} }
if dc != nil && !c.config.InsecureSkipVerify { if dc != nil && !c.config.InsecureSkipVerify {
if v, err := dc.validate(c.peerCertificates[0], hs.c.vers, c.config.time()); err != nil { if v, err := dc.validate(c.peerCertificates[0], c.config.time()); err != nil {
c.sendAlert(alertIllegalParameter) c.sendAlert(alertIllegalParameter)
return fmt.Errorf("delegated credential: %s", err) return fmt.Errorf("delegated credential: %s", err)
} else if !v { } else if !v {
c.sendAlert(alertIllegalParameter) c.sendAlert(alertIllegalParameter)
return errors.New("delegated credential: signature invalid") return errors.New("delegated credential: signature invalid")
} else if dc.cred.expectedVersion != hs.c.vers {
c.sendAlert(alertIllegalParameter)
return errors.New("delegated credential: protocol version mismatch")
} else if dc.cred.expectedCertVerifyAlgorithm != scheme {
c.sendAlert(alertIllegalParameter)
return errors.New("delegated credential: signature scheme mismatch")
} }
} }
@ -477,13 +477,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
if err := hs.processCertsFromServer(certMsg.certificates); err != nil { if err := hs.processCertsFromServer(certMsg.certificates); err != nil {
return err return err
} }
// Validate the DC if present. The DC is only processed if the
// extension was indicated by the ClientHello; otherwise this call will
// result in an "illegal_parameter" alert. It also asserts that the DC
// was sent in the ServerHello if and only if TLS 1.2 is in use.
if err := hs.processDelegatedCredentialFromServer(hs.serverHello.delegatedCredential); err != nil {
return err
}
} else { } else {
// This is a renegotiation handshake. We require that the // This is a renegotiation handshake. We require that the
// server's identity (i.e. leaf certificate) is unchanged and // server's identity (i.e. leaf certificate) is unchanged and
@ -532,13 +525,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
// Set the public key used to verify the handshake. // Set the public key used to verify the handshake.
pk := c.peerCertificates[0].PublicKey pk := c.peerCertificates[0].PublicKey
// If the delegated credential extension has successfully been negotiated,
// then the ServerKeyExchange is signed with delegated credential private
// key.
if c.verifiedDc != nil {
pk = c.verifiedDc.cred.publicKey
}
skx, ok := msg.(*serverKeyExchangeMsg) skx, ok := msg.(*serverKeyExchangeMsg)
if ok { if ok {
hs.finishedHash.Write(skx.marshal()) hs.finishedHash.Write(skx.marshal())

View File

@ -759,7 +759,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8 // https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8
m.earlyData = true m.earlyData = true
case extensionDelegatedCredential: case extensionDelegatedCredential:
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-01 // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02
m.delegatedCredential = true m.delegatedCredential = true
} }
data = data[length:] data = data[length:]
@ -789,10 +789,6 @@ type serverHelloMsg struct {
secureRenegotiationSupported bool secureRenegotiationSupported bool
alpnProtocol string alpnProtocol string
// TLS 1.2. In TLS 1.3, the DC extension is included in of the end-entity
// certificate in the Certificate message.
delegatedCredential []byte
// TLS 1.3 // TLS 1.3
keyShare keyShare keyShare keyShare
psk bool psk bool
@ -828,7 +824,6 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
m.alpnProtocol == m1.alpnProtocol && m.alpnProtocol == m1.alpnProtocol &&
m.keyShare.group == m1.keyShare.group && m.keyShare.group == m1.keyShare.group &&
bytes.Equal(m.delegatedCredential, m1.delegatedCredential) &&
bytes.Equal(m.keyShare.data, m1.keyShare.data) && bytes.Equal(m.keyShare.data, m1.keyShare.data) &&
m.psk == m1.psk && m.psk == m1.psk &&
m.pskIdentity == m1.pskIdentity m.pskIdentity == m1.pskIdentity
@ -882,10 +877,6 @@ func (m *serverHelloMsg) marshal() []byte {
extensionsLength += 2 + sctLen extensionsLength += 2 + sctLen
numExtensions++ numExtensions++
} }
if dcLen := len(m.delegatedCredential); dcLen > 0 && m.vers == VersionTLS12 {
extensionsLength += 4 + dcLen
numExtensions++
}
if m.keyShare.group != 0 { if m.keyShare.group != 0 {
extensionsLength += 4 + len(m.keyShare.data) extensionsLength += 4 + len(m.keyShare.data)
numExtensions++ numExtensions++
@ -1015,13 +1006,6 @@ func (m *serverHelloMsg) marshal() []byte {
z = z[len(sct)+2:] z = z[len(sct)+2:]
} }
} }
if dcLen := len(m.delegatedCredential); dcLen > 0 && m.vers == VersionTLS12 {
binary.BigEndian.PutUint16(z, extensionDelegatedCredential)
binary.BigEndian.PutUint16(z[2:], uint16(dcLen))
z = z[4:]
copy(z, m.delegatedCredential)
z = z[dcLen:]
}
if m.keyShare.group != 0 { if m.keyShare.group != 0 {
z[0] = uint8(extensionKeyShare >> 8) z[0] = uint8(extensionKeyShare >> 8)
z[1] = uint8(extensionKeyShare) z[1] = uint8(extensionKeyShare)
@ -1209,11 +1193,6 @@ func (m *serverHelloMsg) unmarshal(data []byte) alert {
m.scts = append(m.scts, d[:sctLen]) m.scts = append(m.scts, d[:sctLen])
d = d[sctLen:] d = d[sctLen:]
} }
case extensionDelegatedCredential:
if m.vers != VersionTLS12 {
return alertUnexpectedMessage
}
m.delegatedCredential = data[:length]
case extensionKeyShare: case extensionKeyShare:
d := data[:length] d := data[:length]

View File

@ -330,11 +330,6 @@ Curves:
if dc != nil { if dc != nil {
hs.privateKey = sk hs.privateKey = sk
hs.delegatedCredential = dc hs.delegatedCredential = dc
// For TLS 1.2, the DC is an extension to the ServerHello.
if c.vers == VersionTLS12 {
hs.hello.delegatedCredential = hs.delegatedCredential
}
} }
} }

View File

@ -5,7 +5,7 @@
package tls package tls
// Delegated credentials for TLS // Delegated credentials for TLS
// (https://tools.ietf.org/html/draft-ietf-tls-subcerts-01) is an IETF Internet // (https://tools.ietf.org/html/draft-ietf-tls-subcerts-02) is an IETF Internet
// draft and proposed TLS extension. This allows a backend server to delegate // draft and proposed TLS extension. This allows a backend server to delegate
// TLS termination to a trusted frontend. If the client supports this extension, // TLS termination to a trusted frontend. If the client supports this extension,
// then the frontend may use a "delegated credential" as the signing key in the // then the frontend may use a "delegated credential" as the signing key in the
@ -14,7 +14,7 @@ package tls
// revoked; in order to mitigate risk in case the frontend is compromised, the // revoked; in order to mitigate risk in case the frontend is compromised, the
// credential is only valid for a short time (days, hours, or even minutes). // credential is only valid for a short time (days, hours, or even minutes).
// //
// This implements draft 01. This draft doesn't specify an object identifier for // This implements draft 02. This draft doesn't specify an object identifier for
// the X.509 extension; we use one assigned by Cloudflare. In addition, IANA has // the X.509 extension; we use one assigned by Cloudflare. In addition, IANA has
// not assigned an extension ID for this extension; we picked up one that's not // not assigned an extension ID for this extension; we picked up one that's not
// yet taken. // yet taken.
@ -70,8 +70,11 @@ func canDelegate(cert *x509.Certificate) bool {
// credential stores the public components of a credential. // credential stores the public components of a credential.
type credential struct { type credential struct {
// The serialized form of the credential.
raw []byte
// The amount of time for which the credential is valid. Specifically, the // The amount of time for which the credential is valid. Specifically, the
// credential expires `ValidTime` seconds after the `notBefore` of the // the credential expires `ValidTime` seconds after the `notBefore` of the
// delegation certificate. The delegator shall not issue delegated // delegation certificate. The delegator shall not issue delegated
// credentials that are valid for more than 7 days from the current time. // credentials that are valid for more than 7 days from the current time.
// //
@ -79,14 +82,14 @@ type credential struct {
// uint32 representing the duration in seconds. // uint32 representing the duration in seconds.
validTime time.Duration validTime time.Duration
// The signature scheme associated with the delegated credential public key.
expectedCertVerifyAlgorithm SignatureScheme
// The version of TLS in which the credential will be used.
expectedVersion uint16
// The credential public key. // The credential public key.
publicKey crypto.PublicKey publicKey crypto.PublicKey
// The signature scheme associated with the credential public key.
//
// NOTE(cjpatton) This is used for bookkeeping and is not actually part of
// the credential structure specified in the standard.
scheme SignatureScheme
} }
// isExpired returns true if the credential has expired. The end of the validity // isExpired returns true if the credential has expired. The end of the validity
@ -108,7 +111,7 @@ func (cred *credential) invalidTTL(start, now time.Time) bool {
// marshalSubjectPublicKeyInfo returns a DER encoded SubjectPublicKeyInfo structure // marshalSubjectPublicKeyInfo returns a DER encoded SubjectPublicKeyInfo structure
// (as defined in the X.509 standard) for the credential. // (as defined in the X.509 standard) for the credential.
func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) { func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) {
switch cred.scheme { switch cred.expectedCertVerifyAlgorithm {
case ECDSAWithP256AndSHA256, case ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384, ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512: ECDSAWithP521AndSHA512:
@ -119,19 +122,26 @@ func (cred *credential) marshalSubjectPublicKeyInfo() ([]byte, error) {
return serializedPublicKey, nil return serializedPublicKey, nil
default: default:
return nil, fmt.Errorf("unsupported signature scheme: 0x%04x", cred.scheme) return nil, fmt.Errorf("unsupported signature scheme: 0x%04x", cred.expectedCertVerifyAlgorithm)
} }
} }
// marshal encodes a credential in the wire format specified in // marshal encodes a credential in the wire format specified in
// https://tools.ietf.org/html/draft-ietf-tls-subcerts-01. // https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
func (cred *credential) marshal() ([]byte, error) { func (cred *credential) marshal() ([]byte, error) {
// Write the valid_time field. // The number of bytes comprising the DC parameters, which includes the
serialized := make([]byte, 6) // validity time (4 bytes), the signature scheme of the public key (2 bytes), and
// the protocol version (2 bytes).
paramsLen := 8
// The first 4 bytes are the valid_time, scheme, and version fields.
serialized := make([]byte, paramsLen+2)
binary.BigEndian.PutUint32(serialized, uint32(cred.validTime/time.Second)) binary.BigEndian.PutUint32(serialized, uint32(cred.validTime/time.Second))
binary.BigEndian.PutUint16(serialized[4:], uint16(cred.expectedCertVerifyAlgorithm))
binary.BigEndian.PutUint16(serialized[6:], cred.expectedVersion)
// Encode the public key and assert that the encoding is no longer than 2^16 // Encode the public key and assert that the encoding is no longer than 2^16
// bytes (per the spect). // bytes (per the spec).
serializedPublicKey, err := cred.marshalSubjectPublicKeyInfo() serializedPublicKey, err := cred.marshalSubjectPublicKeyInfo()
if err != nil { if err != nil {
return nil, err return nil, err
@ -140,68 +150,58 @@ func (cred *credential) marshal() ([]byte, error) {
return nil, errors.New("public key is too long") return nil, errors.New("public key is too long")
} }
// Write the length of the public_key field. // The next 2 bytes are the length of the public key field.
binary.BigEndian.PutUint16(serialized[4:], uint16(len(serializedPublicKey))) binary.BigEndian.PutUint16(serialized[paramsLen:], uint16(len(serializedPublicKey)))
// Write the public key. // The remaining bytes are the public key itself.
return append(serialized, serializedPublicKey...), nil serialized = append(serialized, serializedPublicKey...)
cred.raw = serialized
return serialized, nil
} }
// unmarshalCredential decodes a credential and returns it. // unmarshalCredential decodes a credential and returns it.
func unmarshalCredential(serialized []byte) (*credential, error) { func unmarshalCredential(serialized []byte) (*credential, error) {
// Bytes 0-3 are the validity time field; bytes 4-6 are the length of the // The number of bytes comprising the DC parameters.
// serialized SubjectPublicKeyInfo. paramsLen := 8
if len(serialized) < 6 {
if len(serialized) < paramsLen+2 {
return nil, errors.New("credential is too short") return nil, errors.New("credential is too short")
} }
// Parse the validity time. // Parse the valid_time, scheme, and version fields.
validTime := time.Duration(binary.BigEndian.Uint32(serialized)) * time.Second validTime := time.Duration(binary.BigEndian.Uint32(serialized)) * time.Second
scheme := SignatureScheme(binary.BigEndian.Uint16(serialized[4:]))
version := binary.BigEndian.Uint16(serialized[6:])
// Parse the SubjectPublicKeyInfo. // Parse the SubjectPublicKeyInfo.
pk, scheme, err := unmarshalSubjectPublicKeyInfo(serialized[6:]) pk, err := x509.ParsePKIXPublicKey(serialized[paramsLen+2:])
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &credential{validTime, pk, scheme}, nil if _, ok := pk.(*ecdsa.PublicKey); !ok {
} return nil, fmt.Errorf("unsupported delegation key type: %T", pk)
// unmarshalSubjectPublicKeyInfo parses a DER encoded SubjectPublicKeyInfo
// structure into a public key and its corresponding algorithm.
func unmarshalSubjectPublicKeyInfo(serialized []byte) (crypto.PublicKey, SignatureScheme, error) {
publicKey, err := x509.ParsePKIXPublicKey(serialized)
if err != nil {
return nil, 0, err
} }
switch pk := publicKey.(type) { return &credential{
case *ecdsa.PublicKey: raw: serialized,
curveName := pk.Curve.Params().Name validTime: validTime,
if curveName == "P-256" { expectedCertVerifyAlgorithm: scheme,
return pk, ECDSAWithP256AndSHA256, nil expectedVersion: version,
} else if curveName == "P-384" { publicKey: pk,
return pk, ECDSAWithP384AndSHA384, nil }, nil
} else if curveName == "P-521" {
return pk, ECDSAWithP521AndSHA512, nil
} else {
return nil, 0, fmt.Errorf("curve %s s not supported", curveName)
}
default:
return nil, 0, fmt.Errorf("unsupported delgation key type: %T", pk)
}
} }
// getCredentialLen returns the number of bytes comprising the serialized // getCredentialLen returns the number of bytes comprising the serialized
// credential that starts at the beginning of the input slice. It returns an // credential that starts at the beginning of the input slice. It returns an
// error if the input is too short to contain a credential. // error if the input is too short to contain a credential.
func getCredentialLen(serialized []byte) (int, error) { func getCredentialLen(serialized []byte) (int, error) {
if len(serialized) < 6 { paramsLen := 8
if len(serialized) < paramsLen+2 {
return 0, errors.New("credential is too short") return 0, errors.New("credential is too short")
} }
// First 4 bytes is the validity time. // First several bytes are the valid_time, scheme, and version fields.
serialized = serialized[4:] serialized = serialized[paramsLen:]
// The next 2 bytes are the length of the serialized public key. // The next 2 bytes are the length of the serialized public key.
serializedPublicKeyLen := int(binary.BigEndian.Uint16(serialized)) serializedPublicKeyLen := int(binary.BigEndian.Uint16(serialized))
@ -211,7 +211,7 @@ func getCredentialLen(serialized []byte) (int, error) {
return 0, errors.New("public key of credential is too short") return 0, errors.New("public key of credential is too short")
} }
return 6 + serializedPublicKeyLen, nil return paramsLen + 2 + serializedPublicKeyLen, nil
} }
// delegatedCredential stores a credential and its delegation. // delegatedCredential stores a credential and its delegation.
@ -222,7 +222,7 @@ type delegatedCredential struct {
cred *credential cred *credential
// The signature scheme used to sign the credential. // The signature scheme used to sign the credential.
scheme SignatureScheme algorithm SignatureScheme
// The credential's delegation. // The credential's delegation.
signature []byte signature []byte
@ -246,7 +246,7 @@ func ensureCertificateHasLeaf(cert *Certificate) error {
// validate checks that that the signature is valid, that the credential hasn't // validate checks that that the signature is valid, that the credential hasn't
// expired, and that the TTL is valid. It also checks that certificate can be // expired, and that the TTL is valid. It also checks that certificate can be
// used for delegation. // used for delegation.
func (dc *delegatedCredential) validate(cert *x509.Certificate, vers uint16, now time.Time) (bool, error) { func (dc *delegatedCredential) validate(cert *x509.Certificate, now time.Time) (bool, error) {
// Check that the cert can delegate. // Check that the cert can delegate.
if !canDelegate(cert) { if !canDelegate(cert) {
return false, errNoDelegationUsage return false, errNoDelegationUsage
@ -261,15 +261,16 @@ func (dc *delegatedCredential) validate(cert *x509.Certificate, vers uint16, now
} }
// Prepare the credential for verification. // Prepare the credential for verification.
hash := getHash(dc.scheme) rawCred, err := dc.cred.marshal()
in, err := prepareDelegation(hash, dc.cred, cert.Raw, dc.scheme, vers)
if err != nil { if err != nil {
return false, err return false, err
} }
hash := getHash(dc.algorithm)
in := prepareDelegation(hash, rawCred, cert.Raw, dc.algorithm)
// TODO(any) This code overlaps signficantly with verifyHandshakeSignature() // TODO(any) This code overlaps significantly with verifyHandshakeSignature()
// in ../auth.go. This should be refactored. // in ../auth.go. This should be refactored.
switch dc.scheme { switch dc.algorithm {
case ECDSAWithP256AndSHA256, case ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384, ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512: ECDSAWithP521AndSHA512:
@ -285,7 +286,7 @@ func (dc *delegatedCredential) validate(cert *x509.Certificate, vers uint16, now
default: default:
return false, fmt.Errorf( return false, fmt.Errorf(
"unsupported signature scheme: 0x%04x", dc.scheme) "unsupported signature scheme: 0x%04x", dc.algorithm)
} }
} }
@ -325,7 +326,7 @@ func unmarshalDelegatedCredential(serialized []byte) (*delegatedCredential, erro
return &delegatedCredential{ return &delegatedCredential{
raw: serialized, raw: serialized,
cred: cred, cred: cred,
scheme: scheme, algorithm: scheme,
signature: sig, signature: sig,
}, nil }, nil
} }
@ -361,11 +362,10 @@ func getHash(scheme SignatureScheme) crypto.Hash {
} }
// prepareDelegation returns a hash of the message that the delegator is to // prepareDelegation returns a hash of the message that the delegator is to
// sign. The inputs are the credential (cred), the DER-encoded delegator // sign. The inputs are the credential (`cred`), the DER-encoded delegator
// certificate (`delegatorCert`), the signature scheme of the delegator // certificate (`delegatorCert`) and the signature scheme of the delegator
// (`delegatorScheme`), and the protocol version (`vers`) in which the credential // (`delegatorAlgorithm`).
// is to be used. func prepareDelegation(hash crypto.Hash, cred, delegatorCert []byte, delegatorAlgorithm SignatureScheme) []byte {
func prepareDelegation(hash crypto.Hash, cred *credential, delegatorCert []byte, delegatorScheme SignatureScheme, vers uint16) ([]byte, error) {
h := hash.New() h := hash.New()
// The header. // The header.
@ -373,25 +373,16 @@ func prepareDelegation(hash crypto.Hash, cred *credential, delegatorCert []byte,
h.Write([]byte("TLS, server delegated credentials")) h.Write([]byte("TLS, server delegated credentials"))
h.Write([]byte{0x00}) h.Write([]byte{0x00})
// The protocol version.
var serializedVers [2]byte
binary.BigEndian.PutUint16(serializedVers[:], uint16(vers))
h.Write(serializedVers[:])
// The delegation certificate. // The delegation certificate.
h.Write(delegatorCert) h.Write(delegatorCert)
// The credential.
h.Write(cred)
// The delegator signature scheme. // The delegator signature scheme.
var serializedScheme [2]byte var serializedScheme [2]byte
binary.BigEndian.PutUint16(serializedScheme[:], uint16(delegatorScheme)) binary.BigEndian.PutUint16(serializedScheme[:], uint16(delegatorAlgorithm))
h.Write(serializedScheme[:]) h.Write(serializedScheme[:])
// The credential. return h.Sum(nil)
serializedCred, err := cred.marshal()
if err != nil {
return nil, err
}
h.Write(serializedCred)
return h.Sum(nil), nil
} }

View File

@ -16,46 +16,46 @@ import (
// A PEM-encoded "delegation certificate", an X.509 certificate with the // A PEM-encoded "delegation certificate", an X.509 certificate with the
// DelegationUsage extension. The extension is defined in // DelegationUsage extension. The extension is defined in
// specified in https://tools.ietf.org/html/draft-ietf-tls-subcerts-01. // specified in https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
var dcDelegationCertPEM = `-----BEGIN CERTIFICATE----- var dcDelegationCertPEM = `-----BEGIN CERTIFICATE-----
MIIBdzCCAR2gAwIBAgIQLVIvEpo0/0TzRja4ImvB1TAKBggqhkjOPQQDAjASMRAw MIIBejCCASGgAwIBAgIQXXtl0v50W2OadoW0QwLUlzAKBggqhkjOPQQDAjAUMRIw
DgYDVQQKEwdBY21lIENvMB4XDTE4MDcwMzE2NTE1M1oXDTE5MDcwMzE2NTE1M1ow EAYDVQQKEwlBY21lIEluYy4wHhcNMTgwNzMwMjAxMTE5WhcNMTgwODA2MjAxMTE5
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOhB WjAUMRIwEAYDVQQKEwlBY21lIEluYy4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
U6adaAgliLaFc1PAo9HBO4Wish1G4df3IK5EXLy+ooYfmkfzT1FxqbNLZufNYzve AATcQuuaUNJ3kqKGs4DBdJVd7zWzyGANT4uBNGVkZ2cgaDsdFnx99fGibfgoWer8
25fmpal/1VJAjpVyKq2jVTBTMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr HLt9Z+S6Hs+8bDPBHNgTR/Lfo1UwUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww
BgEFBQcDATAMBgNVHRMBAf8EAjAAMA8GA1UdEQQIMAaHBH8AAAEwDQYJKwYBBAGC CgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwR/AAABMA0GCSsG
2kssBAAwCgYIKoZIzj0EAwIDSAAwRQIhAPNwRk6cygm6zO5rjOzohKYWS+1KuWCM AQQBgtpLLAQAMAoGCCqGSM49BAMCA0cAMEQCIEMdIkwwmzQAJ6RSDT3wcrsySx2B
OetDIvU4mdyoAiAGN97y3GJccYn9ZOJS4UOqhr9oO8PuZMLgdq4OrMRiiA== 5Lvx5HGzc43Fgu9eAiAi4sFXnizFBVUL43qXZBq4ARw17o0JW3/7eec1xttQhw==
-----END CERTIFICATE----- -----END CERTIFICATE-----
` `
// The PEM-encoded "delegation key", the secret key associated with the // The PEM-encoded "delegation key", the secret key associated with the
// delegation certificate. // delegation certificate. This is a key for ECDSA with P256 and SHA256.
var dcDelegationKeyPEM = `-----BEGIN EC PRIVATE KEY----- var dcDelegationKeyPEM = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJDVlo+sJolMcNjMkfCGDUjMJcE4UgclcXGCrOtbJAi2oAoGCCqGSM49 MHcCAQEEIAS/pGktmxK1hlt3gF4N2nkMrJnoZihvOO63nnNcxXQroAoGCCqGSM49
AwEHoUQDQgAE6EFTpp1oCCWItoVzU8Cj0cE7haKyHUbh1/cgrkRcvL6ihh+aR/NP AwEHoUQDQgAE3ELrmlDSd5KihrOAwXSVXe81s8hgDU+LgTRlZGdnIGg7HRZ8ffXx
UXGps0tm581jO97bl+alqX/VUkCOlXIqrQ== om34KFnq/By7fWfkuh7PvGwzwRzYE0fy3w==
-----END EC PRIVATE KEY----- -----END EC PRIVATE KEY-----
` `
// A certificate without the DelegationUsage extension. // A certificate without the DelegationUsage extension.
var dcCertPEM = `-----BEGIN CERTIFICATE----- var dcCertPEM = `-----BEGIN CERTIFICATE-----
MIIBaTCCAQ6gAwIBAgIQSUo+9uaip3qCW+1EPeHZgDAKBggqhkjOPQQDAjASMRAw MIIBajCCAQ+gAwIBAgIRAMUg/VFqJaWWJwZ9iHoMjqIwCgYIKoZIzj0EAwIwEjEQ
DgYDVQQKEwdBY21lIENvMB4XDTE4MDYxMjIzNDAyNloXDTE5MDYxMjIzNDAyNlow MA4GA1UEChMHQWNtZSBDbzAeFw0xODA3MzAyMDExMTlaFw0xOTA3MzAyMDExMTla
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLf7 MBIxEDAOBgNVBAoTB0FjbWUgQ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATA
fiznPVdc3V5mM3ymswU2/IoJaq/deA6dgdj50ozdYyRiAPjxzcz9zRsZw1apTF/h n+oeWSvSNHhEskSRgkkerCQDoV/NA+r3S5AtCOFT5AYLt8xltSTWerFI/YlZLIcL
yNfiLhV4EE1VrwXcT5OjRjBEMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr xlJPT7T+XpBnfS6xaAuxo0YwRDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI
BgEFBQcDATAMBgNVHRMBAf8EAjAAMA8GA1UdEQQIMAaHBH8AAAEwCgYIKoZIzj0E KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwR/AAABMAoGCCqGSM49
AwIDSQAwRgIhANXG0zmrVtQBK0TNZZoEGMOtSwxmiZzXNe+IjdpxO3TiAiEA5VYx BAMCA0kAMEYCIQCFGWnoJmwH1rxNCKBJWVDBKDTSsYhySRk4h9RPyR8bUwIhAJxc
0CWJq5zqpVXbJMeKVMASo2nrXZoA6NhJvFQ97hw= KFyrowMTan791RJnyANH/4uYhmvkfhfrFGSTXUli
-----END CERTIFICATE----- -----END CERTIFICATE-----
` `
// The secret key associatted with dcCertPEM. // The secret key associatted with dcCertPEM.
var dcKeyPEM = `-----BEGIN EC PRIVATE KEY----- var dcKeyPEM = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIMw9DiOfGI1E/XZrrW2huZSjYi0EKwvVjAe+dYtyFsSloAoGCCqGSM49 MHcCAQEEIEP82pOhzx0tKkky9t0OmUo9MHgmfdAHxDN2cHmWGqOhoAoGCCqGSM49
AwEHoUQDQgAEt/t+LOc9V1zdXmYzfKazBTb8iglqr914Dp2B2PnSjN1jJGIA+PHN AwEHoUQDQgAEwJ/qHlkr0jR4RLJEkYJJHqwkA6FfzQPq90uQLQjhU+QGC7fMZbUk
zP3NGxnDVqlMX+HI1+IuFXgQTVWvBdxPkw== 1nqxSP2JWSyHC8ZST0+0/l6QZ30usWgLsQ==
-----END EC PRIVATE KEY----- -----END EC PRIVATE KEY-----
` `
@ -71,40 +71,50 @@ type dcTestDC struct {
// Test data used for testing the TLS handshake with the delegated creedential // Test data used for testing the TLS handshake with the delegated creedential
// extension. The PEM block encodes a DER encoded slice of dcTestDC's. // extension. The PEM block encodes a DER encoded slice of dcTestDC's.
var dcTestDCsPEM = `-----BEGIN DC TEST DATA----- var dcTestDCsPEM = `-----BEGIN DC TEST DATA-----
MIIGQzCCAToTBXRsczEyAgIDAwICBAMEga0ACUp3AFswWTATBgcqhkjOPQIBBggq MIIIPDCCAUETCXRsczEzcDI1NgICfxcCAgQDBIGwAAk6gAQDfxcAWzBZMBMGByqG
hkjOPQMBBwNCAAQ9z9RDrMvyRzPOkw9SK2S/O5DiwfRNjAwYcq7e/sKdN0ZcSP1K SM49AgEGCCqGSM49AwEHA0IABDFeK+EcMQWKDM6xZJqHEHLcIWE0iHTAL1xAB5r6
se/+ZDXfruwyviuq+h5oSzWPoejHHx7jnwBTBAMASDBGAiEAtYH/x0Ue2B2a34WG bkm7GLlz1HLWcTy28PNsb9KQLV3Yeay2WYA2d2zGQjNbEhcEAwBHMEUCIQDnXyP4
Oj9wVPJeyYBXxIbUrCdqfoQzq2oCIQCJYtwRE9UJvAQKve4ulJOr+zGjN8jG4tdg dOv3a20MDpRX2aNDoY5oQa+tS3Nwhldcwq5F0AIgRtHijJhhCNYFIEygT3VDUqiD
9YSb/yOQgQR5MHcCAQEEIOBCmSaGwzZtXOJRCbA03GgxegoSV5GasVjJlttpUAPh tr9HO2rW7nd8htAkfAsEeTB3AgEBBCA0Xr2CPlkYhONrwcKzIMa4049vzIJqEKrq
oAoGCCqGSM49AwEHoUQDQgAEPc/UQ6zL8kczzpMPUitkvzuQ4sH0TYwMGHKu3v7C lyj8wbBwsKAKBggqhkjOPQMBB6FEA0IABDFeK+EcMQWKDM6xZJqHEHLcIWE0iHTA
nTdGXEj9SrHv/mQ1367sMr4rqvoeaEs1j6Hoxx8e458AUzCCATgTBXRsczEzAgJ/ L1xAB5r6bkm7GLlz1HLWcTy28PNsb9KQLV3Yeay2WYA2d2zGQjNbEhcwggHsEwl0
FwICBAMEgasACUp3AFswWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARcqxvo0JO1 bHMxM3A1MjECAn8XAgIGAwSB9AAJOoAGA38XAJ4wgZswEAYHKoZIzj0CAQYFK4EE
yiXoBhV/T2hmkUhwMnP5XtTJCGGfI0ILShmTeuTcScmiTuzo3qA/HVmr2sdnfBvx ACMDgYYABAGxCv0cyyjBcTIJL793BaStJjp6fgKkycPmXcJJzakqFzh6BU1X9btL
zhQOYXrsfTNxBAMARjBEAiB8xrQk3DRFkACXMLZTJ1jAml/2zj/Vqc4cav0xi9zk E6fE9vgmSJqVKePXe71nyUyk2LvTehXXbwFLXLqLarKEWoXCjlW4O2fxFlej/ptN
dQIgDSrNtkK1akKGeNt7Iquv0lLZgyLp1i+rwQwOTdbw6ScEeTB3AgEBBCC7JqZM 5gimonDr3doIGIozd3sEOzJhxP5GK/tRAF+yX5Z+3jN+K6DAkQ931+6RGwQDAEgw
yIFzXdTmuYIUqOGQ602V4VtQttg/Oh2NuSCteKAKBggqhkjOPQMBB6FEA0IABFyr RgIhAOJkigrFnvc+aqwMLf3Hfroh8I9wP3Z5Rt/4yB4cQVQpAiEA//3uE/UiHNii
G+jQk7XKJegGFX9PaGaRSHAyc/le1MkIYZ8jQgtKGZN65NxJyaJO7OjeoD8dWava IW6lqZLiBkmqKGsYRH3B99vA5BDksowEgd8wgdwCAQEEQgHfmi6BaFRkLAqyNJOF
x2d8G/HOFA5heux9M3EwggE9EwdpbnZhbGlkAgMA/wACAgQDBIGtAAlKdwBbMFkw VRqVkEaB9KfKjjyN9HlAohLxftCNhd/VZ3DlZy6YRzp6WXc2192I518BDHW/IzGU
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdlKK5Dv35nOxaTS0LGqBnQstHSqVFIoZ D/i+uqAHBgUrgQQAI6GBiQOBhgAEAbEK/RzLKMFxMgkvv3cFpK0mOnp+AqTJw+Zd
FsHGdXuR2N4pAoMkUF0w94+BZ/KHm1Djv/ugELm0aMHp8SBbJV3JVQQDAEgwRgIh wknNqSoXOHoFTVf1u0sTp8T2+CZImpUp49d7vWfJTKTYu9N6FddvAUtcuotqsoRa
AL/gfo5JGFV/pNZe4ktc2yO41a4ipFvb8WIv8qn29gjoAiEAw1DB1EelNEfjl+fp hcKOVbg7Z/EWV6P+m03mCKaicOvd2ggYijN3ewQ7MmHE/kYr+1EAX7Jfln7eM34r
CDMT+mdFKRDMnXTRrM2K8gI1QsEEeTB3AgEBBCCdu3sMkUAsbHAcYOZ9wJnQujWr oMCRD3fX7pEbMIIBQBMHYmFkdmVycwIDAP8AAgIEAwSBsAAJOoAEA/8AAFswWTAT
5UqPQotIys9hqJ3PTaAKBggqhkjOPQMBB6FEA0IABHZSiuQ79+ZzsWk0tCxqgZ0L BgcqhkjOPQIBBggqhkjOPQMBBwNCAARETBkaUfQtOP1XaLtZhFSRcuUR9x3w6G6+
LR0qlRSKGRbBxnV7kdjeKQKDJFBdMPePgWfyh5tQ47/7oBC5tGjB6fEgWyVdyVUw JpXMkxU40b2F1tPb0CwrgYigfPXDWvntJeXrD9wIRZZhPRzUT6XiBAMARzBFAiEA
ggFAEwttYWxmb3JtZWQxMgICAwMCAgQDBIGtAAlKdwBbMFkwEwYHKoZIzj0CAQYI zNATGeXl4LwPlpDETFN8DDicBYextKGB+WQIhHxgsHoCIC/CtAXNQMpCa3juMt4b
KoZIzj0DAQcDQgAEn8Rr7eedTHuGJjv7mglv7nJrV7KMDE2A33v8EAMGU+AvRq2m Y5+yZPp+JoyLy8tcjk2xiN2aBHkwdwIBAQQgz80DZbIUuT9ehWBR1qYJlEZrAq7v
XNIoc+a6JxpYetjTnT3s8TW4qWXq9dJzw3VAVgQDAEgwRgIhAKEVbifQNllzjTwX TMAN4Q0NyrFp7zGgCgYIKoZIzj0DAQehRANCAARETBkaUfQtOP1XaLtZhFSRcuUR
s5CUsN42Eo8R8WTiFNSbhJmqDKsCAiEA4cqhQA2Cop2WtuOAG3aMnO9MKAPxLeUc 9x3w6G6+JpXMkxU40b2F1tPb0CwrgYigfPXDWvntJeXrD9wIRZZhPRzUT6XiMIIB
fEmnM658P3kEeTB3AgEBBCAR4EtE/WbJIc6id2bLOR4xgis7mzOWJdiRAiGKNshB PhMGYmFka2V5AgJ/FwICBAMEgbAACTqABAN/FwBbMFkwEwYHKoZIzj0CAQYIKoZI
iKAKBggqhkjOPQMBB6FEA0IABF/2VNK9W/QsMdiBn3qdG19trNMAFvVM0JbeBHin zj0DAQcDQgAEjnv1221/Sz0Cy5TY9vb3Ghbv8u2IX5KCqPjqOqA7y95dTzFfMK4m
gl/7WVXGBk0WzgvmA0qSH4Bc7d8z8n3JKdmByYPgpxTjbFUwggFAEwttYWxmb3Jt HRir0MpyL3iWynQOjTnTmIpMZ/kHevLgkQQDAEcwRQIhALXL680Hjym5FT528pzg
ZWQxMwICAwQCAgQDBIGtAAlKdwBbMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE OuVhgig7OtdsAXQKbb7zPPcWAiAqm0xOXZzNYzNd5+LqGfFBqPO7iNww66O7xgZ3
FGWBYWhjdr9al2imEFlGx+r0tQdcEqL/Qtf7imo/z5fr2z+tG3TawC0QeHU6uyRX cetE0QR5MHcCAQEEIBFFJo/bdQIOU6/DRQDQHos0F+U/XQxdFM9qISHFTgdYoAoG
8zPvZGJ/Xps5q3RBI0tVggQDAEgwRgIhAMv30xlPKpajZuahNRHx3AlGtM9mNt5K CCqGSM49AwEHoUQDQgAEXaL0NN9moDG/TEYEmm6whE9HQvpcV9uR5n44bMj9T1g/
WbWvhqDXhlVgAiEAxqI0K57Y9p9lLC8cSoy2arppjPMWKkVA4G2ck2n4NwUEeTB3 xzN3cC0L30rr9lYCJ6OvpKRbZp9CCvIxV7UNooaQSTCCAT0TBmJhZHNpZwICfxcC
AgEBBCCaruxlln2bwAX0EGy4oge0EpSDObt8Z+pNqx1nxDYyYKAKBggqhkjOPQMB AgQDBIGvAAk6gAQDfxcAWzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAm0yTyE
B6FEA0IABBYfBBlgDC3TLkbJJTTJaZMXiXvDkUiWMeYFpcbAHdvMI8zoS6b++Zgc r5D/+QYjxnfF6gPoZZ/5HfX3pV1hcpk7DW15QynGvZw6dcTlV6d+iPY64Jwpt/pW
HJbn52hmB027JEIMPWsxKxPkr7udk7Q= HdCdnD04h402V44EAwBGMEQCIFz0zku+EtZIOnGkDbav+yzyuRvgtZOaKIgjzmxs
XLXUAiBxhtDEMJFxVCFbHPsJfrE0d3tSaNiEegJcpFxQXEt+IQR5MHcCAQEEIMG1
LPKXbAPq7QLoIpxIPStrsRmxJmXTxRe/7ZeIwbADoAoGCCqGSM49AwEHoUQDQgAE
CbTJPISvkP/5BiPGd8XqA+hln/kd9felXWFymTsNbXlDKca9nDp1xOVXp36I9jrg
nCm3+lYd0J2cPTiHjTZXjjCCATwTBXRsczEyAgIDAwICBAMEga8ACTqABAMDAwBb
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEs/IKFXT7LH1tKHSrXCjk7wIhIigk
YnMNVKX3cvsXUhdDd115Cxwdd3K4gnya9q22daPFewrF+lO9KPv+PIbjyAQDAEYw
RAIgfAVo9yv5NdJLSa5TpvDViDxczalm7EXJP3Dh60EaevICIFCnJKHt8ZZ0i12o
nwvq52TI5LG7tTTKXSc7Un+blF62BHkwdwIBAQQgY00t5UvHWA9b01Alvn9bogNn
4O8MgvWOFEQ/BwTiKH+gCgYIKoZIzj0DAQehRANCAASz8goVdPssfW0odKtcKOTv
AiEiKCRicw1Upfdy+xdSF0N3XXkLHB13criCfJr2rbZ1o8V7CsX6U70o+/48huPI
-----END DC TEST DATA----- -----END DC TEST DATA-----
` `
@ -127,10 +137,6 @@ func init() {
panic("failed to unmarshal DC test ASN.1 data") panic("failed to unmarshal DC test ASN.1 data")
} }
// Use a static time for testing. This is the point at which the test DCs
// were generated.
dcTestNow = time.Date(2018, 07, 03, 18, 0, 0, 234234, time.UTC)
// The base configuration for the client and server. // The base configuration for the client and server.
dcTestConfig = &Config{ dcTestConfig = &Config{
Time: func() time.Time { Time: func() time.Time {
@ -163,6 +169,11 @@ func init() {
panic(err) panic(err)
} }
// For testing purposes, use the point at which the test DCs were generated
// as the current time. This is the same as the time at which the
// delegation certificate was generated.
dcTestNow = dcTestDelegationCert.Leaf.NotBefore
// Make these roots of these certificates the client's trusted CAs. // Make these roots of these certificates the client's trusted CAs.
dcTestConfig.RootCAs = x509.NewCertPool() dcTestConfig.RootCAs = x509.NewCertPool()
@ -251,17 +262,16 @@ var dcTesters = []struct {
expectDC bool expectDC bool
name string name string
}{ }{
{true, true, false, VersionTLS12, VersionTLS12, 0, "tls12", true, true, "tls12"}, {true, true, false, VersionTLS13, VersionTLS13, 0, "tls13p256", true, true, "tls13"},
{true, true, false, VersionTLS13, VersionTLS13, 0, "tls13", true, true, "tls13"}, {true, true, false, VersionTLS13, VersionTLS13, 0, "tls13p521", true, true, "tls13"},
{true, true, false, VersionTLS12, VersionTLS12, 0, "malformed12", false, false, "tls12, malformed dc"}, {true, false, false, VersionTLS13, VersionTLS13, 0, "tls13p256", true, false, "server no dc"},
{true, true, false, VersionTLS13, VersionTLS13, 0, "malformed13", false, false, "tls13, malformed dc"}, {true, true, false, VersionTLS12, VersionTLS13, 0, "tls13p256", true, false, "client old"},
{true, true, true, VersionTLS12, VersionTLS12, 0, "invalid", true, true, "tls12, invalid dc, skip verify"}, {true, true, false, VersionTLS13, VersionTLS12, 0, "tls13p256", true, false, "server old"},
{true, true, true, VersionTLS13, VersionTLS13, 0, "invalid", true, true, "tls13, invalid dc, skip verify"}, {true, true, false, VersionTLS13, VersionTLS13, 0, "badkey", false, false, "bad key"},
{false, true, false, VersionTLS12, VersionTLS12, 0, "tls12", true, false, "client no dc"}, {true, true, true, VersionTLS13, VersionTLS13, 0, "badsig", true, true, "bad key, skip verify"},
{true, false, false, VersionTLS12, VersionTLS12, 0, "tls12", true, false, "server no dc"},
{true, true, false, VersionTLS11, VersionTLS12, 0, "tls12", true, false, "client old"},
{true, true, false, VersionTLS12, VersionTLS11, 0, "tls12", true, false, "server old"},
{true, true, false, VersionTLS13, VersionTLS13, dcMaxTTL, "tls13", false, false, "expired dc"}, {true, true, false, VersionTLS13, VersionTLS13, dcMaxTTL, "tls13", false, false, "expired dc"},
{true, true, false, VersionTLS13, VersionTLS13, 0, "badvers", false, false, "dc wrong version"},
{true, true, false, VersionTLS12, VersionTLS12, 0, "tls12", true, false, "tls12"},
} }
// Tests the handshake with the delegated credential extension for each test // Tests the handshake with the delegated credential extension for each test
@ -283,6 +293,9 @@ func TestDCHandshake(t *testing.T) {
if tester.serverDC { if tester.serverDC {
serverConfig.GetDelegatedCredential = func( serverConfig.GetDelegatedCredential = func(
ch *ClientHelloInfo, vers uint16) ([]byte, crypto.PrivateKey, error) { ch *ClientHelloInfo, vers uint16) ([]byte, crypto.PrivateKey, error) {
if vers < VersionTLS13 {
return nil, nil, nil
}
for _, test := range dcTestDCs { for _, test := range dcTestDCs {
if test.Name == tester.dcTestName { if test.Name == tester.dcTestName {
sk, err := x509.ParseECPrivateKey(test.PrivateKey) sk, err := x509.ParseECPrivateKey(test.PrivateKey)