child.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package ike
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "vocat/internal/vowifi"
  9. )
  10. const (
  11. configRequest = 1
  12. configReply = 2
  13. configInternalIPv4Address = 1
  14. configInternalIPv4DNS = 3
  15. configInternalIPv6Address = 8
  16. configInternalIPv6DNS = 10
  17. configPCSCFIPv4Address = 20
  18. configPCSCFIPv6Address = 21
  19. trafficSelectorIPv4Range = 7
  20. trafficSelectorIPv6Range = 8
  21. )
  22. type espSuite struct {
  23. EncryptionID uint16
  24. EncryptionBits int
  25. IntegrityID uint16
  26. ESN uint16
  27. }
  28. func (suite espSuite) encryptionKeyLength() (int, error) {
  29. if suite.EncryptionID != encryptionAESCBC || (suite.EncryptionBits != 128 && suite.EncryptionBits != 256) {
  30. return 0, fmt.Errorf("%w: ESP encryption id=%d bits=%d", errUnsupportedSuite, suite.EncryptionID, suite.EncryptionBits)
  31. }
  32. return suite.EncryptionBits / 8, nil
  33. }
  34. func (suite espSuite) integrityKeyLength() (int, error) {
  35. switch suite.IntegrityID {
  36. case integrityHMACSHA1_96:
  37. return 20, nil
  38. case integrityHMACSHA256_128:
  39. return 32, nil
  40. default:
  41. return 0, fmt.Errorf("%w: ESP integrity id=%d", errUnsupportedSuite, suite.IntegrityID)
  42. }
  43. }
  44. func parseESPSuite(item proposal) (espSuite, error) {
  45. if item.Protocol != protocolESP || len(item.SPI) != 4 {
  46. return espSuite{}, fmt.Errorf("%w: invalid ESP proposal protocol or SPI", errUnsupportedSuite)
  47. }
  48. var suite espSuite
  49. seen := make(map[uint8]bool)
  50. for _, candidate := range item.Transforms {
  51. if seen[candidate.Type] {
  52. return espSuite{}, fmt.Errorf("%w: duplicate ESP transform type %d", errUnsupportedSuite, candidate.Type)
  53. }
  54. seen[candidate.Type] = true
  55. switch candidate.Type {
  56. case transformEncryption:
  57. suite.EncryptionID = candidate.ID
  58. suite.EncryptionBits = candidate.KeyLength
  59. case transformIntegrity:
  60. suite.IntegrityID = candidate.ID
  61. case transformESN:
  62. suite.ESN = candidate.ID
  63. default:
  64. return espSuite{}, fmt.Errorf("%w: unsupported ESP transform type %d", errUnsupportedSuite, candidate.Type)
  65. }
  66. }
  67. if _, err := suite.encryptionKeyLength(); err != nil {
  68. return espSuite{}, err
  69. }
  70. if _, err := suite.integrityKeyLength(); err != nil {
  71. return espSuite{}, err
  72. }
  73. if suite.ESN != 0 {
  74. return espSuite{}, fmt.Errorf("%w: ESP extended sequence numbers are unsupported", errUnsupportedSuite)
  75. }
  76. return suite, nil
  77. }
  78. type trafficSelector struct {
  79. IPProtocol uint8
  80. StartPort uint16
  81. EndPort uint16
  82. StartIP net.IP
  83. EndIP net.IP
  84. }
  85. func anyTrafficSelector(ipv6 bool) payload {
  86. var selector []byte
  87. if ipv6 {
  88. selector = make([]byte, 40)
  89. selector[0] = trafficSelectorIPv6Range
  90. binary.BigEndian.PutUint16(selector[2:4], uint16(len(selector)))
  91. binary.BigEndian.PutUint16(selector[6:8], 65535)
  92. copy(selector[8:24], net.IPv6zero)
  93. for index := 24; index < 40; index++ {
  94. selector[index] = 0xff
  95. }
  96. } else {
  97. selector = make([]byte, 16)
  98. selector[0] = trafficSelectorIPv4Range
  99. binary.BigEndian.PutUint16(selector[2:4], uint16(len(selector)))
  100. binary.BigEndian.PutUint16(selector[6:8], 65535)
  101. copy(selector[8:12], net.IPv4zero.To4())
  102. copy(selector[12:16], net.IPv4bcast.To4())
  103. }
  104. body := append([]byte{1, 0, 0, 0}, selector...)
  105. return payload{Body: body}
  106. }
  107. func dualStackTrafficSelectors(kind uint8) payload {
  108. ipv4 := anyTrafficSelector(false)
  109. ipv6 := anyTrafficSelector(true)
  110. body := []byte{2, 0, 0, 0}
  111. body = append(body, ipv4.Body[4:]...)
  112. body = append(body, ipv6.Body[4:]...)
  113. return payload{Type: kind, Body: body}
  114. }
  115. func parseTrafficSelectors(item payload) ([]trafficSelector, error) {
  116. if len(item.Body) < 4 {
  117. return nil, errors.New("ike: traffic selector payload is truncated")
  118. }
  119. count := int(item.Body[0])
  120. offset := 4
  121. result := make([]trafficSelector, 0, count)
  122. for index := 0; index < count; index++ {
  123. if offset+8 > len(item.Body) {
  124. return nil, errors.New("ike: traffic selector is truncated")
  125. }
  126. length := int(binary.BigEndian.Uint16(item.Body[offset+2 : offset+4]))
  127. if length < 16 || offset+length > len(item.Body) {
  128. return nil, errors.New("ike: traffic selector has an invalid length")
  129. }
  130. selector := trafficSelector{
  131. IPProtocol: item.Body[offset+1],
  132. StartPort: binary.BigEndian.Uint16(item.Body[offset+4 : offset+6]),
  133. EndPort: binary.BigEndian.Uint16(item.Body[offset+6 : offset+8]),
  134. }
  135. switch item.Body[offset] {
  136. case trafficSelectorIPv4Range:
  137. if length != 16 {
  138. return nil, errors.New("ike: IPv4 traffic selector has an invalid length")
  139. }
  140. selector.StartIP = append(net.IP(nil), item.Body[offset+8:offset+12]...)
  141. selector.EndIP = append(net.IP(nil), item.Body[offset+12:offset+16]...)
  142. case trafficSelectorIPv6Range:
  143. if length != 40 {
  144. return nil, errors.New("ike: IPv6 traffic selector has an invalid length")
  145. }
  146. selector.StartIP = append(net.IP(nil), item.Body[offset+8:offset+24]...)
  147. selector.EndIP = append(net.IP(nil), item.Body[offset+24:offset+40]...)
  148. default:
  149. return nil, fmt.Errorf("ike: unsupported traffic selector type %d", item.Body[offset])
  150. }
  151. result = append(result, selector)
  152. offset += length
  153. }
  154. if offset != len(item.Body) {
  155. return nil, errors.New("ike: traffic selector payload has trailing bytes")
  156. }
  157. return result, nil
  158. }
  159. type networkConfiguration struct {
  160. LocalIPv4 net.IP
  161. LocalIPv6 net.IP
  162. IPv6Prefix uint8
  163. DNS []net.IP
  164. PCSCF []net.IP
  165. }
  166. func configurationRequest() payload {
  167. attributes := []uint16{
  168. configInternalIPv4Address,
  169. configInternalIPv6Address,
  170. configInternalIPv4DNS,
  171. configInternalIPv6DNS,
  172. configPCSCFIPv4Address,
  173. configPCSCFIPv6Address,
  174. }
  175. body := []byte{configRequest, 0, 0, 0}
  176. for _, attribute := range attributes {
  177. var header [4]byte
  178. binary.BigEndian.PutUint16(header[0:2], attribute)
  179. body = append(body, header[:]...)
  180. }
  181. return payload{Type: payloadCP, Body: body}
  182. }
  183. func parseConfiguration(item payload) (networkConfiguration, error) {
  184. if item.Type != payloadCP || len(item.Body) < 4 || item.Body[0] != configReply {
  185. return networkConfiguration{}, errors.New("ike: missing or invalid configuration reply")
  186. }
  187. var configuration networkConfiguration
  188. for offset := 4; offset < len(item.Body); {
  189. if offset+4 > len(item.Body) {
  190. return networkConfiguration{}, errors.New("ike: truncated configuration attribute")
  191. }
  192. kind := binary.BigEndian.Uint16(item.Body[offset : offset+2])
  193. length := int(binary.BigEndian.Uint16(item.Body[offset+2 : offset+4]))
  194. offset += 4
  195. if offset+length > len(item.Body) {
  196. return networkConfiguration{}, errors.New("ike: invalid configuration attribute length")
  197. }
  198. value := item.Body[offset : offset+length]
  199. switch kind & 0x7fff {
  200. case configInternalIPv4Address:
  201. if length == 4 {
  202. configuration.LocalIPv4 = append(net.IP(nil), value...)
  203. }
  204. case configInternalIPv6Address:
  205. if length != 17 {
  206. return networkConfiguration{}, errors.New("ike: INTERNAL_IP6_ADDRESS must contain 16 address bytes and one prefix byte")
  207. }
  208. if value[16] > 128 {
  209. return networkConfiguration{}, errors.New("ike: INTERNAL_IP6_ADDRESS prefix exceeds 128")
  210. }
  211. configuration.LocalIPv6 = append(net.IP(nil), value[:16]...)
  212. configuration.IPv6Prefix = value[16]
  213. case configInternalIPv4DNS:
  214. if length == 4 {
  215. configuration.DNS = append(configuration.DNS, append(net.IP(nil), value...))
  216. }
  217. case configInternalIPv6DNS:
  218. if length == 16 {
  219. configuration.DNS = append(configuration.DNS, append(net.IP(nil), value...))
  220. }
  221. case configPCSCFIPv4Address:
  222. if length == 4 {
  223. configuration.PCSCF = append(configuration.PCSCF, append(net.IP(nil), value...))
  224. }
  225. case configPCSCFIPv6Address:
  226. if length == 16 {
  227. configuration.PCSCF = append(configuration.PCSCF, append(net.IP(nil), value...))
  228. }
  229. }
  230. offset += length
  231. }
  232. return configuration, nil
  233. }
  234. type ChildSAConfig struct {
  235. Name string
  236. OuterLocal net.IP
  237. OuterRemote net.IP
  238. InnerLocalIPv4 net.IP
  239. InnerLocalIPv6 net.IP
  240. InnerIPv6Prefix uint8
  241. PCSCF []net.IP
  242. DNS []net.IP
  243. InboundSPI uint32
  244. OutboundSPI uint32
  245. Encryption string
  246. Integrity string
  247. InboundEncKey []byte
  248. InboundAuthKey []byte
  249. OutboundEncKey []byte
  250. OutboundAuthKey []byte
  251. InitiatorSelectors []trafficSelector
  252. ResponderSelectors []trafficSelector
  253. UDPEncapsulation bool
  254. ProxyMode vowifi.ProxyMode
  255. Relay NATTPacketRelay
  256. }
  257. // NATTPacketRelay carries raw ESP packets inside UDP/4500. A user-space
  258. // CHILD_SA installer must use this relay when ProxyMode is SOCKS5; kernel
  259. // XFRM output cannot transparently enter a SOCKS5 UDP association.
  260. type NATTPacketRelay interface {
  261. SendESP(context.Context, []byte) error
  262. ReceiveESP(context.Context, []byte) (int, error)
  263. }
  264. type ChildSAHandle interface {
  265. Close(context.Context) error
  266. }
  267. type DataplaneEvidence interface {
  268. DataplaneMode() string
  269. }
  270. type DataplaneFailureNotifier interface {
  271. Failures() <-chan error
  272. }
  273. type ChildSAInstaller interface {
  274. Install(context.Context, ChildSAConfig) (ChildSAHandle, error)
  275. }
  276. func deriveChildSAKeys(
  277. ikeSuite negotiatedSuite,
  278. childSuite espSuite,
  279. skd []byte,
  280. initiatorNonce []byte,
  281. responderNonce []byte,
  282. ) (outboundEncryption, outboundIntegrity, inboundEncryption, inboundIntegrity []byte, err error) {
  283. encryptionLength, err := childSuite.encryptionKeyLength()
  284. if err != nil {
  285. return nil, nil, nil, nil, err
  286. }
  287. integrityLength, err := childSuite.integrityKeyLength()
  288. if err != nil {
  289. return nil, nil, nil, nil, err
  290. }
  291. seed := append(append([]byte(nil), initiatorNonce...), responderNonce...)
  292. stream, err := prfPlus(ikeSuite, skd, seed, 2*(encryptionLength+integrityLength))
  293. if err != nil {
  294. return nil, nil, nil, nil, err
  295. }
  296. take := func(length int) []byte {
  297. value := append([]byte(nil), stream[:length]...)
  298. stream = stream[length:]
  299. return value
  300. }
  301. return take(encryptionLength), take(integrityLength), take(encryptionLength), take(integrityLength), nil
  302. }
  303. func espSuiteNames(suite espSuite) (encryption string, integrity string) {
  304. encryption = fmt.Sprintf("aes-cbc-%d", suite.EncryptionBits)
  305. switch suite.IntegrityID {
  306. case integrityHMACSHA1_96:
  307. integrity = "hmac-sha1-96"
  308. case integrityHMACSHA256_128:
  309. integrity = "hmac-sha2-256-128"
  310. }
  311. return encryption, integrity
  312. }