esp.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. package ike
  2. import (
  3. "bytes"
  4. "crypto/aes"
  5. "crypto/cipher"
  6. "crypto/hmac"
  7. "crypto/rand"
  8. "crypto/sha1"
  9. "crypto/sha256"
  10. "crypto/subtle"
  11. "encoding/binary"
  12. "errors"
  13. "fmt"
  14. "io"
  15. "math"
  16. "net"
  17. "sync"
  18. )
  19. const (
  20. espHeaderLength = 8
  21. espReplayWindow = 64
  22. )
  23. var (
  24. errESPAuthentication = errors.New("ike: ESP authentication failed")
  25. errESPReplay = errors.New("ike: ESP packet is outside the replay window")
  26. errESPPolicyDrop = errors.New("ike: ESP packet is not eligible for this CHILD_SA")
  27. )
  28. // espTunnel protects complete IPv4 or IPv6 packets using an IKEv2 CHILD_SA.
  29. // It deliberately implements only the negotiated suites offered by this
  30. // package: AES-CBC with HMAC-SHA1-96 or HMAC-SHA2-256-128 and no ESN.
  31. type espTunnel struct {
  32. outbound *espDirection
  33. inbound *espDirection
  34. initiatorSelectors []trafficSelector
  35. responderSelectors []trafficSelector
  36. }
  37. type espDirection struct {
  38. spi uint32
  39. block cipher.Block
  40. authKey []byte
  41. integrity string
  42. icvLength int
  43. random io.Reader
  44. mu sync.Mutex
  45. sequence uint32
  46. replay replayWindow
  47. }
  48. type replayWindow struct {
  49. highest uint32
  50. bitmap uint64
  51. }
  52. type innerPacketMetadata struct {
  53. source net.IP
  54. destination net.IP
  55. protocol uint8
  56. sourcePort uint16
  57. destinationPort uint16
  58. nextHeader uint8
  59. }
  60. func newESPTunnel(config ChildSAConfig, randomSource io.Reader) (*espTunnel, error) {
  61. if config.InboundSPI == 0 || config.OutboundSPI == 0 {
  62. return nil, errors.New("ike: ESP SPIs must be nonzero")
  63. }
  64. if randomSource == nil {
  65. randomSource = rand.Reader
  66. }
  67. outbound, err := newESPDirection(
  68. config.OutboundSPI,
  69. config.OutboundEncKey,
  70. config.OutboundAuthKey,
  71. config.Encryption,
  72. config.Integrity,
  73. randomSource,
  74. )
  75. if err != nil {
  76. return nil, fmt.Errorf("ike: outbound ESP: %w", err)
  77. }
  78. inbound, err := newESPDirection(
  79. config.InboundSPI,
  80. config.InboundEncKey,
  81. config.InboundAuthKey,
  82. config.Encryption,
  83. config.Integrity,
  84. randomSource,
  85. )
  86. if err != nil {
  87. return nil, fmt.Errorf("ike: inbound ESP: %w", err)
  88. }
  89. if len(config.InitiatorSelectors) == 0 || len(config.ResponderSelectors) == 0 {
  90. return nil, errors.New("ike: ESP traffic selectors are required")
  91. }
  92. return &espTunnel{
  93. outbound: outbound,
  94. inbound: inbound,
  95. initiatorSelectors: copyESPTrafficSelectors(config.InitiatorSelectors),
  96. responderSelectors: copyESPTrafficSelectors(config.ResponderSelectors),
  97. }, nil
  98. }
  99. func newESPDirection(
  100. spi uint32,
  101. encryptionKey []byte,
  102. authenticationKey []byte,
  103. encryption string,
  104. integrity string,
  105. randomSource io.Reader,
  106. ) (*espDirection, error) {
  107. expectedEncryptionLength := 0
  108. switch encryption {
  109. case "aes-cbc-128":
  110. expectedEncryptionLength = 16
  111. case "aes-cbc-256":
  112. expectedEncryptionLength = 32
  113. default:
  114. return nil, fmt.Errorf("unsupported encryption suite %q", encryption)
  115. }
  116. if len(encryptionKey) != expectedEncryptionLength {
  117. return nil, fmt.Errorf("AES key has length %d, want %d", len(encryptionKey), expectedEncryptionLength)
  118. }
  119. expectedAuthenticationLength := 0
  120. icvLength := 0
  121. switch integrity {
  122. case "hmac-sha1-96":
  123. expectedAuthenticationLength = sha1.Size
  124. icvLength = 12
  125. case "hmac-sha2-256-128":
  126. expectedAuthenticationLength = sha256.Size
  127. icvLength = 16
  128. default:
  129. return nil, fmt.Errorf("unsupported integrity suite %q", integrity)
  130. }
  131. if len(authenticationKey) != expectedAuthenticationLength {
  132. return nil, fmt.Errorf(
  133. "authentication key has length %d, want %d",
  134. len(authenticationKey),
  135. expectedAuthenticationLength,
  136. )
  137. }
  138. block, err := aes.NewCipher(encryptionKey)
  139. if err != nil {
  140. return nil, err
  141. }
  142. return &espDirection{
  143. spi: spi,
  144. block: block,
  145. authKey: append([]byte(nil), authenticationKey...),
  146. integrity: integrity,
  147. icvLength: icvLength,
  148. random: randomSource,
  149. }, nil
  150. }
  151. func (tunnel *espTunnel) seal(innerPacket []byte) ([]byte, error) {
  152. if tunnel == nil {
  153. return nil, errors.New("ike: nil ESP tunnel")
  154. }
  155. metadata, err := parseInnerPacket(innerPacket)
  156. if err != nil {
  157. return nil, fmt.Errorf("%w: %v", errESPPolicyDrop, err)
  158. }
  159. if !packetAllowed(
  160. metadata,
  161. tunnel.initiatorSelectors,
  162. tunnel.responderSelectors,
  163. ) {
  164. return nil, fmt.Errorf("%w: outbound packet is outside negotiated traffic selectors", errESPPolicyDrop)
  165. }
  166. return tunnel.outbound.seal(innerPacket, metadata.nextHeader)
  167. }
  168. func (tunnel *espTunnel) open(packet []byte) ([]byte, error) {
  169. if tunnel == nil {
  170. return nil, errors.New("ike: nil ESP tunnel")
  171. }
  172. return tunnel.inbound.open(packet, func(innerPacket []byte, nextHeader uint8) error {
  173. metadata, err := parseInnerPacket(innerPacket)
  174. if err != nil {
  175. return err
  176. }
  177. if metadata.nextHeader != nextHeader {
  178. return errors.New("ike: ESP trailer does not match the inner IP version")
  179. }
  180. if !packetAllowed(
  181. metadata,
  182. tunnel.responderSelectors,
  183. tunnel.initiatorSelectors,
  184. ) {
  185. return errors.New("ike: inbound packet is outside negotiated traffic selectors")
  186. }
  187. return nil
  188. })
  189. }
  190. func (direction *espDirection) seal(innerPacket []byte, nextHeader uint8) ([]byte, error) {
  191. direction.mu.Lock()
  192. defer direction.mu.Unlock()
  193. if direction.sequence == math.MaxUint32 {
  194. return nil, errors.New("ike: ESP sequence number exhausted; rekey is required")
  195. }
  196. direction.sequence++
  197. sequence := direction.sequence
  198. blockSize := direction.block.BlockSize()
  199. paddingLength := (blockSize - ((len(innerPacket) + 2) % blockSize)) % blockSize
  200. plaintext := make([]byte, len(innerPacket)+paddingLength+2)
  201. copy(plaintext, innerPacket)
  202. for index := 0; index < paddingLength; index++ {
  203. plaintext[len(innerPacket)+index] = byte(index + 1)
  204. }
  205. plaintext[len(plaintext)-2] = byte(paddingLength)
  206. plaintext[len(plaintext)-1] = nextHeader
  207. authenticatedLength := espHeaderLength + blockSize + len(plaintext)
  208. packet := make([]byte, authenticatedLength+direction.icvLength)
  209. binary.BigEndian.PutUint32(packet[0:4], direction.spi)
  210. binary.BigEndian.PutUint32(packet[4:8], sequence)
  211. iv := packet[espHeaderLength : espHeaderLength+blockSize]
  212. if _, err := io.ReadFull(direction.random, iv); err != nil {
  213. return nil, fmt.Errorf("ike: generate ESP IV: %w", err)
  214. }
  215. cipher.NewCBCEncrypter(direction.block, iv).CryptBlocks(
  216. packet[espHeaderLength+blockSize:authenticatedLength],
  217. plaintext,
  218. )
  219. icv := direction.authenticationCode(packet[:authenticatedLength])
  220. copy(packet[authenticatedLength:], icv)
  221. return packet, nil
  222. }
  223. func (direction *espDirection) open(
  224. packet []byte,
  225. validate func([]byte, uint8) error,
  226. ) ([]byte, error) {
  227. direction.mu.Lock()
  228. defer direction.mu.Unlock()
  229. blockSize := direction.block.BlockSize()
  230. minimumLength := espHeaderLength + blockSize + blockSize + direction.icvLength
  231. if len(packet) < minimumLength {
  232. return nil, errors.New("ike: ESP packet is truncated")
  233. }
  234. if binary.BigEndian.Uint32(packet[0:4]) != direction.spi {
  235. return nil, errors.New("ike: ESP packet has an unexpected SPI")
  236. }
  237. sequence := binary.BigEndian.Uint32(packet[4:8])
  238. if sequence == 0 || !direction.replay.wouldAccept(sequence) {
  239. return nil, errESPReplay
  240. }
  241. authenticatedLength := len(packet) - direction.icvLength
  242. ciphertext := packet[espHeaderLength+blockSize : authenticatedLength]
  243. if len(ciphertext) == 0 || len(ciphertext)%blockSize != 0 {
  244. return nil, errors.New("ike: ESP ciphertext is not block aligned")
  245. }
  246. expectedICV := direction.authenticationCode(packet[:authenticatedLength])
  247. if subtle.ConstantTimeCompare(expectedICV, packet[authenticatedLength:]) != 1 {
  248. return nil, errESPAuthentication
  249. }
  250. plaintext := make([]byte, len(ciphertext))
  251. iv := packet[espHeaderLength : espHeaderLength+blockSize]
  252. cipher.NewCBCDecrypter(direction.block, iv).CryptBlocks(plaintext, ciphertext)
  253. if len(plaintext) < 2 {
  254. return nil, errors.New("ike: ESP plaintext is truncated")
  255. }
  256. paddingLength := int(plaintext[len(plaintext)-2])
  257. if paddingLength > len(plaintext)-2 {
  258. return nil, errors.New("ike: ESP padding length is invalid")
  259. }
  260. paddingStart := len(plaintext) - 2 - paddingLength
  261. for index := 0; index < paddingLength; index++ {
  262. if plaintext[paddingStart+index] != byte(index+1) {
  263. return nil, errors.New("ike: ESP padding bytes are invalid")
  264. }
  265. }
  266. nextHeader := plaintext[len(plaintext)-1]
  267. if nextHeader != 4 && nextHeader != 41 {
  268. return nil, fmt.Errorf("ike: unsupported ESP next-header value %d", nextHeader)
  269. }
  270. innerPacket := append([]byte(nil), plaintext[:paddingStart]...)
  271. if validate != nil {
  272. if err := validate(innerPacket, nextHeader); err != nil {
  273. return nil, err
  274. }
  275. }
  276. direction.replay.commit(sequence)
  277. return innerPacket, nil
  278. }
  279. func (direction *espDirection) authenticationCode(packet []byte) []byte {
  280. var mac hashWriter
  281. switch direction.integrity {
  282. case "hmac-sha1-96":
  283. mac = hmac.New(sha1.New, direction.authKey)
  284. case "hmac-sha2-256-128":
  285. mac = hmac.New(sha256.New, direction.authKey)
  286. default:
  287. panic("unreachable ESP integrity suite")
  288. }
  289. _, _ = mac.Write(packet)
  290. return mac.Sum(nil)[:direction.icvLength]
  291. }
  292. type hashWriter interface {
  293. Write([]byte) (int, error)
  294. Sum([]byte) []byte
  295. }
  296. func (window replayWindow) wouldAccept(sequence uint32) bool {
  297. if sequence == 0 {
  298. return false
  299. }
  300. if window.highest == 0 || sequence > window.highest {
  301. return true
  302. }
  303. difference := window.highest - sequence
  304. if difference >= espReplayWindow {
  305. return false
  306. }
  307. return window.bitmap&(uint64(1)<<difference) == 0
  308. }
  309. func (window *replayWindow) commit(sequence uint32) {
  310. if window.highest == 0 {
  311. window.highest = sequence
  312. window.bitmap = 1
  313. return
  314. }
  315. if sequence > window.highest {
  316. difference := sequence - window.highest
  317. if difference >= espReplayWindow {
  318. window.bitmap = 1
  319. } else {
  320. window.bitmap = window.bitmap<<difference | 1
  321. }
  322. window.highest = sequence
  323. return
  324. }
  325. window.bitmap |= uint64(1) << (window.highest - sequence)
  326. }
  327. func parseInnerPacket(packet []byte) (innerPacketMetadata, error) {
  328. if len(packet) == 0 {
  329. return innerPacketMetadata{}, errors.New("ike: inner IP packet is empty")
  330. }
  331. switch packet[0] >> 4 {
  332. case 4:
  333. return parseInnerIPv4(packet)
  334. case 6:
  335. return parseInnerIPv6(packet)
  336. default:
  337. return innerPacketMetadata{}, errors.New("ike: inner packet is not IPv4 or IPv6")
  338. }
  339. }
  340. func parseInnerIPv4(packet []byte) (innerPacketMetadata, error) {
  341. if len(packet) < 20 {
  342. return innerPacketMetadata{}, errors.New("ike: inner IPv4 packet is truncated")
  343. }
  344. headerLength := int(packet[0]&0x0f) * 4
  345. if headerLength < 20 || headerLength > len(packet) {
  346. return innerPacketMetadata{}, errors.New("ike: inner IPv4 header length is invalid")
  347. }
  348. totalLength := int(binary.BigEndian.Uint16(packet[2:4]))
  349. if totalLength != len(packet) || totalLength < headerLength {
  350. return innerPacketMetadata{}, errors.New("ike: inner IPv4 total length is invalid")
  351. }
  352. metadata := innerPacketMetadata{
  353. source: append(net.IP(nil), packet[12:16]...),
  354. destination: append(net.IP(nil), packet[16:20]...),
  355. protocol: packet[9],
  356. nextHeader: 4,
  357. }
  358. fragmentOffset := binary.BigEndian.Uint16(packet[6:8]) & 0x1fff
  359. if fragmentOffset == 0 {
  360. parseTransportPorts(packet[headerLength:], &metadata)
  361. }
  362. return metadata, nil
  363. }
  364. func parseInnerIPv6(packet []byte) (innerPacketMetadata, error) {
  365. if len(packet) < 40 {
  366. return innerPacketMetadata{}, errors.New("ike: inner IPv6 packet is truncated")
  367. }
  368. payloadLength := int(binary.BigEndian.Uint16(packet[4:6]))
  369. if payloadLength+40 != len(packet) {
  370. return innerPacketMetadata{}, errors.New("ike: inner IPv6 payload length is invalid")
  371. }
  372. metadata := innerPacketMetadata{
  373. source: append(net.IP(nil), packet[8:24]...),
  374. destination: append(net.IP(nil), packet[24:40]...),
  375. nextHeader: 41,
  376. }
  377. protocol := packet[6]
  378. offset := 40
  379. firstFragment := true
  380. for {
  381. switch protocol {
  382. case 0, 43, 60:
  383. if offset+2 > len(packet) {
  384. return innerPacketMetadata{}, errors.New("ike: inner IPv6 extension header is truncated")
  385. }
  386. length := (int(packet[offset+1]) + 1) * 8
  387. if length < 8 || offset+length > len(packet) {
  388. return innerPacketMetadata{}, errors.New("ike: inner IPv6 extension header length is invalid")
  389. }
  390. protocol = packet[offset]
  391. offset += length
  392. case 44:
  393. if offset+8 > len(packet) {
  394. return innerPacketMetadata{}, errors.New("ike: inner IPv6 fragment header is truncated")
  395. }
  396. firstFragment = binary.BigEndian.Uint16(packet[offset+2:offset+4])&0xfff8 == 0
  397. protocol = packet[offset]
  398. offset += 8
  399. case 51:
  400. if offset+2 > len(packet) {
  401. return innerPacketMetadata{}, errors.New("ike: inner IPv6 AH header is truncated")
  402. }
  403. length := (int(packet[offset+1]) + 2) * 4
  404. if length < 8 || offset+length > len(packet) {
  405. return innerPacketMetadata{}, errors.New("ike: inner IPv6 AH header length is invalid")
  406. }
  407. protocol = packet[offset]
  408. offset += length
  409. default:
  410. metadata.protocol = protocol
  411. if firstFragment {
  412. parseTransportPorts(packet[offset:], &metadata)
  413. }
  414. return metadata, nil
  415. }
  416. }
  417. }
  418. func parseTransportPorts(payload []byte, metadata *innerPacketMetadata) {
  419. if metadata == nil || (metadata.protocol != 6 && metadata.protocol != 17) || len(payload) < 4 {
  420. return
  421. }
  422. metadata.sourcePort = binary.BigEndian.Uint16(payload[0:2])
  423. metadata.destinationPort = binary.BigEndian.Uint16(payload[2:4])
  424. }
  425. func packetAllowed(
  426. metadata innerPacketMetadata,
  427. sourceSelectors []trafficSelector,
  428. destinationSelectors []trafficSelector,
  429. ) bool {
  430. return endpointAllowed(
  431. metadata.source,
  432. metadata.protocol,
  433. metadata.sourcePort,
  434. sourceSelectors,
  435. ) && endpointAllowed(
  436. metadata.destination,
  437. metadata.protocol,
  438. metadata.destinationPort,
  439. destinationSelectors,
  440. )
  441. }
  442. func endpointAllowed(ip net.IP, protocol uint8, port uint16, selectors []trafficSelector) bool {
  443. for _, selector := range selectors {
  444. if selector.IPProtocol != 0 && selector.IPProtocol != protocol {
  445. continue
  446. }
  447. if port < selector.StartPort || port > selector.EndPort {
  448. continue
  449. }
  450. if ipWithinRange(ip, selector.StartIP, selector.EndIP) {
  451. return true
  452. }
  453. }
  454. return false
  455. }
  456. func ipWithinRange(ip net.IP, start net.IP, end net.IP) bool {
  457. normalizedIP, normalizedStart, normalizedEnd, ok := normalizeIPRange(ip, start, end)
  458. if !ok {
  459. return false
  460. }
  461. return bytes.Compare(normalizedIP, normalizedStart) >= 0 &&
  462. bytes.Compare(normalizedIP, normalizedEnd) <= 0
  463. }
  464. func normalizeIPRange(ip net.IP, start net.IP, end net.IP) ([]byte, []byte, []byte, bool) {
  465. if start4 := start.To4(); start4 != nil {
  466. ip4 := ip.To4()
  467. end4 := end.To4()
  468. if ip4 == nil || end4 == nil {
  469. return nil, nil, nil, false
  470. }
  471. return ip4, start4, end4, true
  472. }
  473. ip16 := ip.To16()
  474. start16 := start.To16()
  475. end16 := end.To16()
  476. if ip16 == nil || start16 == nil || end16 == nil || start.To4() != nil || end.To4() != nil {
  477. return nil, nil, nil, false
  478. }
  479. return ip16, start16, end16, true
  480. }
  481. func copyESPTrafficSelectors(selectors []trafficSelector) []trafficSelector {
  482. cloned := make([]trafficSelector, len(selectors))
  483. for index, selector := range selectors {
  484. cloned[index] = selector
  485. cloned[index].StartIP = append(net.IP(nil), selector.StartIP...)
  486. cloned[index].EndIP = append(net.IP(nil), selector.EndIP...)
  487. }
  488. return cloned
  489. }