server_name.go 2.0 KB

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