diff --git a/apps/chanora_flutter/ios/Runner/Info.plist b/apps/chanora_flutter/ios/Runner/Info.plist index b97e12f..057971e 100644 --- a/apps/chanora_flutter/ios/Runner/Info.plist +++ b/apps/chanora_flutter/ios/Runner/Info.plist @@ -25,7 +25,7 @@ CFBundleVersion $(FLUTTER_BUILD_NUMBER) ITSAppUsesNonExemptEncryption - + LSRequiresIPhoneOS LSSupportsOpeningDocumentsInPlace diff --git a/apps/chanora_flutter/macos/Runner/Info.plist b/apps/chanora_flutter/macos/Runner/Info.plist index 3a96692..00d425c 100644 --- a/apps/chanora_flutter/macos/Runner/Info.plist +++ b/apps/chanora_flutter/macos/Runner/Info.plist @@ -23,7 +23,7 @@ CFBundleVersion $(FLUTTER_BUILD_NUMBER) ITSAppUsesNonExemptEncryption - + LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright diff --git a/docs/release/export-compliance.md b/docs/release/export-compliance.md new file mode 100644 index 0000000..ecb0eb8 --- /dev/null +++ b/docs/release/export-compliance.md @@ -0,0 +1,148 @@ +# iOS / macOS Export Compliance + +Status: TestFlight workaround applied. Production submission requires the steps below. + +## Current state (2026-06-08) + +Both `apps/chanora_flutter/ios/Runner/Info.plist` and `apps/chanora_flutter/macos/Runner/Info.plist` declare: + +```xml +ITSAppUsesNonExemptEncryption + +``` + +This is a **temporary workaround** to unblock TestFlight uploads. It is NOT correct for public App Store release because Chanora ships non-exempt encryption (see "Why Chanora is not exempt" below). The workaround is acceptable for internal testing under TestFlight while the BIS self-classification and Apple export-compliance documentation are being prepared. + +## Why Chanora is not exempt + +Chanora is a **closed-source proprietary** application that uses encryption beyond Apple's "standard system encryption" exemption: + +1. `chacha20poly1305` in `crates/chanora_storage` — AEAD encryption of the local Data Encryption Key (DEK) for secret storage. +2. `tsclientlib` in `crates/chanora_protocol` and `crates/chanora_audio` — implements TeamSpeak's custom Ed25519 / P-256 / EAX cryptographic handshake. This is NOT standard IETF TLS. +3. `rustls` in `crates/chanora_protocol` and `crates/chanora_resolver` — ships its own TLS implementation rather than using the system stack. + +Apple's exemption (HTTPS via system networking only) does not apply. Because Chanora is closed-source, the "publicly available source code" path (§734.3(b)(3) + §742.15(b)) is also unavailable — that route is reserved for open-source distributions whose cryptographic source is publicly accessible without restriction. + +Chanora's path is therefore the **mass-market self-classification** route under §740.17(b)(1) with Note 3 to Category 5, Part 2 of the CCL — closed-source consumer apps with standard published algorithms qualify as mass-market and self-classify under **ECCN 5D992.c**. `ITSAppUsesNonExemptEncryption` must be `` for any public release, and `ITSEncryptionExportComplianceCode` must accompany it. + +## The submission flow (in order) + +### Step 1: File the BIS annual self-classification report + +US Department of Commerce, Bureau of Industry and Security (BIS), requires an annual self-classification report for mass-market encryption software under EAR §740.17(b)(1). Since Chanora is **closed-source** but distributed as a mass-market consumer app with standard cryptographic algorithms, it qualifies for self-classification under the **mass-market note (Note 3 to Category 5, Part 2 of the CCL)**, which reclassifies it from ECCN 5D002.c.1 to **ECCN 5D992.c**. + +There is **no fee**, **no review**, **no pre-approval needed**. You export immediately under (b)(1) and file the report within 30 days. + +The format is a **CSV file** per Supplement No. 8 to Part 742, not a prose email body. Send it as an attachment: + +**Recipients** (CC both): +- `crypt@bis.doc.gov` +- `enc@nsa.gov` + +**Subject**: `Self-Classification Report — Chanora — [YEAR]` + +**CSV template** (fill in `[BRACKETS]`): + +```csv +Submitter Name,Submitter Email,Submitter Phone,Submitter Address,Item Type,Item Name,Item Version,ECCN,Authorization Type,Encryption Algorithm,Key Length,Item Description +[YOUR NAME],[YOU@EMAIL.COM],[PHONE],[ADDRESS],Mass Market Encryption Software,Chanora,[VERSION e.g. v1.0.0-rc.1],5D992.c,MMKT,ChaCha20-Poly1305; Ed25519; P-256 ECDH; EAX-AES; TLS 1.2/1.3,256,Cross-platform voice communication client for TeamSpeak-compatible servers. Cryptographic algorithms are all published standards; the application is closed-source proprietary software distributed via mass-market channels (Apple App Store). +``` + +**Notes on the CSV**: +- **Authorization Type** `MMKT` signals the mass-market self-classification under Note 3. +- **ECCN** `5D992.c` — the mass-market note reclassifies closed-source mass-market software with standard crypto from 5D002.c.1 to 5D992.c, removing it from "EI" and "NS" controls. +- The CSV is a **single row** for one product. For multiple products, add one row per product. +- Send it **once per calendar year** (BIS deadline: February 1 for prior calendar year). +- Keep the sent-mail receipt — Apple may ask to see proof during the App Store review. +- BIS does not reply. Filing the report is the compliance event; no approval or confirmation is needed. + +### Step 2: App Store Connect — encryption questionnaire + +Path: `App Store Connect → My Apps → Chanora → App Information → Encryption` (or during version submission, the same questionnaire appears). + +Answer the questions as follows for Chanora: + +1. "Does your app use encryption?" → **Yes** +2. "Does your app qualify for any of the exemptions provided in Category 5, Part 2 of the U.S. Export Administration Regulations?" → **No** + (We do use non-exempt crypto — see "Why Chanora is not exempt".) +3. "Does your app implement any encryption algorithms that are proprietary or not accepted as standard by international standard bodies (IEEE, IETF, ITU, etc.)?" → **No** + (ChaCha20-Poly1305 is RFC 8439; Ed25519 is RFC 8032; P-256 is FIPS 186-4. TeamSpeak's handshake uses standard primitives even though the orchestration is custom.) +4. "Does your app implement any standard encryption algorithms instead of, or in addition to, using or accessing the encryption in Apple's operating system?" → **Yes** +5. "Is your app made available on the French App Store?" → answer per your distribution plan (Yes if you want EU/FR availability). + +Apple will then ask you to upload supporting documentation. Upload: +- A PDF copy of your sent email from Step 1 (showing the date sent and both recipients), with the CSV attachment shown or attached. +- A short cover sheet identifying: product name (Chanora), ECCN (`5D992.c`), authorization basis (`§740.17(b)(1)` mass-market self-classification under Note 3 to Category 5, Part 2 of the CCL), and the date the report was sent to BIS. + +### Step 3: Receive the code from Apple + +After review (typical turnaround: a few business days to ~2 weeks), Apple sends an email with the export compliance code. The code is a UUID, lowercase, 36 characters, e.g. `aeafaa12-a017-48c8-a29a-bdd3061f93e3` (this is Keybase's actual code, used here as a format example only). + +The code is **per-app, not per-version**. Once issued it can be reused for every subsequent build until your encryption usage materially changes. + +### Step 4: Revert the workaround and patch in the code + +Edit `apps/chanora_flutter/ios/Runner/Info.plist`: + +```xml +ITSAppUsesNonExemptEncryption + +ITSEncryptionExportComplianceCode +PASTE_APPLE_ISSUED_UUID_HERE +``` + +Do the same for `apps/chanora_flutter/macos/Runner/Info.plist`. + +Optionally — to avoid committing the literal UUID to git — use a build variable instead (matches the `procivis/one-wallet` pattern): + +```xml +ITSAppUsesNonExemptEncryption + +ITSEncryptionExportComplianceCode +$(CHANORA_IOS_EXPORT_COMPLIANCE_CODE) +``` + +Then set `CHANORA_IOS_EXPORT_COMPLIANCE_CODE` as a build setting (in `Runner.xcodeproj` user-defined settings, in a non-tracked `.xcconfig`, or via the CI/Fastlane environment). + +Validate after editing: + +```bash +plutil -lint apps/chanora_flutter/ios/Runner/Info.plist +plutil -lint apps/chanora_flutter/macos/Runner/Info.plist +``` + +### Step 5: Submit and confirm + +Re-upload the build via Xcode → Organizer → Distribute App, or via Fastlane / CI. App Store Connect should no longer reject the build with the "Invalid Export Compliance Code" error. + +If you use Fastlane, you can also pass `uses_non_exempt_encryption: true` to `upload_to_testflight` / `upload_to_app_store` as belt-and-suspenders; the Info.plist value is authoritative. + +## Annual maintenance + +- Every January, re-send the BIS self-classification CSV (Step 1) with the current year and the latest released version. Deadline: **February 1** for the prior calendar year. Keep the receipt. +- The Apple-issued code does NOT need re-issuance unless Chanora adds a fundamentally new encryption capability (e.g. end-to-end encrypted DMs would qualify; bumping an existing AEAD library version would not). +- If you add E2EE for direct messages, change the at-rest encryption algorithm, or introduce proprietary (non-standard) cryptography, the mass-market classification may no longer apply — you would need to either re-self-classify or file a CCATS (Commodity Classification) request via SNAP-R, and Apple will need updated documentation and a new code. + +## References + +- Apple — `ITSAppUsesNonExemptEncryption` key: +- Apple — `ITSEncryptionExportComplianceCode` key: +- Apple — Complying with encryption export regulations: +- Apple — App Store Connect Help, export compliance overview: +- Apple — App Store Connect Help, determine and upload encryption documentation: +- BIS — Encryption FAQs: +- BIS — EAR §740.17 (License Exception ENC, self-classification): +- BIS — Supplement No. 8 to Part 742 (self-classification report CSV format): +- BIS — Note 3 to Category 5, Part 2 of the CCL (mass-market note): +- Real-world examples (closed-source iOS apps with `ITSEncryptionExportComplianceCode`): + - Keybase: + - Status.im: + - Cryptomator: +- Build-variable pattern (avoid committing UUID to git): + - Procivis One Wallet: + +## Decision log + +| Date | Decision | Rationale | +|---|---|---| +| 2026-06-08 | Temporarily set `ITSAppUsesNonExemptEncryption=` on both iOS and macOS Info.plist | Unblock TestFlight internal testing while BIS / Apple paperwork is being prepared. Re-do per Steps 1-5 above before any public App Store release. |