eap_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. package ike
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "strings"
  7. "testing"
  8. "vocat/internal/vowifi"
  9. )
  10. type testAKAProvider struct {
  11. result vowifi.AKAResult
  12. err error
  13. challenge vowifi.AKAChallenge
  14. calls int
  15. }
  16. func (provider *testAKAProvider) CheckReady(context.Context, vowifi.SIMIdentity) (vowifi.AKAEvidence, error) {
  17. return vowifi.AKAEvidence{Ready: true, Application: "USIM"}, nil
  18. }
  19. func (provider *testAKAProvider) Authenticate(
  20. _ context.Context,
  21. _ vowifi.SIMIdentity,
  22. challenge vowifi.AKAChallenge,
  23. ) (vowifi.AKAResult, error) {
  24. provider.calls++
  25. provider.challenge = challenge
  26. return provider.result, provider.err
  27. }
  28. func testSIMIdentity() vowifi.SIMIdentity {
  29. return vowifi.SIMIdentity{
  30. IMSI: "234150123456789",
  31. HomeMCC: "234",
  32. HomeMNC: "15",
  33. }
  34. }
  35. func TestEAPAKAIdentityRequiresExactlyOneRequestAttribute(t *testing.T) {
  36. client, err := newAKAClient(testSIMIdentity(), &testAKAProvider{})
  37. if err != nil {
  38. t.Fatalf("newAKAClient() error = %v", err)
  39. }
  40. request, err := marshalEAPPacket(eapPacket{
  41. Code: eapRequest,
  42. Identifier: 9,
  43. Type: eapTypeAKA,
  44. Data: []byte{akaSubtypeIdentity, 0, 0},
  45. })
  46. if err != nil {
  47. t.Fatal(err)
  48. }
  49. action, err := client.handle(context.Background(), request)
  50. if err != nil {
  51. t.Fatalf("handle malformed identity error = %v", err)
  52. }
  53. response, err := parseEAPPacket(action.Response)
  54. if err != nil {
  55. t.Fatal(err)
  56. }
  57. if response.Code != eapResponse || response.Identifier != 9 ||
  58. response.Type != eapTypeAKA || len(response.Data) < 1 ||
  59. response.Data[0] != akaSubtypeClientError {
  60. t.Fatalf("malformed identity response = %#v", response)
  61. }
  62. permanent, _ := marshalAKAAttribute(akaAttrPermanentIDReq, []byte{0, 0})
  63. validRequest, _ := marshalEAPPacket(eapPacket{
  64. Code: eapRequest,
  65. Identifier: 10,
  66. Type: eapTypeAKA,
  67. Data: append([]byte{akaSubtypeIdentity, 0, 0}, permanent...),
  68. })
  69. action, err = client.handle(context.Background(), validRequest)
  70. if err != nil {
  71. t.Fatalf("handle valid identity error = %v", err)
  72. }
  73. response, _ = parseEAPPacket(action.Response)
  74. if response.Data[0] != akaSubtypeIdentity {
  75. t.Fatalf("valid identity response subtype = %d", response.Data[0])
  76. }
  77. attributes, err := parseAKAAttributes(response.Data[3:])
  78. if err != nil {
  79. t.Fatal(err)
  80. }
  81. identity, err := oneAKAAttribute(attributes, akaAttrIdentity)
  82. if err != nil {
  83. t.Fatal(err)
  84. }
  85. length := int(identity.Raw[2])<<8 | int(identity.Raw[3])
  86. if got := string(identity.Raw[4 : 4+length]); got != "[email protected]" {
  87. t.Fatalf("permanent AKA identity = %q", got)
  88. }
  89. }
  90. func TestEAPFailureReportsAuthenticationStage(t *testing.T) {
  91. client, err := newAKAClient(testSIMIdentity(), &testAKAProvider{})
  92. if err != nil {
  93. t.Fatal(err)
  94. }
  95. failure, err := marshalEAPPacket(eapPacket{Code: eapFailure, Identifier: 3})
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. _, err = client.handle(context.Background(), failure)
  100. if !errors.Is(err, vowifi.ErrEAPAuthenticationRejected) || !strings.Contains(err.Error(), "before the SIM AKA challenge") {
  101. t.Fatalf("pre-challenge failure = %v", err)
  102. }
  103. client.challengeComplete = true
  104. _, err = client.handle(context.Background(), failure)
  105. if !errors.Is(err, vowifi.ErrEAPAuthenticationRejected) || !strings.Contains(err.Error(), "after the SIM AKA response") {
  106. t.Fatalf("post-challenge failure = %v", err)
  107. }
  108. }
  109. func TestEAPAKAChallengeTypedSIMAndMAC(t *testing.T) {
  110. result := vowifi.AKAResult{
  111. RES: bytes.Repeat([]byte{0x91}, 8),
  112. CK: bytes.Repeat([]byte{0x92}, 16),
  113. IK: bytes.Repeat([]byte{0x93}, 16),
  114. }
  115. provider := &testAKAProvider{result: result}
  116. client, err := newAKAClient(testSIMIdentity(), provider)
  117. if err != nil {
  118. t.Fatal(err)
  119. }
  120. keys, err := deriveAKAKeys(client.identity, result.IK, result.CK)
  121. if err != nil {
  122. t.Fatal(err)
  123. }
  124. randValue := bytes.Repeat([]byte{0xa1}, 16)
  125. autnValue := bytes.Repeat([]byte{0xa2}, 16)
  126. randAttribute, _ := marshalAKAAttribute(akaAttrRAND, append([]byte{0, 0}, randValue...))
  127. autnAttribute, _ := marshalAKAAttribute(akaAttrAUTN, append([]byte{0, 0}, autnValue...))
  128. macAttribute, _ := marshalAKAAttribute(akaAttrMAC, make([]byte, 18))
  129. data := []byte{akaSubtypeChallenge, 0, 0}
  130. data = append(data, randAttribute...)
  131. data = append(data, autnAttribute...)
  132. data = append(data, macAttribute...)
  133. request, _ := marshalEAPPacket(eapPacket{
  134. Code: eapRequest,
  135. Identifier: 21,
  136. Type: eapTypeAKA,
  137. Data: data,
  138. })
  139. attributes, _ := parseAKAAttributes(data[3:])
  140. mac, _ := oneAKAAttribute(attributes, akaAttrMAC)
  141. macOffset := 5 + 3 + mac.Offset
  142. copy(request[macOffset+4:macOffset+20], akaMAC(keys.KAut, request))
  143. action, err := client.handle(context.Background(), request)
  144. if err != nil {
  145. t.Fatalf("handle challenge error = %v", err)
  146. }
  147. if provider.calls != 1 || !bytes.Equal(provider.challenge.RAND[:], randValue) ||
  148. !bytes.Equal(provider.challenge.AUTN[:], autnValue) {
  149. t.Fatalf("typed SIM challenge = %#v calls=%d", provider.challenge, provider.calls)
  150. }
  151. response, err := parseEAPPacket(action.Response)
  152. if err != nil {
  153. t.Fatal(err)
  154. }
  155. if response.Data[0] != akaSubtypeChallenge {
  156. t.Fatalf("challenge response subtype = %d", response.Data[0])
  157. }
  158. responseAttributes, err := parseAKAAttributes(response.Data[3:])
  159. if err != nil {
  160. t.Fatal(err)
  161. }
  162. res, err := oneAKAAttribute(responseAttributes, akaAttrRES)
  163. if err != nil {
  164. t.Fatal(err)
  165. }
  166. if bits := int(res.Raw[2])<<8 | int(res.Raw[3]); bits != len(result.RES)*8 {
  167. t.Fatalf("AT_RES bits = %d", bits)
  168. }
  169. responseMAC, err := oneAKAAttribute(responseAttributes, akaAttrMAC)
  170. if err != nil {
  171. t.Fatal(err)
  172. }
  173. zeroed := append([]byte(nil), action.Response...)
  174. responseOffset := 5 + 3 + responseMAC.Offset
  175. actualMAC := append([]byte(nil), zeroed[responseOffset+4:responseOffset+20]...)
  176. for index := responseOffset + 4; index < responseOffset+20; index++ {
  177. zeroed[index] = 0
  178. }
  179. if !bytes.Equal(actualMAC, akaMAC(keys.KAut, zeroed)) {
  180. t.Fatal("response AT_MAC does not authenticate the complete EAP packet")
  181. }
  182. success, _ := marshalEAPPacket(eapPacket{Code: eapSuccess, Identifier: 22})
  183. finalAction, err := client.handle(context.Background(), success)
  184. if err != nil || !finalAction.Success {
  185. t.Fatalf("authenticated EAP success = %#v err=%v", finalAction, err)
  186. }
  187. }
  188. func TestEAPAKAUSIMNetworkAuthenticationFailureSendsReject(t *testing.T) {
  189. provider := &testAKAProvider{err: vowifi.ErrEC20AKAMACFailure}
  190. client, err := newAKAClient(testSIMIdentity(), provider)
  191. if err != nil {
  192. t.Fatal(err)
  193. }
  194. randAttribute, _ := marshalAKAAttribute(akaAttrRAND, append([]byte{0, 0}, bytes.Repeat([]byte{1}, 16)...))
  195. autnAttribute, _ := marshalAKAAttribute(akaAttrAUTN, append([]byte{0, 0}, bytes.Repeat([]byte{2}, 16)...))
  196. macAttribute, _ := marshalAKAAttribute(akaAttrMAC, make([]byte, 18))
  197. data := append([]byte{akaSubtypeChallenge, 0, 0}, randAttribute...)
  198. data = append(data, autnAttribute...)
  199. data = append(data, macAttribute...)
  200. request, _ := marshalEAPPacket(eapPacket{Code: eapRequest, Identifier: 5, Type: eapTypeAKA, Data: data})
  201. action, err := client.handle(context.Background(), request)
  202. if err != nil {
  203. t.Fatalf("handle USIM MAC failure error = %v", err)
  204. }
  205. response, _ := parseEAPPacket(action.Response)
  206. if len(response.Data) != 3 || response.Data[0] != akaSubtypeAuthReject {
  207. t.Fatalf("USIM MAC failure response = %#v", response)
  208. }
  209. if !errors.Is(provider.err, vowifi.ErrEC20AKAMACFailure) {
  210. t.Fatal("test provider lost the MAC failure sentinel")
  211. }
  212. }