@necessarysdk/react-native 0.0.0-stage → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +2 -0
  4. package/NecessaryReactNative.podspec +23 -0
  5. package/README.md +429 -2
  6. package/android/build.gradle +83 -0
  7. package/android/src/main/AndroidManifest.xml +41 -0
  8. package/android/src/main/cpp/CMakeLists.txt +7 -0
  9. package/android/src/main/cpp/code_integrity.cpp +484 -0
  10. package/android/src/main/java/com/necessarysdk/reactnative/Causes.kt +49 -0
  11. package/android/src/main/java/com/necessarysdk/reactnative/InstallationKeyManager.kt +388 -0
  12. package/android/src/main/java/com/necessarysdk/reactnative/IntegrityProbeManager.kt +1157 -0
  13. package/android/src/main/java/com/necessarysdk/reactnative/KeyPresence.kt +62 -0
  14. package/android/src/main/java/com/necessarysdk/reactnative/NecessaryModules.kt +94 -0
  15. package/android/src/main/java/com/necessarysdk/reactnative/NecessaryNative.kt +338 -0
  16. package/android/src/main/java/com/necessarysdk/reactnative/NecessaryPackage.kt +38 -0
  17. package/android/src/main/java/com/necessarysdk/reactnative/ProbeReads.kt +333 -0
  18. package/android/src/main/java/com/necessarysdk/reactnative/ScreenGuard.kt +56 -0
  19. package/android/src/main/java/com/necessarysdk/reactnative/SecureStore.kt +127 -0
  20. package/android/src/main/java/com/necessarysdk/reactnative/StepUpKeyEntry.kt +57 -0
  21. package/android/src/main/java/com/necessarysdk/reactnative/StepUpKeyManager.kt +767 -0
  22. package/contract/report-1/android-8-ios-5/RULES.md +149 -0
  23. package/contract/report-1/android-8-ios-5/report.schema.json +2753 -0
  24. package/contract/report-1/android-8-ios-5/samples/android-8-complete.json +205 -0
  25. package/contract/report-1/android-8-ios-5/samples/android-8-incomplete.json +205 -0
  26. package/contract/report-1/android-8-ios-5/samples/android-8-invalid.json +205 -0
  27. package/contract/report-1/android-8-ios-5/samples/android-8-location-one-fix.json +228 -0
  28. package/contract/report-1/android-8-ios-5/samples/android-8-location-two-fixes.json +228 -0
  29. package/contract/report-1/android-8-ios-5/samples/android-8-refused.json +208 -0
  30. package/contract/report-1/android-8-ios-5/samples/ios-5-complete.json +106 -0
  31. package/contract/report-1/android-8-ios-5/samples/ios-5-incomplete.json +105 -0
  32. package/contract/report-1/android-8-ios-5/samples/ios-5-invalid.json +107 -0
  33. package/contract/report-1/android-8-ios-5/samples/ios-5-partial.json +110 -0
  34. package/contract/report-1/android-8-ios-5/samples/ios-5-refused.json +109 -0
  35. package/doc/integration_guide.md +771 -0
  36. package/doc/measurements.md +774 -0
  37. package/ios/InstallationKeyManager.swift +694 -0
  38. package/ios/IntegrityProbeManager.swift +959 -0
  39. package/ios/NecessaryModules.h +34 -0
  40. package/ios/NecessaryModules.mm +208 -0
  41. package/ios/NecessaryNative.swift +327 -0
  42. package/ios/PrivacyInfo.xcprivacy +14 -0
  43. package/ios/ProbeReads.swift +370 -0
  44. package/lib/client.d.ts +105 -0
  45. package/lib/client.js +176 -0
  46. package/lib/collector.d.ts +18 -0
  47. package/lib/collector.js +49 -0
  48. package/lib/deviceTrust.d.ts +253 -0
  49. package/lib/deviceTrust.js +699 -0
  50. package/lib/errors.d.ts +43 -0
  51. package/lib/errors.js +56 -0
  52. package/lib/index.d.ts +18 -0
  53. package/lib/index.js +34 -0
  54. package/lib/installationKey.d.ts +62 -0
  55. package/lib/installationKey.js +185 -0
  56. package/lib/installationStore.d.ts +49 -0
  57. package/lib/installationStore.js +127 -0
  58. package/lib/native/NativeNecessaryInstallationKey.d.ts +10 -0
  59. package/lib/native/NativeNecessaryInstallationKey.js +4 -0
  60. package/lib/native/NativeNecessaryIntegrity.d.ts +8 -0
  61. package/lib/native/NativeNecessaryIntegrity.js +4 -0
  62. package/lib/native/NativeNecessarySecureScreen.d.ts +7 -0
  63. package/lib/native/NativeNecessarySecureScreen.js +4 -0
  64. package/lib/native/NativeNecessaryStepUpKey.d.ts +9 -0
  65. package/lib/native/NativeNecessaryStepUpKey.js +4 -0
  66. package/lib/native/NativeNecessaryStorage.d.ts +14 -0
  67. package/lib/native/NativeNecessaryStorage.js +4 -0
  68. package/lib/protocol.d.ts +24 -0
  69. package/lib/protocol.js +50 -0
  70. package/lib/reinstallHint.d.ts +23 -0
  71. package/lib/reinstallHint.js +65 -0
  72. package/lib/report.d.ts +62 -0
  73. package/lib/report.js +134 -0
  74. package/lib/requestProof.d.ts +116 -0
  75. package/lib/requestProof.js +220 -0
  76. package/lib/secureScreen.d.ts +15 -0
  77. package/lib/secureScreen.js +32 -0
  78. package/lib/stepUpKey.d.ts +105 -0
  79. package/lib/stepUpKey.js +187 -0
  80. package/lib/transport.d.ts +39 -0
  81. package/lib/transport.js +117 -0
  82. package/lib/util/answers.d.ts +6 -0
  83. package/lib/util/answers.js +16 -0
  84. package/lib/util/bytes.d.ts +18 -0
  85. package/lib/util/bytes.js +207 -0
  86. package/lib/util/native.d.ts +20 -0
  87. package/lib/util/native.js +49 -0
  88. package/lib/util/release.d.ts +2 -0
  89. package/lib/util/release.js +7 -0
  90. package/lib/util/target.d.ts +18 -0
  91. package/lib/util/target.js +128 -0
  92. package/package.json +81 -4
  93. package/src/client.ts +221 -0
  94. package/src/collector.ts +64 -0
  95. package/src/deviceTrust.ts +851 -0
  96. package/src/errors.ts +71 -0
  97. package/src/index.ts +19 -0
  98. package/src/installationKey.ts +223 -0
  99. package/src/installationStore.ts +143 -0
  100. package/src/native/NativeNecessaryInstallationKey.ts +12 -0
  101. package/src/native/NativeNecessaryIntegrity.ts +15 -0
  102. package/src/native/NativeNecessarySecureScreen.ts +9 -0
  103. package/src/native/NativeNecessaryStepUpKey.ts +11 -0
  104. package/src/native/NativeNecessaryStorage.ts +16 -0
  105. package/src/protocol.ts +52 -0
  106. package/src/reinstallHint.ts +69 -0
  107. package/src/report.ts +168 -0
  108. package/src/requestProof.ts +295 -0
  109. package/src/secureScreen.ts +29 -0
  110. package/src/stepUpKey.ts +238 -0
  111. package/src/transport.ts +145 -0
  112. package/src/util/answers.ts +15 -0
  113. package/src/util/bytes.ts +194 -0
  114. package/src/util/native.ts +56 -0
  115. package/src/util/release.ts +6 -0
  116. package/src/util/target.ts +132 -0
  117. package/vectors/client_server.json +264 -0
