runner: Refactor BoGo clientHelloMsg extension marshalling.

This CL replaces clientHelloMsg's npnAfterAlpn and pskBinderFirst fields
with a new field: prefixExtensions. The extensions in prefixExtensions
are tried first when marshalling clientHelloMsg.

The ability to control extensions' marshalling order will make it
simpler to implement the "outer_extensions" behavior defined in
draft-ietf-tls-esni-07.

Bug: 275
Change-Id: Ib6dcc1e6fa0281f312cb65a9e204415c3f3ef2c6
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/43064
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
chromium-5359
Dan McArdle 5 years ago committed by CQ bot account: commit-bot@chromium.org
parent 51b428153d
commit 6222fe767d
  1. 1
      ssl/test/runner/common.go
  2. 20
      ssl/test/runner/handshake_client.go
  3. 241
      ssl/test/runner/handshake_messages.go

@ -125,6 +125,7 @@ const (
extensionQUICTransportParams uint16 = 0xffa5 // draft-ietf-quic-tls-13
extensionChannelID uint16 = 30032 // not IANA assigned
extensionDelegatedCredentials uint16 = 0x22 // draft-ietf-tls-subcerts-06
extensionDuplicate uint16 = 0xffff // not IANA assigned
)
// TLS signaling cipher suite values

