Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
bogdanfinn committed Nov 11, 2022
1 parent 5e87ba6 commit b803d92
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 35 deletions.
6 changes: 6 additions & 0 deletions common.go
Expand Up @@ -242,6 +242,8 @@ type ConnectionState struct {
// Deprecated: this value is always true.
NegotiatedProtocolIsMutual bool

PeerApplicationSettings []byte // application settings provided by peer

// ServerName is the value of the Server Name Indication extension sent by
// the client. It's available both on the server and on the client side.
ServerName string
Expand Down Expand Up @@ -629,6 +631,10 @@ type Config struct {
// ConnectionState.NegotiatedProtocol will be empty.
NextProtos []string

// ApplicationSettings is a set of application settings to use which each
// application protocol.
ApplicationSettings map[string][]byte

// ServerName is used to verify the hostname on the returned
// certificates unless InsecureSkipVerify is given. It is also included
// in the client's handshake to support virtual hosting unless it is
Expand Down
10 changes: 9 additions & 1 deletion conn.go
Expand Up @@ -92,6 +92,10 @@ type Conn struct {
// clientProtocol is the negotiated ALPN protocol.
clientProtocol string

hasApplicationSettings bool
peerApplicationSettings []byte
localApplicationSettings []byte

// input/output
in, out halfConn
rawInput bytes.Buffer // raw input, starting with a record header
Expand Down Expand Up @@ -1076,7 +1080,11 @@ func (c *Conn) readHandshake() (any, error) {
case typeFinished:
m = new(finishedMsg)
case typeEncryptedExtensions:
m = new(encryptedExtensionsMsg)
if c.isClient {
m = new(encryptedExtensionsMsg)
} else {
m = new(clientEncryptedExtensionsMsg)
}
case typeEndOfEarlyData:
m = new(endOfEarlyDataMsg)
case typeKeyUpdate:
Expand Down
30 changes: 30 additions & 0 deletions handshake_client_tls13.go
Expand Up @@ -103,6 +103,9 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
if err := hs.readServerFinished(); err != nil {
return err
}
if err := hs.sendClientEncryptedExtensions(); err != nil {
return err
}
if err := hs.sendClientCertificate(); err != nil {
return err
}
Expand Down Expand Up @@ -476,6 +479,18 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
return err
}
c.clientProtocol = encryptedExtensions.alpnProtocol
c.hasApplicationSettings = encryptedExtensions.hasApplicationSettings
c.peerApplicationSettings = encryptedExtensions.applicationSettings

if c.hasApplicationSettings {
if c.vers < VersionTLS13 {
return errors.New("tls: server sent application settings at invalid version")
}
if len(c.clientProtocol) == 0 {
return errors.New("tls: server sent application settings without ALPN")
}
c.localApplicationSettings = c.config.ApplicationSettings[hs.serverHello.alpnProtocol]
}

return nil
}
Expand Down Expand Up @@ -801,6 +816,21 @@ func (hs *clientHandshakeStateTLS13) decompressCert(m compressedCertificateMsg)
return certMsg, nil
}

func (hs *clientHandshakeStateTLS13) sendClientEncryptedExtensions() error {
c := hs.c
clientEncryptedExtensions := new(clientEncryptedExtensionsMsg)
if c.hasApplicationSettings {
clientEncryptedExtensions.hasApplicationSettings = true
clientEncryptedExtensions.applicationSettings = c.localApplicationSettings
hs.transcript.Write(clientEncryptedExtensions.marshal())
if _, err := c.writeRecord(recordTypeHandshake, clientEncryptedExtensions.marshal()); err != nil {
return err
}
}

return nil
}

// [UTLS SECTION ENDS]

func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
Expand Down
11 changes: 9 additions & 2 deletions handshake_messages.go
Expand Up @@ -893,8 +893,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}

type encryptedExtensionsMsg struct {
raw []byte
alpnProtocol string
raw []byte
alpnProtocol string
hasApplicationSettings bool
applicationSettings []byte
customExtension []byte
}

