aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@google.com>2017-11-24 10:00:39 -0500
committerCQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>2017-11-27 21:18:40 +0000
commitbe8c8b4b1dd26f5d66d603987f28fc3084fbf217 (patch)
tree548480c6b6875b0f72b4d72ed39bf3e0d21f0bb7
parent8c9ceadc58f425bd5edc71c349ef55e1a516302d (diff)
downloadboringssl-be8c8b4b1dd26f5d66d603987f28fc3084fbf217.zip
boringssl-be8c8b4b1dd26f5d66d603987f28fc3084fbf217.tar.gz
boringssl-be8c8b4b1dd26f5d66d603987f28fc3084fbf217.tar.bz2
runner: Add a byteReader type and convert ClientHello parsing.
Bug: 212 Change-Id: Iecbd8fddef1b55a438947ad60780e08cb4260c48 Reviewed-on: https://boringssl-review.googlesource.com/23444 Reviewed-by: Steven Valdez <svaldez@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
-rw-r--r--ssl/test/runner/handshake_messages.go444
1 files changed, 228 insertions, 216 deletions
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 93da121..766d515 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -125,6 +125,121 @@ func (bb *byteBuilder) discardChild() {
bb.child = nil
}
+type byteReader []byte
+
+func (br *byteReader) readInternal(out *byteReader, n int) bool {
+ if len(*br) < n {
+ return false
+ }
+ *out = (*br)[:n]
+ *br = (*br)[n:]
+ return true
+}
+
+func (br *byteReader) readBytes(out *[]byte, n int) bool {
+ var child byteReader
+ if !br.readInternal(&child, n) {
+ return false
+ }
+ *out = []byte(child)
+ return true
+}
+
+func (br *byteReader) readUint(out *uint64, n int) bool {
+ var b []byte
+ if !br.readBytes(&b, n) {
+ return false
+ }
+ *out = 0
+ for _, v := range b {
+ *out <<= 8
+ *out |= uint64(v)
+ }
+ return true
+}
+
+func (br *byteReader) readU8(out *uint8) bool {
+ var b []byte
+ if !br.readBytes(&b, 1) {
+ return false
+ }
+ *out = b[0]
+ return true
+}
+
+func (br *byteReader) readU16(out *uint16) bool {
+ var v uint64
+ if !br.readUint(&v, 2) {
+ return false
+ }
+ *out = uint16(v)
+ return true
+}
+
+func (br *byteReader) readU24(out *uint32) bool {
+ var v uint64
+ if !br.readUint(&v, 3) {
+ return false
+ }
+ *out = uint32(v)
+ return true
+}
+
+func (br *byteReader) readU32(out *uint32) bool {
+ var v uint64
+ if !br.readUint(&v, 4) {
+ return false
+ }
+ *out = uint32(v)
+ return true
+}
+
+func (br *byteReader) readU64(out *uint64) bool {
+ return br.readUint(out, 8)
+}
+
+func (br *byteReader) readLengthPrefixed(out *byteReader, n int) bool {
+ var length uint64
+ return br.readUint(&length, n) &&
+ uint64(len(*br)) >= length &&
+ br.readInternal(out, int(length))
+}
+
+func (br *byteReader) readLengthPrefixedBytes(out *[]byte, n int) bool {
+ var length uint64
+ return br.readUint(&length, n) &&
+ uint64(len(*br)) >= length &&
+ br.readBytes(out, int(length))
+}
+
+func (br *byteReader) readU8LengthPrefixed(out *byteReader) bool {
+ return br.readLengthPrefixed(out, 1)
+}
+func (br *byteReader) readU8LengthPrefixedBytes(out *[]byte) bool {
+ return br.readLengthPrefixedBytes(out, 1)
+}
+
+func (br *byteReader) readU16LengthPrefixed(out *byteReader) bool {
+ return br.readLengthPrefixed(out, 2)
+}
+func (br *byteReader) readU16LengthPrefixedBytes(out *[]byte) bool {
+ return br.readLengthPrefixedBytes(out, 2)
+}
+
+func (br *byteReader) readU24LengthPrefixed(out *byteReader) bool {
+ return br.readLengthPrefixed(out, 3)
+}
+func (br *byteReader) readU24LengthPrefixedBytes(out *[]byte) bool {
+ return br.readLengthPrefixedBytes(out, 3)
+}
+
+func (br *byteReader) readU32LengthPrefixed(out *byteReader) bool {
+ return br.readLengthPrefixed(out, 4)
+}
+func (br *byteReader) readU32LengthPrefixedBytes(out *[]byte) bool {
+ return br.readLengthPrefixedBytes(out, 4)
+}
+
type keyShareEntry struct {
group CurveID
keyExchange []byte
@@ -483,57 +598,37 @@ func (m *clientHelloMsg) marshal() []byte {
}
func (m *clientHelloMsg) unmarshal(data []byte) bool {
- if len(data) < 42 {
- return false
- }
m.raw = data
- m.vers = uint16(data[4])<<8 | uint16(data[5])
- m.random = data[6:38]
- sessionIdLen := int(data[38])
- if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+ reader := byteReader(data[4:])
+ if !reader.readU16(&m.vers) ||
+ !reader.readBytes(&m.random, 32) ||
+ !reader.readU8LengthPrefixedBytes(&m.sessionId) ||
+ len(m.sessionId) > 32 {
return false
}
- m.sessionId = data[39 : 39+sessionIdLen]
- data = data[39+sessionIdLen:]
if m.isDTLS {
- if len(data) < 1 {
+ if !reader.readU8LengthPrefixedBytes(&m.cookie) ||
+ len(m.cookie) > 32 {
return false
}
- cookieLen := int(data[0])
- if cookieLen > 32 || len(data) < 1+cookieLen {
- return false
- }
- m.cookie = data[1 : 1+cookieLen]
- data = data[1+cookieLen:]
}
- if len(data) < 2 {
+ var cipherSuites byteReader
+ if !reader.readU16LengthPrefixed(&cipherSuites) ||
+ !reader.readU8LengthPrefixedBytes(&m.compressionMethods) {
return false
}
- // cipherSuiteLen is the number of bytes of cipher suite numbers. Since
- // they are uint16s, the number must be even.
- cipherSuiteLen := int(data[0])<<8 | int(data[1])
- if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
- return false
- }
- numCipherSuites := cipherSuiteLen / 2
- m.cipherSuites = make([]uint16, numCipherSuites)
- for i := 0; i < numCipherSuites; i++ {
- m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
- if m.cipherSuites[i] == scsvRenegotiation {
+
+ m.cipherSuites = make([]uint16, 0, len(cipherSuites)/2)
+ for len(cipherSuites) > 0 {
+ var v uint16
+ if !cipherSuites.readU16(&v) {
+ return false
+ }
+ m.cipherSuites = append(m.cipherSuites, v)
+ if v == scsvRenegotiation {
m.secureRenegotiation = []byte{}
}
}
- data = data[2+cipherSuiteLen:]
- if len(data) < 1 {
- return false
- }
- compressionMethodsLen := int(data[0])
- if len(data) < 1+compressionMethodsLen {
- return false
- }
- m.compressionMethods = data[1 : 1+compressionMethodsLen]
-
- data = data[1+compressionMethodsLen:]
m.nextProtoNeg = false
m.serverName = ""
@@ -549,167 +644,108 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.extendedMasterSecret = false
m.customExtension = ""
- if len(data) == 0 {
+ if len(reader) == 0 {
// ClientHello is optionally followed by extension data
return true
}
- if len(data) < 2 {
- return false
- }
- extensionsLength := int(data[0])<<8 | int(data[1])
- data = data[2:]
- if extensionsLength != len(data) {
+ var extensions byteReader
+ if !reader.readU16LengthPrefixed(&extensions) || len(reader) != 0 {
return false
}
-
- for len(data) != 0 {
- if len(data) < 4 {
+ for len(extensions) > 0 {
+ var extension uint16
+ var body byteReader
+ if !extensions.readU16(&extension) ||
+ !extensions.readU16LengthPrefixed(&body) {
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 {
case extensionServerName:
- if length < 2 {
+ var names byteReader
+ if !body.readU16LengthPrefixed(&names) || len(body) != 0 {
return false
}
- numNames := int(data[0])<<8 | int(data[1])
- d := data[2:]
- for i := 0; i < numNames; i++ {
- if len(d) < 3 {
- return false
- }
- nameType := d[0]
- nameLen := int(d[1])<<8 | int(d[2])
- d = d[3:]
- if len(d) < nameLen {
+ for len(names) > 0 {
+ var nameType byte
+ var name []byte
+ if !names.readU8(&nameType) ||
+ !names.readU16LengthPrefixedBytes(&name) {
return false
}
if nameType == 0 {
- m.serverName = string(d[0:nameLen])
- break
+ m.serverName = string(name)
}
- d = d[nameLen:]
}
case extensionNextProtoNeg:
- if length > 0 {
+ if len(body) != 0 {
return false
}
m.nextProtoNeg = true
case extensionStatusRequest:
- m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+ m.ocspStapling = len(body) > 0 && body[0] == statusTypeOCSP
case extensionSupportedCurves:
// http://tools.ietf.org/html/rfc4492#section-5.5.1
- if length < 2 {
+ var curves byteReader
+ if !body.readU16LengthPrefixed(&curves) || len(body) != 0 {
return false
}
- l := int(data[0])<<8 | int(data[1])
- if l%2 == 1 || length != l+2 {
- return false
- }
- numCurves := l / 2
- m.supportedCurves = make([]CurveID, numCurves)
- d := data[2:]
- for i := 0; i < numCurves; i++ {
- m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
- d = d[2:]
+ m.supportedCurves = make([]CurveID, 0, len(curves)/2)
+ for len(curves) > 0 {
+ var v uint16
+ if !curves.readU16(&v) {
+ return false
+ }
+ m.supportedCurves = append(m.supportedCurves, CurveID(v))
}
case extensionSupportedPoints:
// http://tools.ietf.org/html/rfc4492#section-5.5.2
- if length < 1 {
+ if !body.readU8LengthPrefixedBytes(&m.supportedPoints) || len(body) != 0 {
return false
}
- l := int(data[0])
- if length != l+1 {
- return false
- }
- m.supportedPoints = data[1 : 1+l]
case extensionSessionTicket:
// http://tools.ietf.org/html/rfc5077#section-3.2
m.ticketSupported = true
- m.sessionTicket = data[:length]
+ m.sessionTicket = []byte(body)
case extensionKeyShare:
// draft-ietf-tls-tls13 section 6.3.2.3
- if length < 2 {
- return false
- }
- l := int(data[0])<<8 | int(data[1])
- if l != length-2 {
+ var keyShares byteReader
+ if !body.readU16LengthPrefixed(&keyShares) || len(body) != 0 {
return false
}
- d := data[2:length]
m.hasKeyShares = true
- for len(d) > 0 {
- // The next KeyShareEntry contains a NamedGroup (2 bytes) and a
- // key_exchange (2-byte length prefix with at least 1 byte of content).
- if len(d) < 5 {
+ for len(keyShares) > 0 {
+ var entry keyShareEntry
+ var group uint16
+ if !keyShares.readU16(&group) ||
+ !keyShares.readU16LengthPrefixedBytes(&entry.keyExchange) {
return false
}
- entry := keyShareEntry{}
- entry.group = CurveID(d[0])<<8 | CurveID(d[1])
- keyExchLen := int(d[2])<<8 | int(d[3])
- d = d[4:]
- if len(d) < keyExchLen {
- return false
- }
- entry.keyExchange = d[:keyExchLen]
- d = d[keyExchLen:]
+ entry.group = CurveID(group)
m.keyShares = append(m.keyShares, entry)
}
case extensionPreSharedKey:
// draft-ietf-tls-tls13-18 section 4.2.6
- if length < 2 {
+ var psks, binders byteReader
+ if !body.readU16LengthPrefixed(&psks) ||
+ !body.readU16LengthPrefixed(&binders) ||
+ len(body) != 0 {
return false
}
- l := int(data[0])<<8 | int(data[1])
- d := data[2 : l+2]
- // Parse PSK identities.
- for len(d) > 0 {
- if len(d) < 2 {
- return false
- }
- pskLen := int(d[0])<<8 | int(d[1])
- d = d[2:]
-
- if len(d) < pskLen+4 {
+ for len(psks) > 0 {
+ var psk pskIdentity
+ if !psks.readU16LengthPrefixedBytes(&psk.ticket) ||
+ !psks.readU32(&psk.obfuscatedTicketAge) {
return false
}
- ticket := d[:pskLen]
- obfuscatedTicketAge := uint32(d[pskLen])<<24 | uint32(d[pskLen+1])<<16 | uint32(d[pskLen+2])<<8 | uint32(d[pskLen+3])
- psk := pskIdentity{
- ticket: ticket,
- obfuscatedTicketAge: obfuscatedTicketAge,
- }
m.pskIdentities = append(m.pskIdentities, psk)
- d = d[pskLen+4:]
- }
- d = data[l+2:]
- if len(d) < 2 {
- return false
- }
- l = int(d[0])<<8 | int(d[1])
- d = d[2:]
- if l != len(d) {
- return false
}
- // Parse PSK binders.
- for len(d) > 0 {
- if len(d) < 1 {
- return false
- }
- binderLen := int(d[0])
- d = d[1:]
- if binderLen > len(d) {
+ for len(binders) > 0 {
+ var binder []byte
+ if !binders.readU8LengthPrefixedBytes(&binder) {
return false
}
- m.pskBinders = append(m.pskBinders, d[:binderLen])
- d = d[binderLen:]
+ m.pskBinders = append(m.pskBinders, binder)
}
// There must be the same number of identities as binders.
@@ -718,121 +754,97 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
case extensionPSKKeyExchangeModes:
// draft-ietf-tls-tls13-18 section 4.2.7
- if length < 1 {
+ if !body.readU8LengthPrefixedBytes(&m.pskKEModes) || len(body) != 0 {
return false
}
- l := int(data[0])
- if l != length-1 {
- return false
- }
- m.pskKEModes = data[1:length]
case extensionEarlyData:
// draft-ietf-tls-tls13 section 6.3.2.5
- if length != 0 {
+ if len(body) != 0 {
return false
}
m.hasEarlyData = true
case extensionCookie:
- if length < 2 {
+ if !body.readU16LengthPrefixedBytes(&m.tls13Cookie) || len(body) != 0 {
return false
}
- l := int(data[0])<<8 | int(data[1])
- if l != length-2 || l == 0 {
- return false
- }
- m.tls13Cookie = data[2 : 2+l]
case extensionSignatureAlgorithms:
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
- if length < 2 || length&1 != 0 {
+ var sigAlgs byteReader
+ if !body.readU16LengthPrefixed(&sigAlgs) || len(body) != 0 {
return false
}
- l := int(data[0])<<8 | int(data[1])
- if l != length-2 {
- return false
- }
- n := l / 2
- d := data[2:]
- m.signatureAlgorithms = make([]signatureAlgorithm, n)
- for i := range m.signatureAlgorithms {
- m.signatureAlgorithms[i] = signatureAlgorithm(d[0])<<8 | signatureAlgorithm(d[1])
- d = d[2:]
+ m.signatureAlgorithms = make([]signatureAlgorithm, 0, len(sigAlgs)/2)
+ for len(sigAlgs) > 0 {
+ var v uint16
+ if !sigAlgs.readU16(&v) {
+ return false
+ }
+ m.signatureAlgorithms = append(m.signatureAlgorithms, signatureAlgorithm(v))
}
case extensionSupportedVersions:
- if length < 1+2 {
+ var versions byteReader
+ if !body.readU8LengthPrefixed(&versions) || len(body) != 0 {
return false
}
- l := int(data[0])
- if l != length-1 || l%2 == 1 || l < 2 {
- return false
- }
- n := l / 2
- d := data[1:]
- m.supportedVersions = make([]uint16, n)
- for i := range m.supportedVersions {
- m.supportedVersions[i] = uint16(d[0])<<8 | uint16(d[1])
- d = d[2:]
+ m.supportedVersions = make([]uint16, 0, len(versions)/2)
+ for len(versions) > 0 {
+ var v uint16
+ if !versions.readU16(&v) {
+ return false
+ }
+ m.supportedVersions = append(m.supportedVersions, v)
}
case extensionRenegotiationInfo:
- if length < 1 || length != int(data[0])+1 {
+ if !body.readU8LengthPrefixedBytes(&m.secureRenegotiation) || len(body) != 0 {
return false
}
- m.secureRenegotiation = data[1:length]
case extensionALPN:
- if length < 2 {
- return false
- }
- l := int(data[0])<<8 | int(data[1])
- if l != length-2 {
+ var protocols byteReader
+ if !body.readU16LengthPrefixed(&protocols) || len(body) != 0 {
return false
}
- d := data[2:length]
- for len(d) != 0 {
- stringLen := int(d[0])
- d = d[1:]
- if stringLen == 0 || stringLen > len(d) {
+ for len(protocols) > 0 {
+ var protocol []byte
+ if !protocols.readU8LengthPrefixedBytes(&protocol) {
return false
}
- m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
- d = d[stringLen:]
+ m.alpnProtocols = append(m.alpnProtocols, string(protocol))
}
case extensionChannelID:
- if length > 0 {
+ if len(body) != 0 {
return false
}
m.channelIDSupported = true
case extensionExtendedMasterSecret:
- if length != 0 {
+ if len(body) != 0 {
return false
}
m.extendedMasterSecret = true
case extensionUseSRTP:
- if length < 2 {
+ var profiles byteReader
+ var mki []byte
+ if !body.readU16LengthPrefixed(&profiles) ||
+ !body.readU8LengthPrefixedBytes(&mki) ||
+ len(body) != 0 {
return false
}
- l := int(data[0])<<8 | int(data[1])
- if l > length-2 || l%2 != 0 {
- return false
- }
- n := l / 2
- m.srtpProtectionProfiles = make([]uint16, n)
- d := data[2:length]
- for i := 0; i < n; i++ {
- m.srtpProtectionProfiles[i] = uint16(d[0])<<8 | uint16(d[1])
- d = d[2:]
- }
- if len(d) < 1 || int(d[0]) != len(d)-1 {
- return false
+ m.srtpProtectionProfiles = make([]uint16, 0, len(profiles)/2)
+ for len(profiles) > 0 {
+ var v uint16
+ if !profiles.readU16(&v) {
+ return false
+ }
+ m.srtpProtectionProfiles = append(m.srtpProtectionProfiles, v)
}
- m.srtpMasterKeyIdentifier = string(d[1:])
+ m.srtpMasterKeyIdentifier = string(mki)
case extensionSignedCertificateTimestamp:
- if length != 0 {
+ if len(body) != 0 {
return false
}
m.sctListSupported = true
case extensionCustom:
- m.customExtension = string(data[:length])
+ m.customExtension = string(body)
}
- data = data[length:]
if isGREASEValue(extension) {
m.hasGREASEExtension = true