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:
parent
77d1fbf262
commit
174a68a0fb
36
13.go
36
13.go
@ -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,
|
||||||
|
@ -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.
|
||||||
|
@ -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())
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
151
subcerts.go
151
subcerts.go
@ -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
|
|
||||||
}
|
}
|
||||||
|
157
subcerts_test.go
157
subcerts_test.go
@ -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-----
|
||||||
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
|
||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user