@ -100,6 +100,19 @@ func (c *Conn) clientHandshake() error {
return errors.New("tls: NextProtos values too large")
}
// Translate the bugs that modify ClientHello extension order into a
// list of prefix extensions. The marshal function will try these
// extensions before any others, followed by any remaining extensions in
// the default order.
var prefixExtensions []uint16
if c.config.Bugs.PSKBinderFirst && !c.config.Bugs.OnlyCorruptSecondPSKBinder {
prefixExtensions = append(prefixExtensions, extensionPreSharedKey)
}
if c.config.Bugs.SwapNPNAndALPN {
prefixExtensions = append(prefixExtensions, extensionALPN)
prefixExtensions = append(prefixExtensions, extensionNextProtoNeg)
}
minVersion := c.config.minVersion(c.isDTLS)
maxVersion := c.config.maxVersion(c.isDTLS)
hello := &clientHelloMsg{
@ -119,15 +132,14 @@ func (c *Conn) clientHandshake() error {
channelIDSupported: c.config.ChannelID != nil,
tokenBindingParams: c.config.TokenBindingParams,
tokenBindingVersion: c.config.TokenBindingVersion,
npnAfterAlpn: c.config.Bugs.SwapNPNAndALPN,
extendedMasterSecret: maxVersion >= VersionTLS10,
srtpProtectionProfiles: c.config.SRTPProtectionProfiles,
srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
customExtension: c.config.Bugs.CustomExtension,
pskBinderFirst: c.config.Bugs.PSKBinderFirst && !c.config.Bugs.OnlyCorruptSecondPSKBinder,
omitExtensions: c.config.Bugs.OmitExtensions,
emptyExtensions: c.config.Bugs.EmptyExtensions,
delegatedCredentials: !c.config.Bugs.DisableDelegatedCredentials,
prefixExtensions: prefixExtensions,
}
if maxVersion >= VersionTLS13 {
@ -608,7 +620,9 @@ NextCipherSuite:
hello.hasEarlyData = c.config.Bugs.SendEarlyDataOnSecondClientHello
// The first ClientHello may have skipped this due to OnlyCorruptSecondPSKBinder.
hello.pskBinderFirst = c.config.Bugs.PSKBinderFirst
if c.config.Bugs.PSKBinderFirst && c.config.Bugs.OnlyCorruptSecondPSKBinder {
hello.prefixExtensions = append(hello.prefixExtensions, extensionPreSharedKey)
}
if c.config.Bugs.OmitPSKsOnSecondClientHello {
hello.pskIdentities = nil
hello.pskBinders = nil

@ -285,19 +285,18 @@ type clientHelloMsg struct {
channelIDSupported bool
tokenBindingParams []byte
tokenBindingVersion uint16
npnAfterAlpn bool
extendedMasterSecret bool
srtpProtectionProfiles []uint16
srtpMasterKeyIdentifier string
sctListSupported bool
customExtension string
hasGREASEExtension bool
pskBinderFirst bool
omitExtensions bool
emptyExtensions bool
pad int
compressedCertAlgs []uint16
delegatedCredentials bool
prefixExtensions []uint16
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@ -340,19 +339,18 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.channelIDSupported == m1.channelIDSupported &&
bytes.Equal(m.tokenBindingParams, m1.tokenBindingParams) &&
m.tokenBindingVersion == m1.tokenBindingVersion &&
m.npnAfterAlpn == m1.npnAfterAlpn &&
m.extendedMasterSecret == m1.extendedMasterSecret &&
eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) &&
m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier &&
m.sctListSupported == m1.sctListSupported &&
m.customExtension == m1.customExtension &&
m.hasGREASEExtension == m1.hasGREASEExtension &&
m.pskBinderFirst == m1.pskBinderFirst &&
m.omitExtensions == m1.omitExtensions &&
m.emptyExtensions == m1.emptyExtensions &&
m.pad == m1.pad &&
eqUint16s(m.compressedCertAlgs, m1.compressedCertAlgs) &&
m.delegatedCredentials == m1.delegatedCredentials
m.delegatedCredentials == m1.delegatedCredentials &&
eqUint16s(m.prefixExtensions, m1.prefixExtensions)
}
func (m *clientHelloMsg) marshalKeyShares(bb *byteBuilder) {
@ -390,34 +388,20 @@ func (m *clientHelloMsg) marshal() []byte {
compressionMethods := hello.addU8LengthPrefixed()
compressionMethods.addBytes(m.compressionMethods)
extensions := hello.addU16LengthPrefixed()
if len(m.pskIdentities) > 0 && m.pskBinderFirst {
extensions.addU16(extensionPreSharedKey)
pskExtension := extensions.addU16LengthPrefixed()
pskIdentities := pskExtension.addU16LengthPrefixed()
for _, psk := range m.pskIdentities {
pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
pskIdentities.addU32(psk.obfuscatedTicketAge)
}
pskBinders := pskExtension.addU16LengthPrefixed()
for _, binder := range m.pskBinders {
pskBinders.addU8LengthPrefixed().addBytes(binder)
}
type extension struct {
id uint16
body []byte
}
var extensions []extension
if m.duplicateExtension {
// Add a duplicate bogus extension at the beginning and end.
extensions.addU16(0xffff)
extensions.addU16(0) // 0-length for empty extension
extensions = append(extensions, extension{id: extensionDuplicate})
}
if m.nextProtoNeg && !m.npnAfterAlpn {
extensions.addU16(extensionNextProtoNeg)
extensions.addU16(0) // The length is always 0
if m.nextProtoNeg {
extensions = append(extensions, extension{id: extensionNextProtoNeg})
}
if len(m.serverName) > 0 {
extensions.addU16(extensionServerName)
serverNameList := extensions.addU16LengthPrefixed()
// RFC 3546, section 3.1
//
// struct {
@ -437,138 +421,170 @@ func (m *clientHelloMsg) marshal() []byte {
// ServerName server_name_list<1..2^16-1>
// } ServerNameList;
serverNameList := newByteBuilder()
serverName := serverNameList.addU16LengthPrefixed()
serverName.addU8(0) // NameType host_name(0)
hostName := serverName.addU16LengthPrefixed()
hostName.addBytes([]byte(m.serverName))
extensions = append(extensions, extension{
id: extensionServerName,
body: serverNameList.finish(),
})
}
if m.ocspStapling {
extensions.addU16(extensionStatusRequest)
certificateStatusRequest := extensions.addU16LengthPrefixed()
certificateStatusRequest := newByteBuilder()
// RFC 4366, section 3.6
certificateStatusRequest.addU8(1) // OCSP type
// Two zero valued uint16s for the two lengths.
certificateStatusRequest.addU16(0) // ResponderID length
certificateStatusRequest.addU16(0) // Extensions length
extensions = append(extensions, extension{
id: extensionStatusRequest,
body: certificateStatusRequest.finish(),
})
}
if len(m.supportedCurves) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.1.1
extensions.addU16(extensionSupportedCurves)
supportedCurvesList := extensions.addU16LengthPrefixed()
supportedCurvesList := newByteBuilder()
supportedCurves := supportedCurvesList.addU16LengthPrefixed()
for _, curve := range m.supportedCurves {
supportedCurves.addU16(uint16(curve))
}
extensions = append(extensions, extension{
id: extensionSupportedCurves,
body: supportedCurvesList.finish(),
})
}
if len(m.supportedPoints) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.1.2
extensions.addU16(extensionSupportedPoints)
supportedPointsList := extensions.addU16LengthPrefixed()
supportedPointsList := newByteBuilder()
supportedPoints := supportedPointsList.addU8LengthPrefixed()
supportedPoints.addBytes(m.supportedPoints)
extensions = append(extensions, extension{
id: extensionSupportedPoints,
body: supportedPointsList.finish(),
})
}
if m.hasKeyShares {
extensions.addU16(extensionKeyShare)
keyShareList := extensions.addU16LengthPrefixed()
keyShareList := newByteBuilder()
m.marshalKeyShares(keyShareList)
extensions = append(extensions, extension{
id: extensionKeyShare,
body: keyShareList.finish(),
})
}
if len(m.pskKEModes) > 0 {
extensions.addU16(extensionPSKKeyExchangeModes)
pskModesExtension := extensions.addU16LengthPrefixed()
pskModesExtension := newByteBuilder()
pskModesExtension.addU8LengthPrefixed().addBytes(m.pskKEModes)
extensions = append(extensions, extension{
id: extensionPSKKeyExchangeModes,
body: pskModesExtension.finish(),
})
}
if m.hasEarlyData {
extensions.addU16(extensionEarlyData)
extensions.addU16(0) // The length is zero.
extensions = append(extensions, extension{id: extensionEarlyData})
}
if len(m.tls13Cookie) > 0 {
extensions.addU16(extensionCookie)
body := extensions.addU16LengthPrefixed()
body := newByteBuilder()
body.addU16LengthPrefixed().addBytes(m.tls13Cookie)
extensions = append(extensions, extension{
id: extensionCookie,
body: body.finish(),
})
}
if m.ticketSupported {
// http://tools.ietf.org/html/rfc5077#section-3.2
extensions.addU16(extensionSessionTicket)
sessionTicketExtension := extensions.addU16LengthPrefixed()
sessionTicketExtension.addBytes(m.sessionTicket)
extensions = append(extensions, extension{
id: extensionSessionTicket,
body: m.sessionTicket,
})
}
if len(m.signatureAlgorithms) > 0 {
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
extensions.addU16(extensionSignatureAlgorithms)
signatureAlgorithmsExtension := extensions.addU16LengthPrefixed()
signatureAlgorithmsExtension := newByteBuilder()
signatureAlgorithms := signatureAlgorithmsExtension.addU16LengthPrefixed()
for _, sigAlg := range m.signatureAlgorithms {
signatureAlgorithms.addU16(uint16(sigAlg))
}
extensions = append(extensions, extension{
id: extensionSignatureAlgorithms,
body: signatureAlgorithmsExtension.finish(),
})
}
if len(m.signatureAlgorithmsCert) > 0 {
extensions.addU16(extensionSignatureAlgorithmsCert)
signatureAlgorithmsCertExtension := extensions.addU16LengthPrefixed()
signatureAlgorithmsCertExtension := newByteBuilder()
signatureAlgorithmsCert := signatureAlgorithmsCertExtension.addU16LengthPrefixed()
for _, sigAlg := range m.signatureAlgorithmsCert {
signatureAlgorithmsCert.addU16(uint16(sigAlg))
}
extensions = append(extensions, extension{
id: extensionSignatureAlgorithmsCert,
body: signatureAlgorithmsCertExtension.finish(),
})
}
if len(m.supportedVersions) > 0 {
extensions.addU16(extensionSupportedVersions)
supportedVersionsExtension := extensions.addU16LengthPrefixed()
supportedVersionsExtension := newByteBuilder()
supportedVersions := supportedVersionsExtension.addU8LengthPrefixed()
for _, version := range m.supportedVersions {
supportedVersions.addU16(uint16(version))
}
extensions = append(extensions, extension{
id: extensionSupportedVersions,
body: supportedVersionsExtension.finish(),
})
}
if m.secureRenegotiation != nil {
extensions.addU16(extensionRenegotiationInfo)
secureRenegoExt := extensions.addU16LengthPrefixed()
secureRenego := secureRenegoExt.addU8LengthPrefixed()
secureRenego.addBytes(m.secureRenegotiation)
secureRenegoExt := newByteBuilder()
secureRenegoExt.addU8LengthPrefixed().addBytes(m.secureRenegotiation)
extensions = append(extensions, extension{
id: extensionRenegotiationInfo,
body: secureRenegoExt.finish(),
})
}
if len(m.alpnProtocols) > 0 {
// https://tools.ietf.org/html/rfc7301#section-3.1
extensions.addU16(extensionALPN)
alpnExtension := extensions.addU16LengthPrefixed()
alpnExtension := newByteBuilder()
protocolNameList := alpnExtension.addU16LengthPrefixed()
for _, s := range m.alpnProtocols {
protocolName := protocolNameList.addU8LengthPrefixed()
protocolName.addBytes([]byte(s))
}
extensions = append(extensions, extension{
id: extensionALPN,
body: alpnExtension.finish(),
})
}
if len(m.quicTransportParams) > 0 {
extensions.addU16(extensionQUICTransportParams)
params := extensions.addU16LengthPrefixed()
params.addBytes(m.quicTransportParams)
extensions = append(extensions, extension{
id: extensionQUICTransportParams,
body: m.quicTransportParams,
})
}
if m.channelIDSupported {
extensions.addU16(extensionChannelID)
extensions.addU16(0) // Length is always 0
extensions = append(extensions, extension{id: extensionChannelID})
}
if m.tokenBindingParams != nil {
extensions.addU16(extensionTokenBinding)
tokbindExtension := extensions.addU16LengthPrefixed()
tokbindExtension := newByteBuilder()
tokbindExtension.addU16(m.tokenBindingVersion)
tokbindParams := tokbindExtension.addU8LengthPrefixed()
tokbindParams.addBytes(m.tokenBindingParams)
}
if m.nextProtoNeg && m.npnAfterAlpn {
extensions.addU16(extensionNextProtoNeg)
extensions.addU16(0) // Length is always 0
extensions = append(extensions, extension{
id: extensionTokenBinding,
body: tokbindExtension.finish(),
})
}
if m.duplicateExtension {
// Add a duplicate bogus extension at the beginning and end.
extensions.addU16(0xffff)
extensions.addU16(0)
extensions = append(extensions, extension{id: extensionDuplicate})
}
if m.extendedMasterSecret {
// https://tools.ietf.org/html/rfc7627
extensions.addU16(extensionExtendedMasterSecret)
extensions.addU16(0) // Length is always 0
extensions = append(extensions, extension{id: extensionExtendedMasterSecret})
}
if len(m.srtpProtectionProfiles) > 0 {
// https://tools.ietf.org/html/rfc5764#section-4.1.1
extensions.addU16(extensionUseSRTP)
useSrtpExt := extensions.addU16LengthPrefixed()
useSrtpExt := newByteBuilder()
srtpProtectionProfiles := useSrtpExt.addU16LengthPrefixed()
for _, p := range m.srtpProtectionProfiles {
@ -576,38 +592,47 @@ func (m *clientHelloMsg) marshal() []byte {
}
srtpMki := useSrtpExt.addU8LengthPrefixed()
srtpMki.addBytes([]byte(m.srtpMasterKeyIdentifier))
extensions = append(extensions, extension{
id: extensionUseSRTP,
body: useSrtpExt.finish(),
})
}
if m.sctListSupported {
extensions.addU16(extensionSignedCertificateTimestamp)
extensions.addU16(0) // Length is always 0
extensions = append(extensions, extension{id: extensionSignedCertificateTimestamp})
}
if l := len(m.customExtension); l > 0 {
extensions.addU16(extensionCustom)
customExt := extensions.addU16LengthPrefixed()
customExt.addBytes([]byte(m.customExtension))
extensions = append(extensions, extension{
id: extensionCustom,
body: []byte(m.customExtension),
})
}
if len(m.compressedCertAlgs) > 0 {
extensions.addU16(extensionCompressedCertAlgs)
body := extensions.addU16LengthPrefixed()
body := newByteBuilder()
algIDs := body.addU8LengthPrefixed()
for _, v := range m.compressedCertAlgs {
algIDs.addU16(v)
}
extensions = append(extensions, extension{
id: extensionCompressedCertAlgs,
body: body.finish(),
})
}
if m.delegatedCredentials {
extensions.addU16(extensionDelegatedCredentials)
body := extensions.addU16LengthPrefixed()
body := newByteBuilder()
signatureSchemeList := body.addU16LengthPrefixed()
for _, sigAlg := range m.signatureAlgorithms {
signatureSchemeList.addU16(uint16(sigAlg))
}
extensions = append(extensions, extension{
id: extensionDelegatedCredentials,
body: body.finish(),
})
}
// The PSK extension must be last. See https://tools.ietf.org/html/rfc8446#section-4.2.11
if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
extensions.addU16(extensionPreSharedKey)
pskExtension := extensions.addU16LengthPrefixed()
if len(m.pskIdentities) > 0 {
pskExtension := newByteBuilder()
pskIdentities := pskExtension.addU16LengthPrefixed()
for _, psk := range m.pskIdentities {
pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
@ -617,11 +642,43 @@ func (m *clientHelloMsg) marshal() []byte {
for _, binder := range m.pskBinders {
pskBinders.addU8LengthPrefixed().addBytes(binder)
}
extensions = append(extensions, extension{
id: extensionPreSharedKey,
body: pskExtension.finish(),
})
}
// Write each extension in |extensions| to the |hello| message, hoisting
// the extensions named in |m.prefixExtensions| to the front.
extensionsBB := hello.addU16LengthPrefixed()
extMap := make(map[uint16][]byte)
for _, ext := range extensions {
extMap[ext.id] = ext.body
}
// Write each of the prefix extensions, if we have it.
for _, extID := range m.prefixExtensions {
if body, ok := extMap[extID]; ok {
extensionsBB.addU16(extID)
extensionsBB.addU16LengthPrefixed().addBytes(body)
}
}
// Forget each of the prefix extensions. This loop is separate from the
// extension-writing loop because |m.prefixExtensions| may contain
// duplicates.
for _, extID := range m.prefixExtensions {
delete(extMap, extID)
}
// Write each of the remaining extensions in their original order.
for _, ext := range extensions {
if _, ok := extMap[ext.id]; ok {
extensionsBB.addU16(ext.id)
extensionsBB.addU16LengthPrefixed().addBytes(ext.body)
}
}
if m.pad != 0 && hello.len()%m.pad != 0 {
extensions.addU16(extensionPadding)
padding := extensions.addU16LengthPrefixed()
extensionsBB.addU16(extensionPadding)
padding := extensionsBB.addU16LengthPrefixed()
// Note hello.len() has changed at this point from the length
// prefix.
if l := hello.len() % m.pad; l != 0 {
@ -1236,7 +1293,7 @@ type serverExtensions struct {
func (m *serverExtensions) marshal(extensions *byteBuilder) {
if m.duplicateExtension {
// Add a duplicate bogus extension at the beginning and end.
extensions.addU16(0xffff)
extensions.addU16(extensionDuplicate)
extensions.addU16(0) // length = 0 for empty extension
}
if m.nextProtoNeg && !m.npnAfterAlpn {
@ -1286,7 +1343,7 @@ func (m *serverExtensions) marshal(extensions *byteBuilder) {
}
if m.duplicateExtension {
// Add a duplicate bogus extension at the beginning and end.
extensions.addU16(0xffff)
extensions.addU16(extensionDuplicate)
extensions.addU16(0)
}
if m.extendedMasterSecret {

Loading…
Cancel
Save