mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-03 20:17:36 +03:00
Fix #33: renegotiation and export extension fields
Renegotiation: - Disallow specifying the body of Renegotiation extensions to avoid assumption that it will be verified. - Marshal the extension, if it is present in the uconn.Extensions list, even if Renegotiation is set to Never. Exports all unexported uTLS extension fields. Fixes #33
This commit is contained in:
parent
4da6795186
commit
1552a980ce
2 changed files with 34 additions and 57 deletions
16
u_parrots.go
16
u_parrots.go
|
@ -39,7 +39,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
CompressionMethods: []byte{compressionNone},
|
||||
Extensions: []TLSExtension{
|
||||
&UtlsGREASEExtension{},
|
||||
&RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient},
|
||||
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
|
||||
&SNIExtension{},
|
||||
&UtlsExtendedMasterSecretExtension{},
|
||||
&SessionTicketExtension{},
|
||||
|
@ -94,7 +94,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
},
|
||||
Extensions: []TLSExtension{
|
||||
&UtlsGREASEExtension{},
|
||||
&RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient},
|
||||
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
|
||||
&SNIExtension{},
|
||||
&UtlsExtendedMasterSecretExtension{},
|
||||
&SessionTicketExtension{},
|
||||
|
@ -166,7 +166,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
&UtlsGREASEExtension{},
|
||||
&SNIExtension{},
|
||||
&UtlsExtendedMasterSecretExtension{},
|
||||
&RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient},
|
||||
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
|
||||
&SupportedCurvesExtension{[]CurveID{
|
||||
CurveID(GREASE_PLACEHOLDER),
|
||||
X25519,
|
||||
|
@ -237,7 +237,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
Extensions: []TLSExtension{
|
||||
&SNIExtension{},
|
||||
&UtlsExtendedMasterSecretExtension{},
|
||||
&RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient},
|
||||
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
|
||||
&SupportedCurvesExtension{[]CurveID{X25519, CurveP256, CurveP384, CurveP521}},
|
||||
&SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}},
|
||||
&SessionTicketExtension{},
|
||||
|
@ -290,7 +290,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
Extensions: []TLSExtension{
|
||||
&SNIExtension{},
|
||||
&UtlsExtendedMasterSecretExtension{},
|
||||
&RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient},
|
||||
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
|
||||
&SupportedCurvesExtension{[]CurveID{
|
||||
X25519,
|
||||
CurveP256,
|
||||
|
@ -361,7 +361,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
compressionNone,
|
||||
},
|
||||
Extensions: []TLSExtension{
|
||||
&RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient},
|
||||
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
|
||||
&SNIExtension{},
|
||||
&UtlsExtendedMasterSecretExtension{},
|
||||
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
|
||||
|
@ -421,7 +421,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
compressionNone,
|
||||
},
|
||||
Extensions: []TLSExtension{
|
||||
&RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient},
|
||||
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
|
||||
&SNIExtension{},
|
||||
&UtlsExtendedMasterSecretExtension{},
|
||||
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
|
||||
|
@ -722,7 +722,7 @@ func (uconn *UConn) generateRandomizedSpec() (ClientHelloSpec, error) {
|
|||
curves := SupportedCurvesExtension{curveIDs}
|
||||
|
||||
padding := UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}
|
||||
reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
|
||||
reneg := RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient}
|
||||
|
||||
p.Extensions = []TLSExtension{
|
||||
&sni,
|
||||
|
|
|
@ -194,20 +194,18 @@ func (e *SignatureAlgorithmsExtension) Read(b []byte) (int, error) {
|
|||
}
|
||||
|
||||
type RenegotiationInfoExtension struct {
|
||||
renegotiation RenegotiationSupport
|
||||
SecureRenegotiation []byte // if empty, default []byte{0} is assumed
|
||||
// Renegotiation field limits how many times client will perform renegotiation: no limit, once, or never.
|
||||
// The extension still will be sent, even if Renegotiation is set to RenegotiateNever.
|
||||
Renegotiation RenegotiationSupport
|
||||
}
|
||||
|
||||
func (e *RenegotiationInfoExtension) writeToUConn(uc *UConn) error {
|
||||
uc.config.Renegotiation = e.renegotiation
|
||||
switch e.renegotiation {
|
||||
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:
|
||||
}
|
||||
|
@ -215,47 +213,25 @@ func (e *RenegotiationInfoExtension) writeToUConn(uc *UConn) error {
|
|||
}
|
||||
|
||||
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
|
||||
return 5
|
||||
}
|
||||
|
||||
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)
|
||||
var extInnerBody []byte // inner body is empty
|
||||
innerBodyLen := len(extInnerBody)
|
||||
extBodyLen := innerBodyLen + 1
|
||||
|
||||
b[0] = byte(extensionRenegotiationInfo >> 8)
|
||||
b[1] = byte(extensionRenegotiationInfo & 0xff)
|
||||
b[2] = byte(extBodyLen >> 8)
|
||||
b[3] = byte(extBodyLen)
|
||||
b[4] = byte(innerBodyLen)
|
||||
copy(b[5:], extInnerBody)
|
||||
|
||||
if len(e.SecureRenegotiation) != 0 {
|
||||
copy(b[5:], e.SecureRenegotiation)
|
||||
}
|
||||
case RenegotiateNever:
|
||||
default:
|
||||
}
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
|
@ -364,9 +340,10 @@ func (e *SessionTicketExtension) Read(b []byte) (int, error) {
|
|||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
// GenericExtension allows to include in ClientHello arbitrary unsupported extensions.
|
||||
type GenericExtension struct {
|
||||
id uint16
|
||||
data []byte
|
||||
Id uint16
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (e *GenericExtension) writeToUConn(uc *UConn) error {
|
||||
|
@ -374,7 +351,7 @@ func (e *GenericExtension) writeToUConn(uc *UConn) error {
|
|||
}
|
||||
|
||||
func (e *GenericExtension) Len() int {
|
||||
return 4 + len(e.data)
|
||||
return 4 + len(e.Data)
|
||||
}
|
||||
|
||||
func (e *GenericExtension) Read(b []byte) (int, error) {
|
||||
|
@ -382,12 +359,12 @@ func (e *GenericExtension) Read(b []byte) (int, error) {
|
|||
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)
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue