eap.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. package ike
  2. import (
  3. "context"
  4. "crypto/hmac"
  5. "crypto/sha1"
  6. "crypto/subtle"
  7. "encoding/binary"
  8. "errors"
  9. "fmt"
  10. "math/big"
  11. "strings"
  12. "vocat/internal/vowifi"
  13. )
  14. const (
  15. eapRequest = 1
  16. eapResponse = 2
  17. eapSuccess = 3
  18. eapFailure = 4
  19. eapTypeIdentity = 1
  20. eapTypeAKA = 23
  21. akaSubtypeChallenge = 1
  22. akaSubtypeAuthReject = 2
  23. akaSubtypeSyncFailure = 4
  24. akaSubtypeIdentity = 5
  25. akaSubtypeNotification = 12
  26. akaSubtypeReauth = 13
  27. akaSubtypeClientError = 14
  28. akaAttrRAND = 1
  29. akaAttrAUTN = 2
  30. akaAttrRES = 3
  31. akaAttrAUTS = 4
  32. akaAttrPermanentIDReq = 10
  33. akaAttrMAC = 11
  34. akaAttrNotification = 12
  35. akaAttrAnyIDReq = 13
  36. akaAttrIdentity = 14
  37. akaAttrFullAuthIDReq = 17
  38. akaAttrClientError = 22
  39. akaAttrResultInd = 135
  40. )
  41. var errAKAProvider = errors.New("ike: SIM AKA provider failure")
  42. type eapPacket struct {
  43. Code uint8
  44. Identifier uint8
  45. Type uint8
  46. Data []byte
  47. }
  48. func parseEAPPacket(encoded []byte) (eapPacket, error) {
  49. if len(encoded) < 4 {
  50. return eapPacket{}, errors.New("ike: truncated EAP header")
  51. }
  52. length := int(binary.BigEndian.Uint16(encoded[2:4]))
  53. if length != len(encoded) {
  54. return eapPacket{}, fmt.Errorf("ike: EAP length %d does not match payload length %d", length, len(encoded))
  55. }
  56. packet := eapPacket{Code: encoded[0], Identifier: encoded[1]}
  57. switch packet.Code {
  58. case eapRequest, eapResponse:
  59. if len(encoded) < 5 {
  60. return eapPacket{}, errors.New("ike: typed EAP packet is truncated")
  61. }
  62. packet.Type = encoded[4]
  63. packet.Data = append([]byte(nil), encoded[5:]...)
  64. case eapSuccess, eapFailure:
  65. if len(encoded) != 4 {
  66. return eapPacket{}, errors.New("ike: EAP success/failure has trailing data")
  67. }
  68. default:
  69. return eapPacket{}, fmt.Errorf("ike: unsupported EAP code %d", packet.Code)
  70. }
  71. return packet, nil
  72. }
  73. func marshalEAPPacket(packet eapPacket) ([]byte, error) {
  74. length := 4
  75. if packet.Code == eapRequest || packet.Code == eapResponse {
  76. if packet.Type == 0 {
  77. return nil, errors.New("ike: typed EAP packet has no type")
  78. }
  79. length += 1 + len(packet.Data)
  80. } else if len(packet.Data) != 0 || packet.Type != 0 {
  81. return nil, errors.New("ike: EAP success/failure cannot carry type data")
  82. }
  83. if length > 65535 {
  84. return nil, errors.New("ike: EAP packet exceeds 65535 bytes")
  85. }
  86. encoded := make([]byte, length)
  87. encoded[0] = packet.Code
  88. encoded[1] = packet.Identifier
  89. binary.BigEndian.PutUint16(encoded[2:4], uint16(length))
  90. if length > 4 {
  91. encoded[4] = packet.Type
  92. copy(encoded[5:], packet.Data)
  93. }
  94. return encoded, nil
  95. }
  96. type akaAttribute struct {
  97. Type uint8
  98. Raw []byte
  99. Offset int
  100. }
  101. func parseAKAAttributes(encoded []byte) ([]akaAttribute, error) {
  102. var result []akaAttribute
  103. for offset := 0; offset < len(encoded); {
  104. if len(result) >= 64 || offset+2 > len(encoded) {
  105. return nil, errors.New("ike: malformed EAP-AKA attribute list")
  106. }
  107. length := int(encoded[offset+1]) * 4
  108. if length < 4 || offset+length > len(encoded) {
  109. return nil, fmt.Errorf("ike: EAP-AKA attribute %d has invalid length %d", encoded[offset], length)
  110. }
  111. result = append(result, akaAttribute{
  112. Type: encoded[offset],
  113. Raw: append([]byte(nil), encoded[offset:offset+length]...),
  114. Offset: offset,
  115. })
  116. offset += length
  117. }
  118. return result, nil
  119. }
  120. func oneAKAAttribute(attributes []akaAttribute, kind uint8) (akaAttribute, error) {
  121. var result akaAttribute
  122. count := 0
  123. for _, attribute := range attributes {
  124. if attribute.Type == kind {
  125. result = attribute
  126. count++
  127. }
  128. }
  129. if count != 1 {
  130. return akaAttribute{}, fmt.Errorf("ike: EAP-AKA expected one attribute %d, got %d", kind, count)
  131. }
  132. return result, nil
  133. }
  134. func marshalAKAAttribute(kind uint8, value []byte) ([]byte, error) {
  135. length := 2 + len(value)
  136. padded := (length + 3) &^ 3
  137. if padded/4 > 255 {
  138. return nil, errors.New("ike: EAP-AKA attribute is too long")
  139. }
  140. encoded := make([]byte, padded)
  141. encoded[0] = kind
  142. encoded[1] = uint8(padded / 4)
  143. copy(encoded[2:], value)
  144. return encoded, nil
  145. }
  146. type akaKeys struct {
  147. KEncr []byte
  148. KAut []byte
  149. MSK []byte
  150. EMSK []byte
  151. }
  152. func deriveAKAKeys(identity, ik, ck []byte) (akaKeys, error) {
  153. if len(identity) == 0 {
  154. return akaKeys{}, errors.New("ike: EAP-AKA identity is empty")
  155. }
  156. if len(ik) != 16 || len(ck) != 16 {
  157. return akaKeys{}, fmt.Errorf("ike: EAP-AKA requires 16-byte IK and CK, got %d and %d", len(ik), len(ck))
  158. }
  159. material := make([]byte, 0, len(identity)+32)
  160. material = append(material, identity...)
  161. material = append(material, ik...)
  162. material = append(material, ck...)
  163. masterKey := sha1.Sum(material)
  164. stream := fips1862PRF(masterKey[:], 160)
  165. return akaKeys{
  166. KEncr: append([]byte(nil), stream[0:16]...),
  167. KAut: append([]byte(nil), stream[16:32]...),
  168. MSK: append([]byte(nil), stream[32:96]...),
  169. EMSK: append([]byte(nil), stream[96:160]...),
  170. }, nil
  171. }
  172. func fips1862PRF(seed []byte, length int) []byte {
  173. xkey := new(big.Int).SetBytes(seed)
  174. modulus := new(big.Int).Lsh(big.NewInt(1), 160)
  175. result := make([]byte, 0, length)
  176. for len(result) < length {
  177. xval := xkey.FillBytes(make([]byte, 20))
  178. word := fipsSHA1G(xval)
  179. result = append(result, word[:]...)
  180. increment := new(big.Int).SetBytes(word[:])
  181. xkey.Add(xkey, increment)
  182. xkey.Add(xkey, big.NewInt(1))
  183. xkey.Mod(xkey, modulus)
  184. }
  185. return result[:length]
  186. }
  187. // fipsSHA1G is the SHA-1 compression function G(t, XVAL) from FIPS 186-2.
  188. // Unlike ordinary SHA-1, the 160-bit XVAL is zero-filled to one compression
  189. // block and is not followed by SHA-1 message padding.
  190. func fipsSHA1G(xval []byte) [20]byte {
  191. var words [80]uint32
  192. var block [64]byte
  193. copy(block[:20], xval)
  194. for index := 0; index < 16; index++ {
  195. words[index] = binary.BigEndian.Uint32(block[index*4 : index*4+4])
  196. }
  197. for index := 16; index < 80; index++ {
  198. value := words[index-3] ^ words[index-8] ^ words[index-14] ^ words[index-16]
  199. words[index] = value<<1 | value>>31
  200. }
  201. a := uint32(0x67452301)
  202. b := uint32(0xEFCDAB89)
  203. c := uint32(0x98BADCFE)
  204. d := uint32(0x10325476)
  205. e := uint32(0xC3D2E1F0)
  206. initialA, initialB, initialC, initialD, initialE := a, b, c, d, e
  207. for index := 0; index < 80; index++ {
  208. var function, constant uint32
  209. switch {
  210. case index < 20:
  211. function = (b & c) | (^b & d)
  212. constant = 0x5A827999
  213. case index < 40:
  214. function = b ^ c ^ d
  215. constant = 0x6ED9EBA1
  216. case index < 60:
  217. function = (b & c) | (b & d) | (c & d)
  218. constant = 0x8F1BBCDC
  219. default:
  220. function = b ^ c ^ d
  221. constant = 0xCA62C1D6
  222. }
  223. rotatedA := a<<5 | a>>27
  224. next := rotatedA + function + e + constant + words[index]
  225. e = d
  226. d = c
  227. c = b<<30 | b>>2
  228. b = a
  229. a = next
  230. }
  231. values := [5]uint32{initialA + a, initialB + b, initialC + c, initialD + d, initialE + e}
  232. var result [20]byte
  233. for index, value := range values {
  234. binary.BigEndian.PutUint32(result[index*4:index*4+4], value)
  235. }
  236. return result
  237. }
  238. func permanentAKAIdentity(identity vowifi.SIMIdentity) ([]byte, error) {
  239. imsi := strings.TrimSpace(identity.IMSI)
  240. if len(imsi) < 5 || len(imsi) > 16 {
  241. return nil, errors.New("ike: IMSI length is invalid for EAP-AKA")
  242. }
  243. for _, digit := range imsi {
  244. if digit < '0' || digit > '9' {
  245. return nil, errors.New("ike: IMSI contains a non-digit")
  246. }
  247. }
  248. mcc := strings.TrimSpace(identity.HomeMCC)
  249. mnc := strings.TrimSpace(identity.HomeMNC)
  250. if len(mcc) != 3 || (len(mnc) != 2 && len(mnc) != 3) {
  251. return nil, errors.New("ike: explicit home MCC/MNC is required for EAP-AKA")
  252. }
  253. for len(mnc) < 3 {
  254. mnc = "0" + mnc
  255. }
  256. return []byte(fmt.Sprintf("0%[email protected]%s.mcc%s.3gppnetwork.org", imsi, mnc, mcc)), nil
  257. }
  258. type eapAction struct {
  259. Response []byte
  260. Success bool
  261. }
  262. type akaClient struct {
  263. identity []byte
  264. simIdentity vowifi.SIMIdentity
  265. provider vowifi.AKAProvider
  266. keys akaKeys
  267. challengeComplete bool
  268. resultIndication bool
  269. protectedSuccess bool
  270. }
  271. func newAKAClient(identity vowifi.SIMIdentity, provider vowifi.AKAProvider) (*akaClient, error) {
  272. if provider == nil {
  273. return nil, errors.New("ike: AKA provider is required")
  274. }
  275. nai, err := permanentAKAIdentity(identity)
  276. if err != nil {
  277. return nil, err
  278. }
  279. return &akaClient{identity: nai, simIdentity: identity, provider: provider}, nil
  280. }
  281. func (client *akaClient) handle(ctx context.Context, encoded []byte) (eapAction, error) {
  282. packet, err := parseEAPPacket(encoded)
  283. if err != nil {
  284. return eapAction{}, err
  285. }
  286. switch packet.Code {
  287. case eapFailure:
  288. stage := "before the SIM AKA challenge (identity or subscription rejected)"
  289. if client.challengeComplete {
  290. stage = "after the SIM AKA response (AKA result or subscription rejected)"
  291. }
  292. return eapAction{}, fmt.Errorf("%w %s", vowifi.ErrEAPAuthenticationRejected, stage)
  293. case eapSuccess:
  294. if !client.challengeComplete {
  295. return eapAction{}, errors.New("ike: EAP success arrived before an authenticated AKA challenge")
  296. }
  297. if client.resultIndication && !client.protectedSuccess {
  298. return eapAction{}, errors.New("ike: unprotected EAP success received after AT_RESULT_IND")
  299. }
  300. return eapAction{Success: true}, nil
  301. case eapRequest:
  302. default:
  303. return eapAction{}, fmt.Errorf("ike: unexpected EAP code %d from responder", packet.Code)
  304. }
  305. switch packet.Type {
  306. case eapTypeIdentity:
  307. response, err := marshalEAPPacket(eapPacket{
  308. Code: eapResponse,
  309. Identifier: packet.Identifier,
  310. Type: eapTypeIdentity,
  311. Data: client.identity,
  312. })
  313. return eapAction{Response: response}, err
  314. case eapTypeAKA:
  315. return client.handleAKARequest(ctx, packet)
  316. default:
  317. return eapAction{}, fmt.Errorf("ike: responder requested unsupported EAP type %d", packet.Type)
  318. }
  319. }
  320. func (client *akaClient) handleAKARequest(ctx context.Context, packet eapPacket) (eapAction, error) {
  321. if len(packet.Data) < 3 {
  322. return akaClientErrorResponse(packet.Identifier)
  323. }
  324. subtype := packet.Data[0]
  325. if packet.Data[1] != 0 || packet.Data[2] != 0 {
  326. return akaClientErrorResponse(packet.Identifier)
  327. }
  328. attributes, err := parseAKAAttributes(packet.Data[3:])
  329. if err != nil {
  330. return akaClientErrorResponse(packet.Identifier)
  331. }
  332. switch subtype {
  333. case akaSubtypeIdentity:
  334. action, err := client.respondAKAIdentity(packet.Identifier, attributes)
  335. if err != nil {
  336. return akaClientErrorResponse(packet.Identifier)
  337. }
  338. return action, nil
  339. case akaSubtypeChallenge:
  340. action, err := client.respondAKAChallenge(ctx, packet.Identifier, attributes, packet)
  341. if err != nil && !errors.Is(err, errAKAProvider) &&
  342. !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
  343. return akaClientErrorResponse(packet.Identifier)
  344. }
  345. return action, err
  346. case akaSubtypeNotification:
  347. return client.respondAKANotification(packet.Identifier, attributes, packet)
  348. case akaSubtypeReauth:
  349. return akaClientErrorResponse(packet.Identifier)
  350. default:
  351. return akaClientErrorResponse(packet.Identifier)
  352. }
  353. }
  354. func (client *akaClient) respondAKAIdentity(identifier uint8, attributes []akaAttribute) (eapAction, error) {
  355. requests := 0
  356. for _, attribute := range attributes {
  357. switch attribute.Type {
  358. case akaAttrPermanentIDReq, akaAttrAnyIDReq, akaAttrFullAuthIDReq:
  359. if len(attribute.Raw) != 4 {
  360. return eapAction{}, errors.New("ike: malformed EAP-AKA identity request attribute")
  361. }
  362. requests++
  363. default:
  364. if attribute.Type < 128 {
  365. return eapAction{}, fmt.Errorf("ike: unsupported mandatory EAP-AKA identity attribute %d", attribute.Type)
  366. }
  367. }
  368. }
  369. if requests != 1 {
  370. return eapAction{}, errors.New("ike: EAP-AKA identity request must contain exactly one request attribute")
  371. }
  372. identityAttribute, err := marshalAKAAttribute(akaAttrIdentity, append([]byte{byte(len(client.identity) >> 8), byte(len(client.identity))}, client.identity...))
  373. if err != nil {
  374. return eapAction{}, err
  375. }
  376. data := append([]byte{akaSubtypeIdentity, 0, 0}, identityAttribute...)
  377. response, err := marshalEAPPacket(eapPacket{
  378. Code: eapResponse,
  379. Identifier: identifier,
  380. Type: eapTypeAKA,
  381. Data: data,
  382. })
  383. return eapAction{Response: response}, err
  384. }
  385. func (client *akaClient) respondAKAChallenge(
  386. ctx context.Context,
  387. identifier uint8,
  388. attributes []akaAttribute,
  389. request eapPacket,
  390. ) (eapAction, error) {
  391. for _, attribute := range attributes {
  392. switch attribute.Type {
  393. case akaAttrRAND, akaAttrAUTN, akaAttrMAC, akaAttrResultInd:
  394. default:
  395. if attribute.Type < 128 {
  396. return eapAction{}, fmt.Errorf("ike: unknown mandatory EAP-AKA challenge attribute %d", attribute.Type)
  397. }
  398. }
  399. }
  400. randAttribute, err := oneAKAAttribute(attributes, akaAttrRAND)
  401. if err != nil {
  402. return eapAction{}, err
  403. }
  404. autnAttribute, err := oneAKAAttribute(attributes, akaAttrAUTN)
  405. if err != nil {
  406. return eapAction{}, err
  407. }
  408. macAttribute, err := oneAKAAttribute(attributes, akaAttrMAC)
  409. if err != nil {
  410. return eapAction{}, err
  411. }
  412. if len(randAttribute.Raw) != 20 || len(autnAttribute.Raw) != 20 || len(macAttribute.Raw) != 20 {
  413. return eapAction{}, errors.New("ike: EAP-AKA RAND, AUTN, or MAC has an invalid length")
  414. }
  415. var challenge vowifi.AKAChallenge
  416. copy(challenge.RAND[:], randAttribute.Raw[4:20])
  417. copy(challenge.AUTN[:], autnAttribute.Raw[4:20])
  418. result, err := client.provider.Authenticate(ctx, client.simIdentity, challenge)
  419. if err != nil {
  420. if errors.Is(err, vowifi.ErrEC20AKAMACFailure) {
  421. return akaAuthenticationRejectResponse(identifier)
  422. }
  423. return eapAction{}, errors.Join(errAKAProvider, fmt.Errorf("ike: SIM AKA authentication: %w", err))
  424. }
  425. if result.SynchronizationFailure {
  426. if len(result.AUTS) != 14 {
  427. return eapAction{}, errors.New("ike: SIM reported synchronization failure without a 14-byte AUTS")
  428. }
  429. autsAttribute, err := marshalAKAAttribute(akaAttrAUTS, result.AUTS)
  430. if err != nil {
  431. return eapAction{}, err
  432. }
  433. data := append([]byte{akaSubtypeSyncFailure, 0, 0}, autsAttribute...)
  434. response, err := marshalEAPPacket(eapPacket{Code: eapResponse, Identifier: identifier, Type: eapTypeAKA, Data: data})
  435. return eapAction{Response: response}, err
  436. }
  437. if len(result.RES) < 4 || len(result.RES) > 16 {
  438. return eapAction{}, fmt.Errorf("ike: SIM returned invalid RES length %d", len(result.RES))
  439. }
  440. keys, err := deriveAKAKeys(client.identity, result.IK, result.CK)
  441. if err != nil {
  442. return eapAction{}, err
  443. }
  444. requestBytes, err := marshalEAPPacket(request)
  445. if err != nil {
  446. return eapAction{}, err
  447. }
  448. zeroed := append([]byte(nil), requestBytes...)
  449. macOffset := 5 + 3 + macAttribute.Offset
  450. if macOffset+20 > len(zeroed) {
  451. return eapAction{}, errors.New("ike: EAP-AKA MAC offset is invalid")
  452. }
  453. for index := macOffset + 4; index < macOffset+20; index++ {
  454. zeroed[index] = 0
  455. }
  456. expectedMAC := akaMAC(keys.KAut, zeroed)
  457. if subtle.ConstantTimeCompare(expectedMAC, macAttribute.Raw[4:20]) != 1 {
  458. return eapAction{}, errors.New("ike: EAP-AKA server MAC is invalid")
  459. }
  460. resValue := make([]byte, 2+len(result.RES))
  461. binary.BigEndian.PutUint16(resValue[0:2], uint16(len(result.RES)*8))
  462. copy(resValue[2:], result.RES)
  463. resAttribute, err := marshalAKAAttribute(akaAttrRES, resValue)
  464. if err != nil {
  465. return eapAction{}, err
  466. }
  467. macResponse, _ := marshalAKAAttribute(akaAttrMAC, make([]byte, 18))
  468. responseData := append([]byte{akaSubtypeChallenge, 0, 0}, resAttribute...)
  469. resultIndication := false
  470. for _, attribute := range attributes {
  471. if attribute.Type == akaAttrResultInd {
  472. if len(attribute.Raw) != 4 {
  473. return eapAction{}, errors.New("ike: malformed AT_RESULT_IND")
  474. }
  475. responseData = append(responseData, attribute.Raw...)
  476. resultIndication = true
  477. }
  478. }
  479. responseData = append(responseData, macResponse...)
  480. responseBytes, err := marshalEAPPacket(eapPacket{
  481. Code: eapResponse,
  482. Identifier: identifier,
  483. Type: eapTypeAKA,
  484. Data: responseData,
  485. })
  486. if err != nil {
  487. return eapAction{}, err
  488. }
  489. responseAttributes, _ := parseAKAAttributes(responseData[3:])
  490. responseMAC, err := oneAKAAttribute(responseAttributes, akaAttrMAC)
  491. if err != nil {
  492. return eapAction{}, err
  493. }
  494. responseMACOffset := 5 + 3 + responseMAC.Offset
  495. computed := akaMAC(keys.KAut, responseBytes)
  496. copy(responseBytes[responseMACOffset+4:responseMACOffset+20], computed)
  497. client.keys = keys
  498. client.challengeComplete = true
  499. client.resultIndication = resultIndication
  500. return eapAction{Response: responseBytes}, nil
  501. }
  502. func (client *akaClient) respondAKANotification(
  503. identifier uint8,
  504. attributes []akaAttribute,
  505. request eapPacket,
  506. ) (eapAction, error) {
  507. notification, err := oneAKAAttribute(attributes, akaAttrNotification)
  508. if err != nil {
  509. return eapAction{}, err
  510. }
  511. if len(notification.Raw) != 4 {
  512. return eapAction{}, errors.New("ike: malformed EAP-AKA notification")
  513. }
  514. code := binary.BigEndian.Uint16(notification.Raw[2:4])
  515. if code != 32768 {
  516. responseData := []byte{akaSubtypeNotification, 0, 0}
  517. if code&0x4000 == 0 {
  518. if !client.challengeComplete {
  519. return akaClientErrorResponse(identifier)
  520. }
  521. macAttribute, err := oneAKAAttribute(attributes, akaAttrMAC)
  522. if err != nil || len(macAttribute.Raw) != 20 {
  523. return akaClientErrorResponse(identifier)
  524. }
  525. requestBytes, err := marshalEAPPacket(request)
  526. if err != nil {
  527. return eapAction{}, err
  528. }
  529. zeroed := append([]byte(nil), requestBytes...)
  530. macOffset := 5 + 3 + macAttribute.Offset
  531. for index := macOffset + 4; index < macOffset+20; index++ {
  532. zeroed[index] = 0
  533. }
  534. if subtle.ConstantTimeCompare(akaMAC(client.keys.KAut, zeroed), macAttribute.Raw[4:20]) != 1 {
  535. return akaClientErrorResponse(identifier)
  536. }
  537. responseMAC, _ := marshalAKAAttribute(akaAttrMAC, make([]byte, 18))
  538. responseData = append(responseData, responseMAC...)
  539. }
  540. responseBytes, err := marshalEAPPacket(eapPacket{
  541. Code: eapResponse, Identifier: identifier, Type: eapTypeAKA, Data: responseData,
  542. })
  543. if err != nil {
  544. return eapAction{}, err
  545. }
  546. if code&0x4000 == 0 {
  547. responseAttributes, _ := parseAKAAttributes(responseData[3:])
  548. responseMAC, _ := oneAKAAttribute(responseAttributes, akaAttrMAC)
  549. offset := 5 + 3 + responseMAC.Offset
  550. copy(responseBytes[offset+4:offset+20], akaMAC(client.keys.KAut, responseBytes))
  551. }
  552. return eapAction{Response: responseBytes}, nil
  553. }
  554. if !client.challengeComplete || !client.resultIndication {
  555. return eapAction{}, errors.New("ike: unexpected protected EAP-AKA success notification")
  556. }
  557. macAttribute, err := oneAKAAttribute(attributes, akaAttrMAC)
  558. if err != nil {
  559. return eapAction{}, err
  560. }
  561. if len(macAttribute.Raw) != 20 {
  562. return eapAction{}, errors.New("ike: malformed notification AT_MAC")
  563. }
  564. requestBytes, err := marshalEAPPacket(request)
  565. if err != nil {
  566. return eapAction{}, err
  567. }
  568. zeroed := append([]byte(nil), requestBytes...)
  569. macOffset := 5 + 3 + macAttribute.Offset
  570. for index := macOffset + 4; index < macOffset+20; index++ {
  571. zeroed[index] = 0
  572. }
  573. if subtle.ConstantTimeCompare(akaMAC(client.keys.KAut, zeroed), macAttribute.Raw[4:20]) != 1 {
  574. return eapAction{}, errors.New("ike: EAP-AKA protected success MAC is invalid")
  575. }
  576. responseMAC, _ := marshalAKAAttribute(akaAttrMAC, make([]byte, 18))
  577. responseData := append([]byte{akaSubtypeNotification, 0, 0}, responseMAC...)
  578. responseBytes, err := marshalEAPPacket(eapPacket{
  579. Code: eapResponse,
  580. Identifier: identifier,
  581. Type: eapTypeAKA,
  582. Data: responseData,
  583. })
  584. if err != nil {
  585. return eapAction{}, err
  586. }
  587. responseAttributes, _ := parseAKAAttributes(responseData[3:])
  588. responseMACAttribute, _ := oneAKAAttribute(responseAttributes, akaAttrMAC)
  589. responseOffset := 5 + 3 + responseMACAttribute.Offset
  590. copy(responseBytes[responseOffset+4:responseOffset+20], akaMAC(client.keys.KAut, responseBytes))
  591. client.protectedSuccess = true
  592. return eapAction{Response: responseBytes}, nil
  593. }
  594. func akaMAC(key, packet []byte) []byte {
  595. mac := hmac.New(sha1.New, key)
  596. _, _ = mac.Write(packet)
  597. return mac.Sum(nil)[:16]
  598. }
  599. func akaClientErrorResponse(identifier uint8) (eapAction, error) {
  600. attribute, err := marshalAKAAttribute(akaAttrClientError, []byte{0, 0})
  601. if err != nil {
  602. return eapAction{}, err
  603. }
  604. response, err := marshalEAPPacket(eapPacket{
  605. Code: eapResponse,
  606. Identifier: identifier,
  607. Type: eapTypeAKA,
  608. Data: append([]byte{akaSubtypeClientError, 0, 0}, attribute...),
  609. })
  610. return eapAction{Response: response}, err
  611. }
  612. func akaAuthenticationRejectResponse(identifier uint8) (eapAction, error) {
  613. response, err := marshalEAPPacket(eapPacket{
  614. Code: eapResponse,
  615. Identifier: identifier,
  616. Type: eapTypeAKA,
  617. Data: []byte{akaSubtypeAuthReject, 0, 0},
  618. })
  619. return eapAction{Response: response}, err
  620. }