Quellcode durchsuchen

[dev.tls] crypto/tls: implement TLS 1.3 messages

Updates #9671

Change-Id: Ia1b06ae518a4b2821a584a420d99859a2666c8f0
v1.2.3
Filippo Valsorda vor 8 Jahren
committed by Peter Wu
Ursprung
Commit
9bc837c453
4 geänderte Dateien mit 528 neuen und 19 gelöschten Zeilen
  1. +27
    -14
      common.go
  2. +12
    -2
      conn.go
  3. +446
    -1
      handshake_messages.go
  4. +43
    -2
      handshake_messages_test.go

+ 27
- 14
common.go Datei anzeigen

@@ -51,19 +51,20 @@ const (

// TLS handshake message types.
const (
typeHelloRequest uint8 = 0
typeClientHello uint8 = 1
typeServerHello uint8 = 2
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
typeHelloRequest uint8 = 0
typeClientHello uint8 = 1
typeServerHello uint8 = 2
typeNewSessionTicket uint8 = 4
typeEncryptedExtensions uint8 = 8
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
)

// TLS compression types.
@@ -75,12 +76,14 @@ const (
const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10
extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
extensionSessionTicket uint16 = 35
extensionKeyShare uint16 = 40
extensionSupportedVersions uint16 = 43
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
)
@@ -92,6 +95,9 @@ const (

// CurveID is the type of a TLS identifier for an elliptic curve. See
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
//
// TLS 1.3 refers to these as Groups, but this library implements only
// curve-based ones anyway. See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4.
type CurveID uint16

const (
@@ -101,6 +107,13 @@ const (
X25519 CurveID = 29
)

// TLS 1.3 Key Share
// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
type keyShare struct {
group CurveID
data []byte
}

// TLS Elliptic Curve Point Formats
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
const (


+ 12
- 2
conn.go Datei anzeigen

@@ -1009,11 +1009,21 @@ func (c *Conn) readHandshake() (interface{}, error) {
case typeClientHello:
m = new(clientHelloMsg)
case typeServerHello:
m = new(serverHelloMsg)
if c.vers >= VersionTLS13 {
m = new(serverHelloMsg13)
} else {
m = new(serverHelloMsg)
}
case typeEncryptedExtensions:
m = new(encryptedExtensionsMsg)
case typeNewSessionTicket:
m = new(newSessionTicketMsg)
case typeCertificate:
m = new(certificateMsg)
if c.vers >= VersionTLS13 {
m = new(certificateMsg13)
} else {
m = new(certificateMsg)
}
case typeCertificateRequest:
m = &certificateRequestMsg{
hasSignatureAndHash: c.vers >= VersionTLS12,


+ 446
- 1
handshake_messages.go Datei anzeigen

@@ -28,6 +28,8 @@ type clientHelloMsg struct {
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
keyShares []keyShare
supportedVersions []uint16
}

func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -53,7 +55,9 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
eqStrings(m.alpnProtocols, m1.alpnProtocols)
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
eqKeyShares(m.keyShares, m1.keyShares) &&
eqUint16s(m.supportedVersions, m1.supportedVersions)
}

func (m *clientHelloMsg) marshal() []byte {
@@ -109,6 +113,17 @@ func (m *clientHelloMsg) marshal() []byte {
if m.scts {
numExtensions++
}
if len(m.keyShares) > 0 {
extensionsLength += 2
for _, k := range m.keyShares {
extensionsLength += 4 + len(k.data)
}
numExtensions++
}
if len(m.supportedVersions) > 0 {
extensionsLength += 1 + 2*len(m.supportedVersions)
numExtensions++
}
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -193,6 +208,7 @@ func (m *clientHelloMsg) marshal() []byte {
}
if len(m.supportedCurves) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.5.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
z[0] = byte(extensionSupportedCurves >> 8)
z[1] = byte(extensionSupportedCurves)
l := 2 + 2*len(m.supportedCurves)
@@ -236,6 +252,7 @@ func (m *clientHelloMsg) marshal() []byte {
}
if len(m.signatureAndHashes) > 0 {
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3
z[0] = byte(extensionSignatureAlgorithms >> 8)
z[1] = byte(extensionSignatureAlgorithms)
l := 2 + 2*len(m.signatureAndHashes)
@@ -291,6 +308,45 @@ func (m *clientHelloMsg) marshal() []byte {
// zero uint16 for the zero-length extension_data
z = z[4:]
}
if len(m.keyShares) > 0 {
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
z[0] = byte(extensionKeyShare >> 8)
z[1] = byte(extensionKeyShare)
lengths := z[2:]
z = z[6:]

totalLength := 0
for _, ks := range m.keyShares {
z[0] = byte(ks.group >> 8)
z[1] = byte(ks.group)
z[2] = byte(len(ks.data) >> 8)
z[3] = byte(len(ks.data))
copy(z[4:], ks.data)
z = z[4+len(ks.data):]
totalLength += 4 + len(ks.data)
}

lengths[2] = byte(totalLength >> 8)
lengths[3] = byte(totalLength)
totalLength += 2
lengths[0] = byte(totalLength >> 8)
lengths[1] = byte(totalLength)
}
if len(m.supportedVersions) > 0 {
z[0] = byte(extensionSupportedVersions >> 8)
z[1] = byte(extensionSupportedVersions)
l := 1 + 2*len(m.supportedVersions)
z[2] = byte(l >> 8)
z[3] = byte(l)
l -= 1
z[4] = byte(l)
z = z[5:]
for _, v := range m.supportedVersions {
z[0] = byte(v >> 8)
z[1] = byte(v)
z = z[2:]
}
}

m.raw = x

@@ -347,6 +403,8 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.signatureAndHashes = nil
m.alpnProtocols = nil
m.scts = false
m.keyShares = nil
m.supportedVersions = nil

if len(data) == 0 {
// ClientHello is optionally followed by extension data
@@ -415,6 +473,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
case extensionSupportedCurves:
// http://tools.ietf.org/html/rfc4492#section-5.5.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
if length < 2 {
return false
}
@@ -446,6 +505,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.sessionTicket = data[:length]
case extensionSignatureAlgorithms:
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3
if length < 2 || length&1 != 0 {
return false
}
@@ -497,6 +557,46 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
if length != 0 {
return false
}
case extensionKeyShare:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5
if length < 2 {
return false
}
l := int(data[0])<<8 | int(data[1])
if l != length-2 {
return false
}
d := data[2:length]
for len(d) != 0 {
if len(d) < 4 {
return false
}
dataLen := int(d[2])<<8 | int(d[3])
if dataLen == 0 || 4+dataLen > len(d) {
return false
}
m.keyShares = append(m.keyShares, keyShare{
group: CurveID(d[0])<<8 | CurveID(d[1]),
data: d[4 : 4+dataLen],
})
d = d[4+dataLen:]
}
case extensionSupportedVersions:
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.1
if length < 1 {
return false
}
l := int(data[0])
if l%2 == 1 || length != l+1 {
return false
}
n := l / 2
d := data[1:]
for i := 0; i < n; i++ {
v := uint16(d[0])<<8 + uint16(d[1])
m.supportedVersions = append(m.supportedVersions, v)
d = d[2:]
}
}
data = data[length:]
}
@@ -835,6 +935,219 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return true
}

type serverHelloMsg13 struct {
raw []byte
vers uint16
random []byte
cipherSuite uint16
keyShare keyShare
}

func (m *serverHelloMsg13) equal(i interface{}) bool {
m1, ok := i.(*serverHelloMsg13)
if !ok {
return false
}

return bytes.Equal(m.raw, m1.raw) &&
m.vers == m1.vers &&
bytes.Equal(m.random, m1.random) &&
m.cipherSuite == m1.cipherSuite &&
m.keyShare.group == m1.keyShare.group &&
bytes.Equal(m.keyShare.data, m1.keyShare.data)
}

func (m *serverHelloMsg13) marshal() []byte {
if m.raw != nil {
return m.raw
}

length := 38
if m.keyShare.group != 0 {
length += 8 + len(m.keyShare.data)
}

x := make([]byte, 4+length)
x[0] = typeServerHello
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
x[4] = uint8(m.vers >> 8)
x[5] = uint8(m.vers)
copy(x[6:38], m.random)
x[38] = uint8(m.cipherSuite >> 8)
x[39] = uint8(m.cipherSuite)

z := x[42:]
x[40] = uint8(len(z) >> 8)
x[41] = uint8(len(z))

if m.keyShare.group != 0 {
z[0] = uint8(extensionKeyShare >> 8)
z[1] = uint8(extensionKeyShare)
l := 4 + len(m.keyShare.data)
z[2] = uint8(l >> 8)
z[3] = uint8(l)
z[4] = uint8(m.keyShare.group >> 8)
z[5] = uint8(m.keyShare.group)
l -= 4
z[6] = uint8(l >> 8)
z[7] = uint8(l)
copy(z[8:], m.keyShare.data)
}

m.raw = x
return x
}

func (m *serverHelloMsg13) unmarshal(data []byte) bool {
if len(data) < 50 {
return false
}
m.raw = data
m.vers = uint16(data[4])<<8 | uint16(data[5])
m.random = data[6:38]
m.cipherSuite = uint16(data[38])<<8 | uint16(data[39])

extensionsLength := int(data[40])<<8 | int(data[41])
data = data[42:]
if len(data) != extensionsLength {
return false
}

for len(data) != 0 {
if len(data) < 4 {
return false
}
extension := uint16(data[0])<<8 | uint16(data[1])
length := int(data[2])<<8 | int(data[3])
data = data[4:]
if len(data) < length {
return false
}

switch extension {
default:
return false
case extensionKeyShare:
if length < 2 {
return false
}
m.keyShare.group = CurveID(data[0])<<8 | CurveID(data[1])
if length-4 != int(data[2])<<8|int(data[3]) {
return false
}
m.keyShare.data = data[4:length]
}
data = data[length:]
}

return true
}

type encryptedExtensionsMsg struct {
raw []byte
alpnProtocol string
}

func (m *encryptedExtensionsMsg) equal(i interface{}) bool {
m1, ok := i.(*encryptedExtensionsMsg)
if !ok {
return false
}

return bytes.Equal(m.raw, m1.raw) &&
m.alpnProtocol == m1.alpnProtocol
}

func (m *encryptedExtensionsMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}

length := 2

alpnLen := len(m.alpnProtocol)
if alpnLen > 0 {
if alpnLen >= 256 {
panic("invalid ALPN protocol")
}
length += 2 + 2 + 2 + 1 + alpnLen
}

x := make([]byte, 4+length)
x[0] = typeEncryptedExtensions
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
length -= 2
x[4] = uint8(length >> 8)
x[5] = uint8(length)

z := x[6:]
if alpnLen > 0 {
z[0] = byte(extensionALPN >> 8)
z[1] = byte(extensionALPN)
l := 2 + 1 + alpnLen
z[2] = byte(l >> 8)
z[3] = byte(l)
l -= 2
z[4] = byte(l >> 8)
z[5] = byte(l)
l -= 1
z[6] = byte(l)
copy(z[7:], []byte(m.alpnProtocol))
z = z[7+alpnLen:]
}

m.raw = x
return x
}

func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
if len(data) < 6 {
return false
}
m.raw = data
l := int(data[4])<<8 | int(data[5])
if l != len(data)-6 {
return false
}
m.alpnProtocol = ""
if l == 0 {
return true
}

d := data[6:]
if len(d) < 5 {
return false
}
if uint16(d[0])<<8|uint16(d[1]) != extensionALPN {
return false
}
l = int(d[2])<<8 | int(d[3])
if l != len(d)-4 {
return false
}
l = int(d[4])<<8 | int(d[5])
if l != len(d)-6 {
return false
}
d = d[6:]
l = int(d[0])
if l != len(d)-1 {
return false
}
d = d[1:]
if len(d) == 0 {
// ALPN protocols must not be empty.
return false
}
m.alpnProtocol = string(d)

return true
}

type certificateMsg struct {
raw []byte
certificates [][]byte
@@ -922,6 +1235,123 @@ func (m *certificateMsg) unmarshal(data []byte) bool {
return true
}

type certificateMsg13 struct {
raw []byte
requestContext []byte
certificates [][]byte
}

func (m *certificateMsg13) equal(i interface{}) bool {
m1, ok := i.(*certificateMsg13)
if !ok {
return false
}

return bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.requestContext, m1.requestContext) &&
eqByteSlices(m.certificates, m1.certificates)
}

func (m *certificateMsg13) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}

var i int
for _, slice := range m.certificates {
i += len(slice)
}

length := 3 + 3*len(m.certificates) + i
length += 2 * len(m.certificates) // extensions
length += 1 + len(m.requestContext)
x = make([]byte, 4+length)
x[0] = typeCertificate
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)

z := x[4:]

z[0] = byte(len(m.requestContext))
copy(z[1:], m.requestContext)
z = z[1+len(m.requestContext):]

certificateOctets := len(z) - 3
z[0] = uint8(certificateOctets >> 16)
z[1] = uint8(certificateOctets >> 8)
z[2] = uint8(certificateOctets)

z = z[3:]
for _, slice := range m.certificates {
z[0] = uint8(len(slice) >> 16)
z[1] = uint8(len(slice) >> 8)
z[2] = uint8(len(slice))
copy(z[3:], slice)
z = z[3+len(slice)+2:]
}

m.raw = x
return
}

func (m *certificateMsg13) unmarshal(data []byte) bool {
if len(data) < 5 {
return false
}

m.raw = data

ctxLen := data[4]
if len(data) < int(ctxLen)+5+3 {
return false
}
m.requestContext = data[5 : 5+ctxLen]

d := data[5+ctxLen:]
certsLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
if uint32(len(d)) != certsLen+3 {
return false
}

numCerts := 0
d = d[3:]
for certsLen > 0 {
if len(d) < 4 {
return false
}
certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
if uint32(len(d)) < 3+certLen {
return false
}
d = d[3+certLen:]

if len(d) < 2 {
return false
}
extLen := uint16(d[0])<<8 | uint16(d[1])
if uint16(len(d)) < 2+extLen {
return false
}
d = d[2+extLen:]

certsLen -= 3 + certLen + 2 + uint32(extLen)
numCerts++
}

m.certificates = make([][]byte, numCerts)
d = data[8+ctxLen:]
for i := 0; i < numCerts; i++ {
certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
m.certificates[i] = d[3 : 3+certLen]
d = d[3+certLen:]
extLen := uint16(d[0])<<8 | uint16(d[1])
d = d[2+extLen:]
}

return true
}

type serverKeyExchangeMsg struct {
raw []byte
key []byte
@@ -1566,3 +1996,18 @@ func eqSignatureAndHashes(x, y []signatureAndHash) bool {
}
return true
}

func eqKeyShares(x, y []keyShare) bool {
if len(x) != len(y) {
return false
}
for i := range x {
if x[i].group != y[i].group {
return false
}
if !bytes.Equal(x[i].data, y[i].data) {
return false
}
}
return true
}

+ 43
- 2
handshake_messages_test.go Datei anzeigen

@@ -26,6 +26,9 @@ var tests = []interface{}{
&nextProtoMsg{},
&newSessionTicketMsg{},
&sessionState{},
&serverHelloMsg13{},
&encryptedExtensionsMsg{},
&certificateMsg13{},
}

type testMessage interface {
@@ -55,13 +58,13 @@ func TestMarshalUnmarshal(t *testing.T) {
marshaled := m1.marshal()
m2 := iface.(testMessage)
if !m2.unmarshal(marshaled) {
t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
t.Errorf("#%d.%d failed to unmarshal %#v %x", i, j, m1, marshaled)
break
}
m2.marshal() // to fill any marshal cache in the message

if !m1.equal(m2) {
t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
t.Errorf("#%d.%d got:%#v want:%#v %x", i, j, m2, m1, marshaled)
break
}

@@ -150,6 +153,15 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
if rand.Intn(10) > 5 {
m.scts = true
}
m.keyShares = make([]keyShare, rand.Intn(4))
for i := range m.keyShares {
m.keyShares[i].group = CurveID(rand.Intn(30000))
m.keyShares[i].data = randomBytes(rand.Intn(300), rand)
}
m.supportedVersions = make([]uint16, rand.Intn(5))
for i := range m.supportedVersions {
m.supportedVersions[i] = uint16(rand.Intn(30000))
}

return reflect.ValueOf(m)
}
@@ -191,6 +203,24 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
return reflect.ValueOf(m)
}

func (*serverHelloMsg13) Generate(rand *rand.Rand, size int) reflect.Value {
m := &serverHelloMsg13{}
m.vers = uint16(rand.Intn(65536))
m.random = randomBytes(32, rand)
m.cipherSuite = uint16(rand.Int31())
m.keyShare.group = CurveID(rand.Intn(30000))
m.keyShare.data = randomBytes(rand.Intn(300), rand)

return reflect.ValueOf(m)
}

func (*encryptedExtensionsMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m := &encryptedExtensionsMsg{}
m.alpnProtocol = randomString(rand.Intn(32)+1, rand)

return reflect.ValueOf(m)
}

func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m := &certificateMsg{}
numCerts := rand.Intn(20)
@@ -201,6 +231,17 @@ func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
return reflect.ValueOf(m)
}

func (*certificateMsg13) Generate(rand *rand.Rand, size int) reflect.Value {
m := &certificateMsg13{}
numCerts := rand.Intn(20)
m.certificates = make([][]byte, numCerts)
for i := 0; i < numCerts; i++ {
m.certificates[i] = randomBytes(rand.Intn(10)+1, rand)
}
m.requestContext = randomBytes(rand.Intn(5), rand)
return reflect.ValueOf(m)
}

func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m := &certificateRequestMsg{}
m.certificateTypes = randomBytes(rand.Intn(5)+1, rand)


Laden…
Abbrechen
Speichern