func (m *encryptedExtensionsMsg) marshal() []byte {
Expand Down Expand Up @@ -953,6 +956,10 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
return false
}
m.alpnProtocol = string(proto)
case ExtensionALPS:
m.hasApplicationSettings = true
m.applicationSettings = []byte(extData)
continue
default:
// Ignore unknown extensions.
continue
Expand Down
12 changes: 7 additions & 5 deletions u_common.go
Expand Up @@ -24,11 +24,13 @@ const (
// utlsExtensionCompressCertificate uint16 = 27

// extensions with 'fake' prefix break connection, if server echoes them back
fakeExtensionTokenBinding uint16 = 24
fakeExtensionChannelIDOld uint16 = 30031 // not IANA assigned
fakeExtensionChannelID uint16 = 30032 // not IANA assigned
fakeExtensionALPS uint16 = 17513 // not IANA assigned
fakeExtensionDelegatedCredentials uint16 = 34
fakeExtensionTokenBinding uint16 = 24
fakeExtensionChannelIDOld uint16 = 30031 // not IANA assigned
fakeExtensionChannelID uint16 = 30032 // not IANA assigned
fakeExtensionALPS uint16 = 17513 // not IANA assigned
//fakeExtensionDelegatedCredentials uint16 = 34

extensionCustom uint16 = 1234 // not IANA assigned

fakeRecordSizeLimit uint16 = 0x001c

Expand Down
4 changes: 2 additions & 2 deletions u_fingerprinter.go
Expand Up @@ -359,7 +359,7 @@ func (f *Fingerprinter) FingerprintClientHello(data []byte) (*ClientHelloSpec, e
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, recordSizeExt)

case fakeExtensionDelegatedCredentials:
case ExtensionDelegatedCredentials:
//https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
var supportedAlgs cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&supportedAlgs) || supportedAlgs.Empty() {
Expand All @@ -374,7 +374,7 @@ func (f *Fingerprinter) FingerprintClientHello(data []byte) (*ClientHelloSpec, e
supportedSignatureAlgorithms = append(
supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &FakeDelegatedCredentialsExtension{supportedSignatureAlgorithms})
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &DelegatedCredentialsExtension{supportedSignatureAlgorithms})

case ExtensionPreSharedKey:
// RFC 8446, Section 4.2.11
Expand Down
85 changes: 60 additions & 25 deletions u_tls_extensions.go
Expand Up @@ -7,6 +7,8 @@ package tls
import (
"errors"
"io"

"golang.org/x/crypto/cryptobyte"
)

type TLSExtension interface {
Expand Down Expand Up @@ -1008,34 +1010,67 @@ func (e *FakeTokenBindingExtension) Read(b []byte) (int, error) {
return e.Len(), io.EOF
}

// https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1

type FakeDelegatedCredentialsExtension struct {
SupportedSignatureAlgorithms []SignatureScheme
}

func (e *FakeDelegatedCredentialsExtension) writeToUConn(uc *UConn) error {
return nil
type clientEncryptedExtensionsMsg struct {
raw []byte
applicationSettings []byte
hasApplicationSettings bool
customExtension []byte
}

func (e *FakeDelegatedCredentialsExtension) Len() int {
return 6 + 2*len(e.SupportedSignatureAlgorithms)
}
func (m *clientEncryptedExtensionsMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}

func (e *FakeDelegatedCredentialsExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
var builder cryptobyte.Builder
builder.AddUint8(typeEncryptedExtensions)
builder.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) {
body.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) {
if m.hasApplicationSettings {
extensions.AddUint16(ExtensionALPS)
extensions.AddUint16LengthPrefixed(func(msg *cryptobyte.Builder) {
msg.AddBytes(m.applicationSettings)
})
}
if len(m.customExtension) > 0 {
extensions.AddUint16(extensionCustom)
extensions.AddUint16LengthPrefixed(func(msg *cryptobyte.Builder) {
msg.AddBytes(m.customExtension)
})
}
})
})

m.raw = builder.BytesOrPanic()
return m.raw
}

func (m *clientEncryptedExtensionsMsg) unmarshal(data []byte) bool {
*m = clientEncryptedExtensionsMsg{raw: data}
s := cryptobyte.String(data)

var extensions cryptobyte.String
if !s.Skip(4) || // message type and uint24 length field
!s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
return false
}
// https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
b[0] = byte(fakeExtensionDelegatedCredentials >> 8)
b[1] = byte(fakeExtensionDelegatedCredentials)
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)

for !extensions.Empty() {
var extension uint16
var extData cryptobyte.String
if !extensions.ReadUint16(&extension) ||
!extensions.ReadUint16LengthPrefixed(&extData) {
return false
}

switch extension {
case ExtensionALPS:
m.hasApplicationSettings = true
m.applicationSettings = []byte(extData)
default:
// Unknown extensions are illegal in EncryptedExtensions.
return false
}
}
return e.Len(), io.EOF
return true
}

0 comments on commit b803d92

Please sign in to comment.