Implement TLS Channel ID in runner.go
Change-Id: Ia349c7a7cdcfd49965cd0c4d6cf81a76fbffb696 Reviewed-on: https://boringssl-review.googlesource.com/1604 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
committed by
Adam Langley
parent
f9b96fa493
commit
d30a990850
+27
-13
@@ -7,6 +7,7 @@ package main
|
||||
import (
|
||||
"container/list"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
@@ -47,19 +48,20 @@ const (
|
||||
|
||||
// TLS handshake message types.
|
||||
const (
|
||||
typeClientHello uint8 = 1
|
||||
typeServerHello uint8 = 2
|
||||
typeHelloVerifyRequest uint8 = 3
|
||||
typeNewSessionTicket uint8 = 4
|
||||
typeCertificate uint8 = 11
|
||||
typeServerKeyExchange uint8 = 12
|
||||
typeCertificateRequest uint8 = 13
|
||||
typeServerHelloDone uint8 = 14
|
||||
typeCertificateVerify uint8 = 15
|
||||
typeClientKeyExchange uint8 = 16
|
||||
typeFinished uint8 = 20
|
||||
typeCertificateStatus uint8 = 22
|
||||
typeNextProtocol uint8 = 67 // Not IANA assigned
|
||||
typeClientHello uint8 = 1
|
||||
typeServerHello uint8 = 2
|
||||
typeHelloVerifyRequest uint8 = 3
|
||||
typeNewSessionTicket uint8 = 4
|
||||
typeCertificate uint8 = 11
|
||||
typeServerKeyExchange uint8 = 12
|
||||
typeCertificateRequest uint8 = 13
|
||||
typeServerHelloDone uint8 = 14
|
||||
typeCertificateVerify uint8 = 15
|
||||
typeClientKeyExchange uint8 = 16
|
||||
typeFinished uint8 = 20
|
||||
typeCertificateStatus uint8 = 22
|
||||
typeNextProtocol uint8 = 67 // Not IANA assigned
|
||||
typeEncryptedExtensions uint8 = 203 // Not IANA assigned
|
||||
)
|
||||
|
||||
// TLS compression types.
|
||||
@@ -77,6 +79,7 @@ const (
|
||||
extensionSessionTicket uint16 = 35
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
extensionChannelID uint16 = 30032 // not IANA assigned
|
||||
)
|
||||
|
||||
// TLS signaling cipher suite values
|
||||
@@ -166,6 +169,7 @@ type ConnectionState struct {
|
||||
ServerName string // server name requested by client, if any (server side only)
|
||||
PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
|
||||
VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
|
||||
ChannelID *ecdsa.PublicKey // the channel ID for this connection
|
||||
}
|
||||
|
||||
// ClientAuthType declares the policy the server will follow for
|
||||
@@ -187,6 +191,7 @@ type ClientSessionState struct {
|
||||
vers uint16 // SSL/TLS version negotiated for the session
|
||||
cipherSuite uint16 // Ciphersuite negotiated for the session
|
||||
masterSecret []byte // MasterSecret generated by client on a full handshake
|
||||
handshakeHash []byte // Handshake hash for Channel ID purposes.
|
||||
serverCertificates []*x509.Certificate // Certificate chain presented by the server
|
||||
}
|
||||
|
||||
@@ -307,6 +312,15 @@ type Config struct {
|
||||
// be used.
|
||||
CurvePreferences []CurveID
|
||||
|
||||
// ChannelID contains the ECDSA key for the client to use as
|
||||
// its TLS Channel ID.
|
||||
ChannelID *ecdsa.PrivateKey
|
||||
|
||||
// RequestChannelID controls whether the server requests a TLS
|
||||
// Channel ID. If negotiated, the client's public key is
|
||||
// returned in the ConnectionState.
|
||||
RequestChannelID bool
|
||||
|
||||
// Bugs specifies optional misbehaviour to be used for testing other
|
||||
// implementations.
|
||||
Bugs ProtocolBugs
|
||||
|
||||
@@ -9,6 +9,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
@@ -47,6 +48,8 @@ type Conn struct {
|
||||
clientProtocol string
|
||||
clientProtocolFallback bool
|
||||
|
||||
channelID *ecdsa.PublicKey
|
||||
|
||||
// input/output
|
||||
in, out halfConn // in.Mutex < out.Mutex
|
||||
rawInput *block // raw input, right off the wire
|
||||
@@ -937,6 +940,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
|
||||
m = new(finishedMsg)
|
||||
case typeHelloVerifyRequest:
|
||||
m = new(helloVerifyRequestMsg)
|
||||
case typeEncryptedExtensions:
|
||||
m = new(encryptedExtensionsMsg)
|
||||
default:
|
||||
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
@@ -1104,6 +1109,7 @@ func (c *Conn) ConnectionState() ConnectionState {
|
||||
state.PeerCertificates = c.peerCertificates
|
||||
state.VerifiedChains = c.verifiedChains
|
||||
state.ServerName = c.serverName
|
||||
state.ChannelID = c.channelID
|
||||
}
|
||||
|
||||
return state
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
@@ -54,6 +55,7 @@ func (c *Conn) clientHandshake() error {
|
||||
nextProtoNeg: len(c.config.NextProtos) > 0,
|
||||
secureRenegotiation: true,
|
||||
duplicateExtension: c.config.Bugs.DuplicateExtension,
|
||||
channelIDSupported: c.config.ChannelID != nil,
|
||||
}
|
||||
|
||||
if c.config.Bugs.SendClientVersion != 0 {
|
||||
@@ -238,7 +240,7 @@ NextCipherSuite:
|
||||
if err := hs.readFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendFinished(); err != nil {
|
||||
if err := hs.sendFinished(isResume); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@@ -248,7 +250,7 @@ NextCipherSuite:
|
||||
if err := hs.establishKeys(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendFinished(); err != nil {
|
||||
if err := hs.sendFinished(isResume); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.readSessionTicket(); err != nil {
|
||||
@@ -565,6 +567,11 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
||||
return false, errors.New("server advertised unrequested NPN extension")
|
||||
}
|
||||
|
||||
if !hs.hello.channelIDSupported && hs.serverHello.channelIDRequested {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return false, errors.New("server advertised unrequested Channel ID extension")
|
||||
}
|
||||
|
||||
if hs.serverResumedSession() {
|
||||
// Restore masterSecret and peerCerts from previous state
|
||||
hs.masterSecret = hs.session.masterSecret
|
||||
@@ -619,20 +626,22 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(sessionTicketMsg, msg)
|
||||
}
|
||||
hs.writeServerHash(sessionTicketMsg.marshal())
|
||||
|
||||
hs.session = &ClientSessionState{
|
||||
sessionTicket: sessionTicketMsg.ticket,
|
||||
vers: c.vers,
|
||||
cipherSuite: hs.suite.id,
|
||||
masterSecret: hs.masterSecret,
|
||||
handshakeHash: hs.finishedHash.server.Sum(nil),
|
||||
serverCertificates: c.peerCertificates,
|
||||
}
|
||||
|
||||
hs.writeServerHash(sessionTicketMsg.marshal())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeState) sendFinished() error {
|
||||
func (hs *clientHandshakeState) sendFinished(isResume bool) error {
|
||||
c := hs.c
|
||||
|
||||
var postCCSBytes []byte
|
||||
@@ -650,6 +659,34 @@ func (hs *clientHandshakeState) sendFinished() error {
|
||||
postCCSBytes = append(postCCSBytes, nextProtoBytes...)
|
||||
}
|
||||
|
||||
if hs.serverHello.channelIDRequested {
|
||||
encryptedExtensions := new(encryptedExtensionsMsg)
|
||||
if c.config.ChannelID.Curve != elliptic.P256() {
|
||||
return fmt.Errorf("tls: Channel ID is not on P-256.")
|
||||
}
|
||||
var resumeHash []byte
|
||||
if isResume {
|
||||
resumeHash = hs.session.handshakeHash
|
||||
}
|
||||
r, s, err := ecdsa.Sign(c.config.rand(), c.config.ChannelID, hs.finishedHash.hashForChannelID(resumeHash))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
channelID := make([]byte, 128)
|
||||
writeIntPadded(channelID[0:32], c.config.ChannelID.X)
|
||||
writeIntPadded(channelID[32:64], c.config.ChannelID.Y)
|
||||
writeIntPadded(channelID[64:96], r)
|
||||
writeIntPadded(channelID[96:128], s)
|
||||
encryptedExtensions.channelID = channelID
|
||||
|
||||
c.channelID = &c.config.ChannelID.PublicKey
|
||||
|
||||
encryptedExtensionsBytes := encryptedExtensions.marshal()
|
||||
hs.writeHash(encryptedExtensionsBytes, seqno)
|
||||
seqno++
|
||||
postCCSBytes = append(postCCSBytes, encryptedExtensionsBytes...)
|
||||
}
|
||||
|
||||
finished := new(finishedMsg)
|
||||
if c.config.Bugs.EarlyChangeCipherSpec == 2 {
|
||||
finished.verifyData = hs.finishedHash.clientSum(nil)
|
||||
@@ -724,3 +761,13 @@ func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
|
||||
|
||||
return clientProtos[0], true
|
||||
}
|
||||
|
||||
// writeIntPadded writes x into b, padded up with leading zeros as
|
||||
// needed.
|
||||
func writeIntPadded(b []byte, x *big.Int) {
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
xb := x.Bytes()
|
||||
copy(b[len(b)-len(xb):], xb)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ type clientHelloMsg struct {
|
||||
signatureAndHashes []signatureAndHash
|
||||
secureRenegotiation bool
|
||||
duplicateExtension bool
|
||||
channelIDSupported bool
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||
@@ -49,7 +50,9 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||
m.ticketSupported == m1.ticketSupported &&
|
||||
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
|
||||
eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
|
||||
m.secureRenegotiation == m1.secureRenegotiation
|
||||
m.secureRenegotiation == m1.secureRenegotiation &&
|
||||
m.duplicateExtension == m1.duplicateExtension &&
|
||||
m.channelIDSupported == m1.channelIDSupported
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) marshal() []byte {
|
||||
@@ -97,6 +100,9 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
if m.duplicateExtension {
|
||||
numExtensions += 2
|
||||
}
|
||||
if m.channelIDSupported {
|
||||
numExtensions++
|
||||
}
|
||||
if numExtensions > 0 {
|
||||
extensionsLength += 4 * numExtensions
|
||||
length += 2 + extensionsLength
|
||||
@@ -260,6 +266,11 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
z[3] = 1
|
||||
z = z[5:]
|
||||
}
|
||||
if m.channelIDSupported {
|
||||
z[0] = byte(extensionChannelID >> 8)
|
||||
z[1] = byte(extensionChannelID & 0xff)
|
||||
z = z[4:]
|
||||
}
|
||||
if m.duplicateExtension {
|
||||
// Add a duplicate bogus extension at the beginning and end.
|
||||
z[0] = 0xff
|
||||
@@ -440,6 +451,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
return false
|
||||
}
|
||||
m.secureRenegotiation = true
|
||||
case extensionChannelID:
|
||||
if length > 0 {
|
||||
return false
|
||||
}
|
||||
m.channelIDSupported = true
|
||||
}
|
||||
data = data[length:]
|
||||
}
|
||||
@@ -461,6 +477,7 @@ type serverHelloMsg struct {
|
||||
ticketSupported bool
|
||||
secureRenegotiation bool
|
||||
duplicateExtension bool
|
||||
channelIDRequested bool
|
||||
}
|
||||
|
||||
func (m *serverHelloMsg) equal(i interface{}) bool {
|
||||
@@ -480,7 +497,9 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
|
||||
eqStrings(m.nextProtos, m1.nextProtos) &&
|
||||
m.ocspStapling == m1.ocspStapling &&
|
||||
m.ticketSupported == m1.ticketSupported &&
|
||||
m.secureRenegotiation == m1.secureRenegotiation
|
||||
m.secureRenegotiation == m1.secureRenegotiation &&
|
||||
m.duplicateExtension == m1.duplicateExtension &&
|
||||
m.channelIDRequested == m1.channelIDRequested
|
||||
}
|
||||
|
||||
func (m *serverHelloMsg) marshal() []byte {
|
||||
@@ -514,6 +533,9 @@ func (m *serverHelloMsg) marshal() []byte {
|
||||
if m.duplicateExtension {
|
||||
numExtensions += 2
|
||||
}
|
||||
if m.channelIDRequested {
|
||||
numExtensions++
|
||||
}
|
||||
if numExtensions > 0 {
|
||||
extensionsLength += 4 * numExtensions
|
||||
length += 2 + extensionsLength
|
||||
@@ -581,6 +603,11 @@ func (m *serverHelloMsg) marshal() []byte {
|
||||
z[3] = 1
|
||||
z = z[5:]
|
||||
}
|
||||
if m.channelIDRequested {
|
||||
z[0] = byte(extensionChannelID >> 8)
|
||||
z[1] = byte(extensionChannelID & 0xff)
|
||||
z = z[4:]
|
||||
}
|
||||
if m.duplicateExtension {
|
||||
// Add a duplicate bogus extension at the beginning and end.
|
||||
z[0] = 0xff
|
||||
@@ -671,6 +698,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
|
||||
return false
|
||||
}
|
||||
m.secureRenegotiation = true
|
||||
case extensionChannelID:
|
||||
if length > 0 {
|
||||
return false
|
||||
}
|
||||
m.channelIDRequested = true
|
||||
}
|
||||
data = data[length:]
|
||||
}
|
||||
@@ -1407,7 +1439,8 @@ func (m *helloVerifyRequestMsg) equal(i interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
return m.vers == m1.vers &&
|
||||
return bytes.Equal(m.raw, m1.raw) &&
|
||||
m.vers == m1.vers &&
|
||||
bytes.Equal(m.cookie, m1.cookie)
|
||||
}
|
||||
|
||||
@@ -1447,6 +1480,58 @@ func (m *helloVerifyRequestMsg) unmarshal(data []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type encryptedExtensionsMsg struct {
|
||||
raw []byte
|
||||
channelID []byte
|
||||
}
|
||||
|
||||
func (m *encryptedExtensionsMsg) equal(i interface{}) bool {
|
||||
m1, ok := i.(*encryptedExtensionsMsg)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return bytes.Equal(m.raw, m1.raw) &&
|
||||
bytes.Equal(m.channelID, m1.channelID)
|
||||
}
|
||||
|
||||
func (m *encryptedExtensionsMsg) marshal() []byte {
|
||||
if m.raw != nil {
|
||||
return m.raw
|
||||
}
|
||||
|
||||
length := 2 + 2 + len(m.channelID)
|
||||
|
||||
x := make([]byte, 4+length)
|
||||
x[0] = typeEncryptedExtensions
|
||||
x[1] = uint8(length >> 16)
|
||||
x[2] = uint8(length >> 8)
|
||||
x[3] = uint8(length)
|
||||
x[4] = uint8(extensionChannelID >> 8)
|
||||
x[5] = uint8(extensionChannelID & 0xff)
|
||||
x[6] = uint8(len(m.channelID) >> 8)
|
||||
x[7] = uint8(len(m.channelID) & 0xff)
|
||||
copy(x[8:], m.channelID)
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
|
||||
if len(data) != 4+2+2+128 {
|
||||
return false
|
||||
}
|
||||
m.raw = data
|
||||
if (uint16(data[4])<<8)|uint16(data[5]) != extensionChannelID {
|
||||
return false
|
||||
}
|
||||
if int(data[6])<<8|int(data[7]) != 128 {
|
||||
return false
|
||||
}
|
||||
m.channelID = data[4+2+2:]
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func eqUint16s(x, y []uint16) bool {
|
||||
if len(x) != len(y) {
|
||||
return false
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// serverHandshakeState contains details of a server handshake in progress.
|
||||
@@ -69,7 +71,7 @@ func (c *Conn) serverHandshake() error {
|
||||
if err := hs.sendFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.readFinished(); err != nil {
|
||||
if err := hs.readFinished(isResume); err != nil {
|
||||
return err
|
||||
}
|
||||
c.didResume = true
|
||||
@@ -82,7 +84,7 @@ func (c *Conn) serverHandshake() error {
|
||||
if err := hs.establishKeys(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.readFinished(); err != nil {
|
||||
if err := hs.readFinished(isResume); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendSessionTicket(); err != nil {
|
||||
@@ -231,6 +233,10 @@ Curves:
|
||||
hs.cert = config.getCertificateForName(hs.clientHello.serverName)
|
||||
}
|
||||
|
||||
if hs.clientHello.channelIDSupported && config.RequestChannelID {
|
||||
hs.hello.channelIDRequested = true
|
||||
}
|
||||
|
||||
_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
|
||||
|
||||
if hs.checkForResumption() {
|
||||
@@ -579,7 +585,7 @@ func (hs *serverHandshakeState) establishKeys() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) readFinished() error {
|
||||
func (hs *serverHandshakeState) readFinished(isResume bool) error {
|
||||
c := hs.c
|
||||
|
||||
c.readRecord(recordTypeChangeCipherSpec)
|
||||
@@ -601,6 +607,36 @@ func (hs *serverHandshakeState) readFinished() error {
|
||||
c.clientProtocol = nextProto.proto
|
||||
}
|
||||
|
||||
if hs.hello.channelIDRequested {
|
||||
msg, err := c.readHandshake()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(encryptedExtensions, msg)
|
||||
}
|
||||
x := new(big.Int).SetBytes(encryptedExtensions.channelID[0:32])
|
||||
y := new(big.Int).SetBytes(encryptedExtensions.channelID[32:64])
|
||||
r := new(big.Int).SetBytes(encryptedExtensions.channelID[64:96])
|
||||
s := new(big.Int).SetBytes(encryptedExtensions.channelID[96:128])
|
||||
if !elliptic.P256().IsOnCurve(x, y) {
|
||||
return errors.New("tls: invalid channel ID public key")
|
||||
}
|
||||
channelID := &ecdsa.PublicKey{elliptic.P256(), x, y}
|
||||
var resumeHash []byte
|
||||
if isResume {
|
||||
resumeHash = hs.sessionState.handshakeHash
|
||||
}
|
||||
if !ecdsa.Verify(channelID, hs.finishedHash.hashForChannelID(resumeHash), r, s) {
|
||||
return errors.New("tls: invalid channel ID signature")
|
||||
}
|
||||
c.channelID = channelID
|
||||
|
||||
hs.writeClientHash(encryptedExtensions.marshal())
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -632,10 +668,11 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||
|
||||
var err error
|
||||
state := sessionState{
|
||||
vers: c.vers,
|
||||
cipherSuite: hs.suite.id,
|
||||
masterSecret: hs.masterSecret,
|
||||
certificates: hs.certsFromClient,
|
||||
vers: c.vers,
|
||||
cipherSuite: hs.suite.id,
|
||||
masterSecret: hs.masterSecret,
|
||||
certificates: hs.certsFromClient,
|
||||
handshakeHash: hs.finishedHash.server.Sum(nil),
|
||||
}
|
||||
m.ticket, err = c.encryptTicket(&state)
|
||||
if err != nil {
|
||||
|
||||
@@ -120,6 +120,8 @@ var masterSecretLabel = []byte("master secret")
|
||||
var keyExpansionLabel = []byte("key expansion")
|
||||
var clientFinishedLabel = []byte("client finished")
|
||||
var serverFinishedLabel = []byte("server finished")
|
||||
var channelIDLabel = []byte("TLS Channel ID signature\x00")
|
||||
var channelIDResumeLabel = []byte("Resumption\x00")
|
||||
|
||||
func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
|
||||
switch version {
|
||||
@@ -321,3 +323,17 @@ func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash
|
||||
digest = h.server.Sum(digest)
|
||||
return digest, crypto.MD5SHA1, nil
|
||||
}
|
||||
|
||||
// hashForChannelID returns the hash to be signed for TLS Channel
|
||||
// ID. If a resumption, resumeHash has the previous handshake
|
||||
// hash. Otherwise, it is nil.
|
||||
func (h finishedHash) hashForChannelID(resumeHash []byte) []byte {
|
||||
hash := sha256.New()
|
||||
hash.Write(channelIDLabel)
|
||||
if resumeHash != nil {
|
||||
hash.Write(channelIDResumeLabel)
|
||||
hash.Write(resumeHash)
|
||||
}
|
||||
hash.Write(h.server.Sum(nil))
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
@@ -18,10 +18,11 @@ import (
|
||||
// sessionState contains the information that is serialized into a session
|
||||
// ticket in order to later resume a connection.
|
||||
type sessionState struct {
|
||||
vers uint16
|
||||
cipherSuite uint16
|
||||
masterSecret []byte
|
||||
certificates [][]byte
|
||||
vers uint16
|
||||
cipherSuite uint16
|
||||
masterSecret []byte
|
||||
handshakeHash []byte
|
||||
certificates [][]byte
|
||||
}
|
||||
|
||||
func (s *sessionState) equal(i interface{}) bool {
|
||||
@@ -32,7 +33,8 @@ func (s *sessionState) equal(i interface{}) bool {
|
||||
|
||||
if s.vers != s1.vers ||
|
||||
s.cipherSuite != s1.cipherSuite ||
|
||||
!bytes.Equal(s.masterSecret, s1.masterSecret) {
|
||||
!bytes.Equal(s.masterSecret, s1.masterSecret) ||
|
||||
!bytes.Equal(s.handshakeHash, s1.handshakeHash) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -50,7 +52,7 @@ func (s *sessionState) equal(i interface{}) bool {
|
||||
}
|
||||
|
||||
func (s *sessionState) marshal() []byte {
|
||||
length := 2 + 2 + 2 + len(s.masterSecret) + 2
|
||||
length := 2 + 2 + 2 + len(s.masterSecret) + 2 + len(s.handshakeHash) + 2
|
||||
for _, cert := range s.certificates {
|
||||
length += 4 + len(cert)
|
||||
}
|
||||
@@ -67,6 +69,12 @@ func (s *sessionState) marshal() []byte {
|
||||
copy(x, s.masterSecret)
|
||||
x = x[len(s.masterSecret):]
|
||||
|
||||
x[0] = byte(len(s.handshakeHash) >> 8)
|
||||
x[1] = byte(len(s.handshakeHash))
|
||||
x = x[2:]
|
||||
copy(x, s.handshakeHash)
|
||||
x = x[len(s.handshakeHash):]
|
||||
|
||||
x[0] = byte(len(s.certificates) >> 8)
|
||||
x[1] = byte(len(s.certificates))
|
||||
x = x[2:]
|
||||
@@ -103,6 +111,19 @@ func (s *sessionState) unmarshal(data []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
handshakeHashLen := int(data[0])<<8 | int(data[1])
|
||||
data = data[2:]
|
||||
if len(data) < handshakeHashLen {
|
||||
return false
|
||||
}
|
||||
|
||||
s.handshakeHash = data[:handshakeHashLen]
|
||||
data = data[handshakeHashLen:]
|
||||
|
||||
if len(data) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
numCerts := int(data[0])<<8 | int(data[1])
|
||||
data = data[2:]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user