Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
689 lines (581 sloc) 16.5 KB
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
import (
"errors"
"io"
)
type TLSExtension interface {
writeToUConn(*UConn) error
Len() int // includes header
// Read reads up to len(p) bytes into p.
// It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
Read(p []byte) (n int, err error) // implements io.Reader
}
type NPNExtension struct {
NextProtos []string
}
func (e *NPNExtension) writeToUConn(uc *UConn) error {
uc.config.NextProtos = e.NextProtos
uc.HandshakeState.Hello.NextProtoNeg = true
return nil
}
func (e *NPNExtension) Len() int {
return 4
}
func (e *NPNExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
b[0] = byte(extensionNextProtoNeg >> 8)
b[1] = byte(extensionNextProtoNeg & 0xff)
// The length is always 0
return e.Len(), io.EOF
}
type SNIExtension struct {
ServerName string // not an array because go crypto/tls doesn't support multiple SNIs
}
func (e *SNIExtension) writeToUConn(uc *UConn) error {
uc.config.ServerName = e.ServerName
uc.HandshakeState.Hello.ServerName = e.ServerName
return nil
}
func (e *SNIExtension) Len() int {
return 4 + 2 + 1 + 2 + len(e.ServerName)
}
func (e *SNIExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// RFC 3546, section 3.1
b[0] = byte(extensionServerName >> 8)
b[1] = byte(extensionServerName)
b[2] = byte((len(e.ServerName) + 5) >> 8)
b[3] = byte((len(e.ServerName) + 5))
b[4] = byte((len(e.ServerName) + 3) >> 8)
b[5] = byte(len(e.ServerName) + 3)
// b[6] Server Name Type: host_name (0)
b[7] = byte(len(e.ServerName) >> 8)
b[8] = byte(len(e.ServerName))
copy(b[9:], []byte(e.ServerName))
return e.Len(), io.EOF
}
type StatusRequestExtension struct {
}
func (e *StatusRequestExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.OcspStapling = true
return nil
}
func (e *StatusRequestExtension) Len() int {
return 9
}
func (e *StatusRequestExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// RFC 4366, section 3.6
b[0] = byte(extensionStatusRequest >> 8)
b[1] = byte(extensionStatusRequest)
b[2] = 0
b[3] = 5
b[4] = 1 // OCSP type
// Two zero valued uint16s for the two lengths.
return e.Len(), io.EOF
}
type SupportedCurvesExtension struct {
Curves []CurveID
}
func (e *SupportedCurvesExtension) writeToUConn(uc *UConn) error {
uc.config.CurvePreferences = e.Curves
uc.HandshakeState.Hello.SupportedCurves = e.Curves
return nil
}
func (e *SupportedCurvesExtension) Len() int {
return 6 + 2*len(e.Curves)
}
func (e *SupportedCurvesExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// http://tools.ietf.org/html/rfc4492#section-5.5.1
b[0] = byte(extensionSupportedCurves >> 8)
b[1] = byte(extensionSupportedCurves)
b[2] = byte((2 + 2*len(e.Curves)) >> 8)
b[3] = byte((2 + 2*len(e.Curves)))
b[4] = byte((2 * len(e.Curves)) >> 8)
b[5] = byte((2 * len(e.Curves)))
for i, curve := range e.Curves {
b[6+2*i] = byte(curve >> 8)
b[7+2*i] = byte(curve)
}
return e.Len(), io.EOF
}
type SupportedPointsExtension struct {
SupportedPoints []uint8
}
func (e *SupportedPointsExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.SupportedPoints = e.SupportedPoints
return nil
}
func (e *SupportedPointsExtension) Len() int {
return 5 + len(e.SupportedPoints)
}
func (e *SupportedPointsExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// http://tools.ietf.org/html/rfc4492#section-5.5.2
b[0] = byte(extensionSupportedPoints >> 8)
b[1] = byte(extensionSupportedPoints)
b[2] = byte((1 + len(e.SupportedPoints)) >> 8)
b[3] = byte((1 + len(e.SupportedPoints)))
b[4] = byte((len(e.SupportedPoints)))
for i, pointFormat := range e.SupportedPoints {
b[5+i] = pointFormat
}
return e.Len(), io.EOF
}
type SignatureAlgorithmsExtension struct {
SupportedSignatureAlgorithms []SignatureScheme
}
func (e *SignatureAlgorithmsExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.SupportedSignatureAlgorithms = e.SupportedSignatureAlgorithms
return nil
}
func (e *SignatureAlgorithmsExtension) Len() int {
return 6 + 2*len(e.SupportedSignatureAlgorithms)
}
func (e *SignatureAlgorithmsExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
b[0] = byte(extensionSignatureAlgorithms >> 8)
b[1] = byte(extensionSignatureAlgorithms)
b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
b[3] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)))
b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
b[5] = byte((2 * len(e.SupportedSignatureAlgorithms)))
for i, sigAndHash := range e.SupportedSignatureAlgorithms {
b[6+2*i] = byte(sigAndHash >> 8)
b[7+2*i] = byte(sigAndHash)
}
return e.Len(), io.EOF
}
type RenegotiationInfoExtension struct {
renegotiation RenegotiationSupport
SecureRenegotiation []byte // if empty, default []byte{0} is assumed
}
func (e *RenegotiationInfoExtension) writeToUConn(uc *UConn) error {
uc.config.Renegotiation = e.renegotiation
switch e.renegotiation {
case RenegotiateOnceAsClient:
fallthrough
case RenegotiateFreelyAsClient:
uc.HandshakeState.Hello.SecureRenegotiationSupported = true
// Note that if we manage to use this in renegotiation(currently only in initial handshake), we'd have to point
// uc.ClientHelloMsg.SecureRenegotiation = chs.C.clientFinished
// and probably do something else. It's a mess.
case RenegotiateNever:
default:
}
return nil
}
func (e *RenegotiationInfoExtension) Len() int {
switch e.renegotiation {
case RenegotiateOnceAsClient:
fallthrough
case RenegotiateFreelyAsClient:
extBodyLen := len(e.SecureRenegotiation)
if extBodyLen == 0 {
extBodyLen = 1
}
return 4 + extBodyLen
case RenegotiateNever:
default:
}
return 0
}
func (e *RenegotiationInfoExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
switch e.renegotiation {
case RenegotiateOnceAsClient:
fallthrough
case RenegotiateFreelyAsClient:
secureRenegBody := e.SecureRenegotiation
if len(secureRenegBody) == 0 {
secureRenegBody = []byte{0}
}
extBodyLen := len(secureRenegBody)
b[0] = byte(extensionRenegotiationInfo >> 8)
b[1] = byte(extensionRenegotiationInfo & 0xff)
b[2] = byte(extBodyLen >> 8)
b[3] = byte(extBodyLen)
copy(b[4:], secureRenegBody)
if len(e.SecureRenegotiation) != 0 {
copy(b[5:], e.SecureRenegotiation)
}
case RenegotiateNever:
default:
}
return e.Len(), io.EOF
}
type ALPNExtension struct {
AlpnProtocols []string
}
func (e *ALPNExtension) writeToUConn(uc *UConn) error {
uc.config.NextProtos = e.AlpnProtocols
uc.HandshakeState.Hello.AlpnProtocols = e.AlpnProtocols
return nil
}
func (e *ALPNExtension) Len() int {
bLen := 2 + 2 + 2
for _, s := range e.AlpnProtocols {
bLen += 1 + len(s)
}
return bLen
}
func (e *ALPNExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
b[0] = byte(extensionALPN >> 8)
b[1] = byte(extensionALPN & 0xff)
lengths := b[2:]
b = b[6:]
stringsLength := 0
for _, s := range e.AlpnProtocols {
l := len(s)
b[0] = byte(l)
copy(b[1:], s)
b = b[1+l:]
stringsLength += 1 + l
}
lengths[2] = byte(stringsLength >> 8)
lengths[3] = byte(stringsLength)
stringsLength += 2
lengths[0] = byte(stringsLength >> 8)
lengths[1] = byte(stringsLength)
return e.Len(), io.EOF
}
type SCTExtension struct {
}
func (e *SCTExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.Scts = true
return nil
}
func (e *SCTExtension) Len() int {
return 4
}
func (e *SCTExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// https://tools.ietf.org/html/rfc6962#section-3.3.1
b[0] = byte(extensionSCT >> 8)
b[1] = byte(extensionSCT)
// zero uint16 for the zero-length extension_data
return e.Len(), io.EOF
}
type SessionTicketExtension struct {
Session *ClientSessionState
}
func (e *SessionTicketExtension) writeToUConn(uc *UConn) error {
if e.Session != nil {
uc.HandshakeState.Session = e.Session
uc.HandshakeState.Hello.SessionTicket = e.Session.sessionTicket
}
return nil
}
func (e *SessionTicketExtension) Len() int {
if e.Session != nil {
return 4 + len(e.Session.sessionTicket)
}
return 4
}
func (e *SessionTicketExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
extBodyLen := e.Len() - 4
b[0] = byte(extensionSessionTicket >> 8)
b[1] = byte(extensionSessionTicket)
b[2] = byte(extBodyLen >> 8)
b[3] = byte(extBodyLen)
if extBodyLen > 0 {
copy(b[4:], e.Session.sessionTicket)
}
return e.Len(), io.EOF
}
type GenericExtension struct {
id uint16
data []byte
}
func (e *GenericExtension) writeToUConn(uc *UConn) error {
return nil
}
func (e *GenericExtension) Len() int {
return 4 + len(e.data)
}
func (e *GenericExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
b[0] = byte(e.id >> 8)
b[1] = byte(e.id)
b[2] = byte(len(e.data) >> 8)
b[3] = byte(len(e.data))
if len(e.data) > 0 {
copy(b[4:], e.data)
}
return e.Len(), io.EOF
}
/*
FAKE EXTENSIONS
*/
type FakeChannelIDExtension struct {
}
func (e *FakeChannelIDExtension) writeToUConn(uc *UConn) error {
return nil
}
func (e *FakeChannelIDExtension) Len() int {
return 4
}
func (e *FakeChannelIDExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// https://tools.ietf.org/html/draft-balfanz-tls-channelid-00
b[0] = byte(fakeExtensionChannelID >> 8)
b[1] = byte(fakeExtensionChannelID & 0xff)
// The length is 0
return e.Len(), io.EOF
}
type UtlsExtendedMasterSecretExtension struct {
}
// TODO: update when this extension is implemented in crypto/tls
// but we probably won't have to enable it in Config
func (e *UtlsExtendedMasterSecretExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.Ems = true
return nil
}
func (e *UtlsExtendedMasterSecretExtension) Len() int {
return 4
}
func (e *UtlsExtendedMasterSecretExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// https://tools.ietf.org/html/rfc7627
b[0] = byte(utlsExtensionExtendedMasterSecret >> 8)
b[1] = byte(utlsExtensionExtendedMasterSecret)
// The length is 0
return e.Len(), io.EOF
}
var extendedMasterSecretLabel = []byte("extended master secret")
// extendedMasterFromPreMasterSecret generates the master secret from the pre-master
// secret and session hash. See https://tools.ietf.org/html/rfc7627#section-4
func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, fh finishedHash) []byte {
sessionHash := fh.Sum()
masterSecret := make([]byte, masterSecretLength)
prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, sessionHash)
return masterSecret
}
// GREASE stinks with dead parrots, have to be super careful, and, if possible, not include GREASE
// https://github.com/google/boringssl/blob/1c68fa2350936ca5897a66b430ebaf333a0e43f5/ssl/internal.h
const (
ssl_grease_cipher = iota
ssl_grease_group
ssl_grease_extension1
ssl_grease_extension2
ssl_grease_version
ssl_grease_ticket_extension
ssl_grease_last_index = ssl_grease_ticket_extension
)
// it is responsibility of user not to generate multiple grease extensions with same value
type UtlsGREASEExtension struct {
Value uint16
Body []byte // in Chrome first grease has empty body, second grease has a single zero byte
}
func (e *UtlsGREASEExtension) writeToUConn(uc *UConn) error {
return nil
}
// will panic if ssl_grease_last_index[index] is out of bounds.
func GetBoringGREASEValue(greaseSeed [ssl_grease_last_index]uint16, index int) uint16 {
// GREASE value is back from deterministic to random.
// https://github.com/google/boringssl/blob/a365138ac60f38b64bfc608b493e0f879845cb88/ssl/handshake_client.c#L530
ret := uint16(greaseSeed[index])
/* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
ret = (ret & 0xf0) | 0x0a
ret |= ret << 8
return ret
}
func (e *UtlsGREASEExtension) Len() int {
return 4 + len(e.Body)
}
func (e *UtlsGREASEExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
b[0] = byte(e.Value >> 8)
b[1] = byte(e.Value)
b[2] = byte(len(e.Body) >> 8)
b[3] = byte(len(e.Body))
if len(e.Body) > 0 {
copy(b[4:], e.Body)
}
return e.Len(), io.EOF
}
type UtlsPaddingExtension struct {
PaddingLen int
WillPad bool // set to false to disable extension
// Functor for deciding on padding length based on unpadded ClientHello length.
// If willPad is false, then this extension should not be included.
GetPaddingLen func(clientHelloUnpaddedLen int) (paddingLen int, willPad bool)
}
func (e *UtlsPaddingExtension) writeToUConn(uc *UConn) error {
return nil
}
func (e *UtlsPaddingExtension) Len() int {
if e.WillPad {
return 4 + e.PaddingLen
} else {
return 0
}
}
func (e *UtlsPaddingExtension) Update(clientHelloUnpaddedLen int) {
if e.GetPaddingLen != nil {
e.PaddingLen, e.WillPad = e.GetPaddingLen(clientHelloUnpaddedLen)
}
}
func (e *UtlsPaddingExtension) Read(b []byte) (int, error) {
if !e.WillPad {
return 0, io.EOF
}
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// https://tools.ietf.org/html/rfc7627
b[0] = byte(utlsExtensionPadding >> 8)
b[1] = byte(utlsExtensionPadding)
b[2] = byte(e.PaddingLen >> 8)
b[3] = byte(e.PaddingLen)
return e.Len(), io.EOF
}
// https://github.com/google/boringssl/blob/7d7554b6b3c79e707e25521e61e066ce2b996e4c/ssl/t1_lib.c#L2803
func BoringPaddingStyle(unpaddedLen int) (int, bool) {
if unpaddedLen > 0xff && unpaddedLen < 0x200 {
paddingLen := 0x200 - unpaddedLen
if paddingLen >= 4+1 {
paddingLen -= 4
} else {
paddingLen = 1
}
return paddingLen, true
}
return 0, false
}
/* TLS 1.3 */
type KeyShareExtension struct {
KeyShares []KeyShare
}
func (e *KeyShareExtension) Len() int {
return 4 + 2 + e.keySharesLen()
}
func (e *KeyShareExtension) keySharesLen() int {
extLen := 0
for _, ks := range e.KeyShares {
extLen += 4 + len(ks.Data)
}
return extLen
}
func (e *KeyShareExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
b[0] = byte(extensionKeyShare >> 8)
b[1] = byte(extensionKeyShare)
keySharesLen := e.keySharesLen()
b[2] = byte((keySharesLen + 2) >> 8)
b[3] = byte((keySharesLen + 2))
b[4] = byte((keySharesLen) >> 8)
b[5] = byte((keySharesLen))
i := 6
for _, ks := range e.KeyShares {
b[i] = byte(ks.Group >> 8)
b[i+1] = byte(ks.Group)
b[i+2] = byte(len(ks.Data) >> 8)
b[i+3] = byte(len(ks.Data))
copy(b[i+4:], ks.Data)
i += 4 + len(ks.Data)
}
return e.Len(), io.EOF
}
func (e *KeyShareExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.KeyShares = e.KeyShares
return nil
}
type PSKKeyExchangeModesExtension struct {
Modes []uint8
}
func (e *PSKKeyExchangeModesExtension) Len() int {
return 4 + 1 + len(e.Modes)
}
func (e *PSKKeyExchangeModesExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
if len(e.Modes) > 255 {
return 0, errors.New("too many PSK Key Exchange modes")
}
b[0] = byte(extensionPSKModes >> 8)
b[1] = byte(extensionPSKModes)
modesLen := len(e.Modes)
b[2] = byte((modesLen + 1) >> 8)
b[3] = byte((modesLen + 1))
b[4] = byte(modesLen)
if len(e.Modes) > 0 {
copy(b[5:], e.Modes)
}
return e.Len(), io.EOF
}
func (e *PSKKeyExchangeModesExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.PskModes = e.Modes
return nil
}
type SupportedVersionsExtension struct {
Versions []uint16
}
func (e *SupportedVersionsExtension) writeToUConn(uc *UConn) error {
uc.HandshakeState.Hello.SupportedVersions = e.Versions
return nil
}
func (e *SupportedVersionsExtension) Len() int {
return 4 + 1 + (2 * len(e.Versions))
}
func (e *SupportedVersionsExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
extLen := 2 * len(e.Versions)
if extLen > 255 {
return 0, errors.New("too many supported versions")
}
b[0] = byte(extensionSupportedVersions >> 8)
b[1] = byte(extensionSupportedVersions)
b[2] = byte((extLen + 1) >> 8)
b[3] = byte((extLen + 1))
b[4] = byte(extLen)
i := 5
for _, sv := range e.Versions {
b[i] = byte(sv >> 8)
b[i+1] = byte(sv)
i += 2
}
return e.Len(), io.EOF
}
// TODO: FakeCertificateCompressionAlgorithmsExtension
// TODO: FakeRecordSizeLimitExtension
You can’t perform that action at this time.