github.com/pion/dtls/v2@v2.2.12/pkg/protocol/extension/server_name.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 package extension 5 6 import ( 7 "strings" 8 9 "golang.org/x/crypto/cryptobyte" 10 ) 11 12 const serverNameTypeDNSHostName = 0 13 14 // ServerName allows the client to inform the server the specific 15 // name it wishes to contact. Useful if multiple DNS names resolve 16 // to one IP 17 // 18 // https://tools.ietf.org/html/rfc6066#section-3 19 type ServerName struct { 20 ServerName string 21 } 22 23 // TypeValue returns the extension TypeValue 24 func (s ServerName) TypeValue() TypeValue { 25 return ServerNameTypeValue 26 } 27 28 // Marshal encodes the extension 29 func (s *ServerName) Marshal() ([]byte, error) { 30 var b cryptobyte.Builder 31 b.AddUint16(uint16(s.TypeValue())) 32 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { 33 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { 34 b.AddUint8(serverNameTypeDNSHostName) 35 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { 36 b.AddBytes([]byte(s.ServerName)) 37 }) 38 }) 39 }) 40 return b.Bytes() 41 } 42 43 // Unmarshal populates the extension from encoded data 44 func (s *ServerName) Unmarshal(data []byte) error { 45 val := cryptobyte.String(data) 46 var extension uint16 47 val.ReadUint16(&extension) 48 if TypeValue(extension) != s.TypeValue() { 49 return errInvalidExtensionType 50 } 51 52 var extData cryptobyte.String 53 val.ReadUint16LengthPrefixed(&extData) 54 55 var nameList cryptobyte.String 56 if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() { 57 return errInvalidSNIFormat 58 } 59 for !nameList.Empty() { 60 var nameType uint8 61 var serverName cryptobyte.String 62 if !nameList.ReadUint8(&nameType) || 63 !nameList.ReadUint16LengthPrefixed(&serverName) || 64 serverName.Empty() { 65 return errInvalidSNIFormat 66 } 67 if nameType != serverNameTypeDNSHostName { 68 continue 69 } 70 if len(s.ServerName) != 0 { 71 // Multiple names of the same name_type are prohibited. 72 return errInvalidSNIFormat 73 } 74 s.ServerName = string(serverName) 75 // An SNI value may not include a trailing dot. 76 if strings.HasSuffix(s.ServerName, ".") { 77 return errInvalidSNIFormat 78 } 79 } 80 return nil 81 }