@@ -0,0 +1,149 @@
1
+ # The measurement contract: report format 1, Android collector 8, iOS collector 5
2
+
3
+ What a Necessary collector sends in its signed integrity report, and how to read it. Three parts,
4
+ all in this folder:
5
+
6
+ - `report.schema.json` — the report's shape (JSON Schema 2020-12): every measurement, field, type,
7
+ unit and bound. It says what is well-formed, nothing more.
8
+ - this file — what a schema cannot say: when a measurement is complete, how its figures add up, what
9
+ contradicts itself, and how versions change.
10
+ - `samples/` — reports as a collector signs them, for each platform, each with the plan it answers and
11
+ how it is judged.
12
+
13
+ The thresholds and the decisions are yours: which measurements to ask for, what each one costs, how
14
+ old a location may be, when to refuse. Nothing here scores anything.
15
+
16
+ ## 1. The report
17
+
18
+ - The app sends `report_payload`, the base64url (without padding) of the report's UTF-8 JSON bytes,
19
+ and `report_signature`: ECDSA P-256 over SHA-256 of exactly those bytes, ASN.1 DER, base64url.
20
+ Verify over the bytes as sent, never over JSON you encoded again. The plugins' shared test vectors
21
+ (`client_server.json`) pin the encoding.
22
+ - At most 65,536 bytes decoded: refuse larger.
23
+ - `version` is 1. `challenge_nonce` is the challenge's 32-byte nonce exactly as issued (43
24
+ characters). `collected_at` is the phone's clock in Unix seconds, to be within 90 seconds of yours.
25
+ `collector_version` is the collector's version on its platform. `probe_results` holds one object per
26
+ measurement; `enabled_measurements` names the personal measurements this app's developers enabled.
27
+ - Numbers the schema types as integers are written without a fraction or an exponent, and a number is
28
+ never `true` or `false`.
29
+
30
+ ## 2. What counts as a measurement
31
+
32
+ - Each measurement has a `status`: `ok`, measured; `error`, with `error` saying why (Android may add
33
+ `error_type`); `unsupported`, with `reason`; or `not_enabled`, a personal measurement this app does
34
+ not collect. `ok` means measured, never "all clear": what was found is in the fields.
35
+ - **`ok` says measured; the fields say how much.** A measurement is complete when it answered `ok` and carries
36
+ every field its `x-complete-when-ok` lists — for `code_integrity` with `checked` true, every field of
37
+ `x-complete-when-checked` too, and for a personal measurement every one of its `x-parts`.
38
+ - **`unread`** names the parts an `ok` measurement could not read, each with why: at most 64, a name
39
+ of at most 128 characters, a reason of at most 160. An unread part is not measured — never read it
40
+ as a clean "no". A measurement that could read nothing answers `error`.
41
+ - A field a collector version does not know is absent: read absent as not measured.
42
+ - A report that lacks a measurement you asked for is refused, not read. A failed or incomplete one
43
+ tells you something could not be measured; it is not proof of an attack. Ask again rather than
44
+ punish the person.
45
+
46
+ ## 3. When each measurement comes
47
+
48
+ Each measurement's `x-answered` says it:
49
+
50
+ - **when the backend requests it** — ask, in the challenge, for every measurement you rely on, every
51
+ time, and vary the others from scan to scan;
52
+ - **volunteered on every scan** — `device`, `network`, and on iOS `code_integrity`. Rely on one only
53
+ if you decide to; until you ask for it, its absence or failure does not make a report incomplete;
54
+ - **personal** — only when the backend asks for it and the app's developers enabled it, and the
55
+ location only with the person's permission as well. Drop any personal measurement you did not ask
56
+ for before you store or read the report, after checking the signature over the bytes as sent.
57
+
58
+ ## 4. Comparing code in memory with its files
59
+
60
+ **Android** compares three regions: `core` (the C library and the runtime), `ext` (the other system
61
+ libraries the app has mapped) and `app` (the app's own native code). In each region the expected bytes
62
+ are the compared, skipped and unreadable bytes together, and `<region>_complete` is true exactly when
63
+ some code was expected and all of it was compared. `checked` false: the comparison did not run.
64
+ `checked` true with nothing compared in a region that always holds code: nothing was measured there.
65
+
66
+ **iOS** can compare only the app's own code. The system libraries live in a shared cache no app can
67
+ read: `system_images_unreadable` counts them, and their figures are always 0 — not measured, never
68
+ clean. Every app image the loader has mapped is expected, and each is compared, unreadable (its file
69
+ could not be read in full) or skipped (no usable `__text`, a `__TEXT` too large, no live address);
70
+ `app_images_not_compared` names each one not compared, by its path in the app, with why. Images and
71
+ bytes both add up: expected = compared + unreadable + skipped. `app_complete` is true exactly when every
72
+ image was compared — the images decide, since an image whose `__text` size could not be read adds no
73
+ bytes — and then the main executable is among them (`main_executable_compared`).
74
+
75
+ On both, a comparison short of complete compared part of the code: never a complete clean comparison.
76
+ Any differing byte in compared code is a change in code that should never change.
77
+
78
+ ## 5. Location
79
+
80
+ - Without the permission (`permission` `none`) no coordinates are sent.
81
+ - The location is the one the phone already holds — never a fresh fix, never a prompt — and
82
+ `age_seconds` says how old it is. How old is too old is yours to decide.
83
+ - With the permission and no coordinates, the phone holds no location — but only when every location
84
+ source was read: with a source in `unread`, the location may be there.
85
+ - Both answers describe one fix, read once per scan, and carry its time (`fix_time`, Unix seconds):
86
+ two different times are two observations presented as one.
87
+ - `mock_location` never carries coordinates, so asking for it alone never sends them. On iOS `mock` is
88
+ Apple's flag, from iOS 15; `accessory` marks a location from an external GPS accessory.
89
+
90
+ ## 6. Lists
91
+
92
+ - **Apps** (`services`, `listeners`, `device_admins`, `remote_access_apps`): at most 32 from a
93
+ collector, each with `package`, and `service`, `system` and `installer` where Android shows them;
94
+ `truncated` is true when the phone had more. A list is complete only when `truncated` is false.
95
+ - **`split_apks`**: each installed split's file `name` and `sha256`, at most 64, **sorted by name, none
96
+ twice** — the one rule the schema cannot state. Empty without splits. `apk_sha256` is the base APK's
97
+ alone, so installs of one release with different splits share it.
98
+ - **`current_signers`, `signing_lineage`**: at most 8 lower-case hex SHA-256 digests each.
99
+ - **`addresses`** (`local_addresses`): at most 64, each an `interface` and an `address` of at most 64
100
+ characters.
101
+
102
+ ## 7. Figures that cannot all be true
103
+
104
+ A report whose figures contradict each other is one to distrust: not a measurement, clean or
105
+ otherwise.
106
+
107
+ - code-comparison coverage that does not add up, or a `complete` flag that does not follow from it
108
+ (section 4);
109
+ - no writable-and-executable mapping, with the sizes of such mappings listed;
110
+ - screen recording `unsupported` on a platform version that measures it (iOS; Android 15 and later);
111
+ - two different `fix_time`s for the location and the mock-location answers.
112
+
113
+ These, by contrast, are failed reads — incomplete, not contradictions: a process map read as empty
114
+ (`maps_lines` 0), no thread found in a running process (`thread_count` 0), a code comparison that did
115
+ not run or compared nothing in a region that always holds code.
116
+
117
+ ## 8. Versions
118
+
119
+ - `collector_version` counts per platform. This contract: Android 8, iOS 5 — the schema allows no
120
+ lower version on either, since an older collector's report is not this contract's.
121
+ - Before these versions a collector could report a failed read as a clean value (Android before 8) or
122
+ a partial comparison of the app's code as complete (iOS before 5). Refuse those versions, or keep
123
+ their scans apart as older evidence.
124
+ - Fields are only ever added; a field's meaning never changes. A new measurement is volunteered before
125
+ any backend asks for it, so that older apps keep working. Unknown fields and unknown measurements
126
+ are ignored.
127
+ - A new contract gets a folder of its own beside this one.
128
+
129
+ ## 9. The samples
130
+
131
+ Each sample holds the report as a collector signs it (`report`), the plan it answers
132
+ (`required_probes`, and the personal `optional_probes`), and how a backend following these rules
133
+ judges it (`expect`, with `why`). The envelope's `installation_id`, `challenge_id`, `challenge_nonce`
134
+ and `collected_at` are placeholders a test replaces before signing. Each is checked, as published,
135
+ against the reference backend's judgment.
136
+
137
+ | Sample | Judged | What it shows |
138
+ |---|---|---|
139
+ | `android-8-complete` | complete | a clean phone, every requested measurement whole, one split APK listed apart |
140
+ | `android-8-incomplete` | incomplete | a setting in `unread`, a probe in `error` |
141
+ | `android-8-invalid` | invalid | coverage that does not add up |
142
+ | `android-8-location-one-fix` | complete | both location answers with one `fix_time` |
143
+ | `android-8-location-two-fixes` | invalid | the mock flag of another fix than the coordinates |
144
+ | `android-8-refused` | refused | an `unread` that is not an object |
145
+ | `ios-5-complete` | complete | a clean iPhone, every app image compared |
146
+ | `ios-5-incomplete` | incomplete | an `ok` without its fields |
147
+ | `ios-5-partial` | partial | the app-code comparison requested, one image unreadable |
148
+ | `ios-5-invalid` | invalid | images that do not add up |
149
+ | `ios-5-refused` | refused | an `app_images_not_compared` that is not an object |