utls
utls copied to clipboard
How to implement the "application_settings (17613)," extended
How to implement the "application_settings (17613)," extended. The previous 17513 has been changed to "application_dettings_old (17513)".
just extend the orignal utls.ApplicationSettingsExtension
type ApplicationSettingsExtension struct {
*utls.ApplicationSettingsExtension
}
func (e *ApplicationSettingsExtension) Len() int {
bLen := 2 + 2 + 2 // Type + Length + ALPS Extension length
for _, s := range e.SupportedProtocols {
bLen += 1 + len(s) // Supported ALPN Length + actual length of protocol
}
return bLen
}
func (e *ApplicationSettingsExtension) Read(b []byte) (int, error) {
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// Read Type.
b[0] = byte(17613 >> 8) // hex: 44 dec: 68
b[1] = byte(17613 & 0xff) // hex: 69 dec: 105
lengths := b[2:] // get the remaining buffer without Type
b = b[6:] // set the buffer to the buffer without Type, Length and ALPS Extension Length (so only the Supported ALPN list remains)
stringsLength := 0
for _, s := range e.SupportedProtocols {
l := len(s) // Supported ALPN Length
b[0] = byte(l) // Supported ALPN Length in bytes hex: 02 dec: 2
copy(b[1:], s) // copy the Supported ALPN as bytes to the buffer
b = b[1+l:] // set the buffer to the buffer without the Supported ALPN Length and Supported ALPN (so we can continue to the next protocol in this loop)
stringsLength += 1 + l // Supported ALPN Length (the field itself) + Supported ALPN Length (the value)
}
lengths[2] = byte(stringsLength >> 8) // ALPS Extension Length hex: 00 dec: 0
lengths[3] = byte(stringsLength) // ALPS Extension Length hex: 03 dec: 3
stringsLength += 2 // plus ALPS Extension Length field length
lengths[0] = byte(stringsLength >> 8) // Length hex:00 dec: 0
lengths[1] = byte(stringsLength) // Length hex: 05 dec: 5
return e.Len(), io.EOF
}
func (e *ApplicationSettingsExtension) UnmarshalJSON(b []byte) error {
var applicationSettingsSupport struct {
SupportedProtocols []string `json:"supported_protocols_new"`
}
if err := json.Unmarshal(b, &applicationSettingsSupport); err != nil {
return err
}
e.SupportedProtocols = applicationSettingsSupport.SupportedProtocols
return nil
}
// Write implementation copied from ALPNExtension.Write
func (e *ApplicationSettingsExtension) Write(b []byte) (int, error) {
fullLen := len(b)
extData := cryptobyte.String(b)
// https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01
var protoList cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
return 0, errors.New("unable to read ALPN extension data")
}
alpnProtocols := []string{}
for !protoList.Empty() {
var proto cryptobyte.String
if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
return 0, errors.New("unable to read ALPN extension data")
}
alpnProtocols = append(alpnProtocols, string(proto))
}
e.SupportedProtocols = alpnProtocols
return fullLen, nil
}