esim_lpa_test.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package device
  2. import (
  3. "bytes"
  4. "errors"
  5. "testing"
  6. )
  7. // buildTestBPP assembles a synthetic BoundProfilePackage (BF36) with the
  8. // initialiseSecureChannel + A0/A1/A3 sequences lpac's segmenter cares about.
  9. func buildTestBPP(t *testing.T) (bpp []byte, parts map[string][]byte) {
  10. t.Helper()
  11. parts = map[string][]byte{}
  12. parts["bf23"] = tlv([]byte{0xBF, 0x23}, bytes.Repeat([]byte{0x01}, 20))
  13. parts["a0"] = tlv([]byte{0xA0}, bytes.Repeat([]byte{0x02}, 8))
  14. parts["a1c1"] = tlv([]byte{0x88}, bytes.Repeat([]byte{0x03}, 5))
  15. parts["a1c2"] = tlv([]byte{0x88}, bytes.Repeat([]byte{0x04}, 6))
  16. parts["a1"] = tlv([]byte{0xA1}, parts["a1c1"], parts["a1c2"])
  17. parts["a3c1"] = tlv([]byte{0x86}, bytes.Repeat([]byte{0x05}, 7))
  18. parts["a3"] = tlv([]byte{0xA3}, parts["a3c1"])
  19. bpp = tlv([]byte{0xBF, 0x36}, parts["bf23"], parts["a0"], parts["a1"], parts["a3"])
  20. return bpp, parts
  21. }
  22. func TestSegmentBoundProfilePackage(t *testing.T) {
  23. bpp, parts := buildTestBPP(t)
  24. segments, err := segmentBoundProfilePackage(bpp)
  25. if err != nil {
  26. t.Fatalf("segmentBoundProfilePackage: %v", err)
  27. }
  28. // The slices must reassemble into the exact original package.
  29. if got := bytes.Join(segments, nil); !bytes.Equal(got, bpp) {
  30. t.Fatalf("segments do not reassemble to the original BPP")
  31. }
  32. // Segment 0 = BF36 header + complete BF23 (secure channel first).
  33. if !bytes.HasPrefix(segments[0], []byte{0xBF, 0x36}) {
  34. t.Fatalf("segment 0 must start with BF36, got %X", segments[0][:3])
  35. }
  36. if !bytes.Contains(segments[0], parts["bf23"]) {
  37. t.Fatalf("segment 0 must contain the full BF23")
  38. }
  39. // A0 sent whole; A1/A3 split header then children.
  40. if !bytes.Equal(segments[1], parts["a0"]) {
  41. t.Fatalf("segment 1 should be the whole A0")
  42. }
  43. if !bytes.Equal(segments[2], parts["a1"][:2]) {
  44. t.Fatalf("segment 2 should be the A1 header only, got %X", segments[2])
  45. }
  46. if !bytes.Equal(segments[3], parts["a1c1"]) || !bytes.Equal(segments[4], parts["a1c2"]) {
  47. t.Fatalf("A1 children not segmented correctly")
  48. }
  49. }
  50. func TestSegmentBoundProfilePackageNoBF36(t *testing.T) {
  51. if _, err := segmentBoundProfilePackage(tlv([]byte{0xBF, 0x35}, []byte{0x00})); err == nil {
  52. t.Fatalf("expected error when BF36 is absent")
  53. }
  54. }
  55. func buildInstallResult(t *testing.T, finalResult []byte) []byte {
  56. t.Helper()
  57. iccidBCD, err := encodeICCID("8944476500017228672")
  58. if err != nil {
  59. t.Fatalf("encodeICCID: %v", err)
  60. }
  61. notifMeta := tlv([]byte{0xBF, 0x2F}, tlv([]byte{0x80}, []byte{0x01}), tlv([]byte{0x5A}, iccidBCD))
  62. bf27 := tlv([]byte{0xBF, 0x27}, notifMeta, finalResult)
  63. return tlv([]byte{0xBF, 0x37}, bf27)
  64. }
  65. func TestInstallationResultSuccess(t *testing.T) {
  66. payload := buildInstallResult(t, tlv([]byte{0xA2}, tlv([]byte{0xA0})))
  67. iccid, err := installationResult(payload)
  68. if err != nil {
  69. t.Fatalf("installationResult: %v", err)
  70. }
  71. if iccid != "8944476500017228672" {
  72. t.Fatalf("iccid = %q", iccid)
  73. }
  74. }
  75. func TestInstallationResultInsufficientMemory(t *testing.T) {
  76. // A2 { A1 { 80 bppCommandId=5, 81 errorReason=10 (insufficient memory) } }
  77. errResult := tlv([]byte{0xA1}, tlv([]byte{0x80}, []byte{0x05}), tlv([]byte{0x81}, []byte{0x0A}))
  78. payload := buildInstallResult(t, tlv([]byte{0xA2}, errResult))
  79. _, err := installationResult(payload)
  80. if err == nil {
  81. t.Fatalf("expected an installation error")
  82. }
  83. var installErr *esimInstallError
  84. if !errors.As(err, &installErr) {
  85. t.Fatalf("expected *esimInstallError, got %T (%v)", err, err)
  86. }
  87. if installErr.ErrorReason != 10 || installErr.CommandID != 5 {
  88. t.Fatalf("got reason=%d command=%d", installErr.ErrorReason, installErr.CommandID)
  89. }
  90. if code := ESIMDownloadErrorCode(err); code != "euicc_insufficient_memory" {
  91. t.Fatalf("error code = %q, want euicc_insufficient_memory", code)
  92. }
  93. }
  94. func TestESIMDownloadErrorCodePublicProfileFailures(t *testing.T) {
  95. tests := []struct {
  96. err error
  97. want string
  98. }{
  99. {
  100. err: errors.New("The SM-DP+ has no CERT.DPauth.SIG which chains to one of the eSIM CA Root CA Certificate with a Public Key supported by the eUICC"),
  101. want: "euicc_ci_incompatible",
  102. },
  103. {err: errors.New("Refused"), want: "activation_code_refused"},
  104. {err: errors.New("campaign resource pool is empty"), want: "profile_pool_empty"},
  105. }
  106. for _, test := range tests {
  107. if got := ESIMDownloadErrorCode(test.err); got != test.want {
  108. t.Errorf("ESIMDownloadErrorCode(%q) = %q, want %q", test.err, got, test.want)
  109. }
  110. }
  111. }
  112. func TestAuthenticateServerResultError(t *testing.T) {
  113. success := derConstruct(0xBF38, derConstruct(0xA0, derEncode(0x30, nil)))
  114. if err := authenticateServerResultError(success); err != nil {
  115. t.Fatalf("success response returned %v", err)
  116. }
  117. errorResponse := derConstruct(0xBF38, derConstruct(0xA1,
  118. derConstruct(0x30, derEncode(0x80, []byte{0x01, 0x02}), derEncode(0x02, []byte{0x02})),
  119. ))
  120. err := authenticateServerResultError(errorResponse)
  121. var authenticateErr *esimAuthenticateError
  122. if !errors.As(err, &authenticateErr) || authenticateErr.Code != 2 {
  123. t.Fatalf("error = %T %v, want authenticate code 2", err, err)
  124. }
  125. if code := ESIMDownloadErrorCode(err); code != "euicc_authentication_failed" {
  126. t.Fatalf("download error code = %q", code)
  127. }
  128. }
  129. func TestEuiccFreeNVRAM(t *testing.T) {
  130. // BF22 { 84 { 81 installedApp, 82 freeNonVolatile=0x05E849, 83 freeVolatile } }
  131. extRes := tlv([]byte{0x84},
  132. tlv([]byte{0x81}, []byte{0x00}),
  133. tlv([]byte{0x82}, []byte{0x05, 0xE8, 0x49}),
  134. tlv([]byte{0x83}, []byte{0x00}),
  135. )
  136. info2 := tlv([]byte{0xBF, 0x22}, extRes)
  137. n, ok := euiccFreeNVRAM(info2)
  138. if !ok || n != 387145 {
  139. t.Fatalf("freeNVRAM = %d, ok=%v (want 387145)", n, ok)
  140. }
  141. if _, ok := euiccFreeNVRAM(tlv([]byte{0xBF, 0x22})); ok {
  142. t.Fatalf("expected ok=false when extCardResource absent")
  143. }
  144. }