Compare commits

...
Author SHA1 Message Date
Edison Jwa f4ffde2752 docs(release): add closed-source export-compliance plan; TestFlight workaround
App Store Connect rejected the iOS upload with 'Invalid Export
Compliance Code' because ITSAppUsesNonExemptEncryption was <true/>
without an accompanying ITSEncryptionExportComplianceCode. Apply a
TestFlight-only workaround now and document the full production path
that needs to land before any public App Store / Mac App Store release.

Info.plist (ios + macos)
- ITSAppUsesNonExemptEncryption set to <false/> on both platforms to
  unblock TestFlight internal-test uploads. This is NOT correct for
  public release: Chanora ships non-system crypto (chacha20poly1305 in
  chanora_storage, custom Ed25519/P-256/EAX in tsclientlib, bundled
  TLS in rustls), so the value MUST be flipped back to <true/> with a
  valid ITSEncryptionExportComplianceCode before any public submission.

docs/release/export-compliance.md (new)
- Closed-source mass-market path under EAR §740.17(b)(1) with Note 3
  to Category 5, Part 2 of the CCL (reclassifies the app from
  ECCN 5D002.c.1 to ECCN 5D992.c).
- BIS annual self-classification report as CSV per Supplement No. 8
  to Part 742, with authorization type MMKT; recipients crypt@bis.doc
  .gov + enc@nsa.gov; deadline Feb 1 for prior calendar year; no fee,
  no pre-approval, file within 30 days of first export.
- Apple App Store Connect questionnaire answers for Chanora, with the
  supporting-documentation upload (sent BIS CSV + cover sheet).
- Step-by-step revert plan once Apple issues the UUID, including the
  optional CHANORA_IOS_EXPORT_COMPLIANCE_CODE build-variable pattern
  (procivis/one-wallet style) to keep the UUID out of git.
- Annual maintenance plus the fallback to CCATS / SNAP-R if Chanora
  ever adds non-standard crypto or E2EE DMs.
- References to Apple docs, eCFR §740.17, Supplement No. 8, and real-
  world closed-source iOS Info.plist examples (Keybase, Status.im,
  Cryptomator) confirming the UUID format and key placement.

Verification
- plutil -lint apps/chanora_flutter/ios/Runner/Info.plist: OK
- plutil -lint apps/chanora_flutter/macos/Runner/Info.plist: OK

Follow-up
- README.md / LICENSE-{APACHE,MIT} / DEC-020 still declare Chanora as
  Apache-2.0/MIT dual-licensed. The closed-source export-compliance
  doc assumes proprietary distribution; the license decision needs
  reconciliation before submission so the BIS CSV and Apple
  questionnaire answers match the actual distribution model.
2026-06-08 05:46:26 +09:00
3 changed files with 150 additions and 2 deletions
+1 -1
View File
@@ -25,7 +25,7 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<true/> <false/>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>LSSupportsOpeningDocumentsInPlace</key> <key>LSSupportsOpeningDocumentsInPlace</key>
+1 -1
View File
@@ -23,7 +23,7 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<true/> <false/>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
+148
View File
@@ -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
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
```
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 `<true/>` 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
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>
<string>PASTE_APPLE_ISSUED_UUID_HERE</string>
```
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
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>
<string>$(CHANORA_IOS_EXPORT_COMPLIANCE_CODE)</string>
```
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: <https://developer.apple.com/documentation/bundleresources/information-property-list/itsappusesnonexemptencryption>
- Apple — `ITSEncryptionExportComplianceCode` key: <https://developer.apple.com/documentation/bundleresources/information-property-list/itsencryptionexportcompliancecode>
- Apple — Complying with encryption export regulations: <https://developer.apple.com/documentation/security/complying-with-encryption-export-regulations>
- Apple — App Store Connect Help, export compliance overview: <https://developer.apple.com/help/app-store-connect/manage-app-information/overview-of-export-compliance/>
- Apple — App Store Connect Help, determine and upload encryption documentation: <https://developer.apple.com/help/app-store-connect/manage-app-information/determine-and-upload-app-encryption-documentation/>
- BIS — Encryption FAQs: <https://www.bis.doc.gov/index.php/policy-guidance/encryption>
- BIS — EAR §740.17 (License Exception ENC, self-classification): <https://www.ecfr.gov/current/title-15/subtitle-B/chapter-VII/subchapter-C/part-740/section-740.17>
- BIS — Supplement No. 8 to Part 742 (self-classification report CSV format): <https://www.ecfr.gov/current/title-15/subtitle-B/chapter-VII/subchapter-C/part-742>
- BIS — Note 3 to Category 5, Part 2 of the CCL (mass-market note): <https://www.ecfr.gov/current/title-15/subtitle-B/chapter-VII/subchapter-C/part-774>
- Real-world examples (closed-source iOS apps with `ITSEncryptionExportComplianceCode`):
- Keybase: <https://github.com/keybase/client/blob/master/shared/ios/Keybase/Info.plist>
- Status.im: <https://github.com/status-im/status-mobile/blob/develop/ios/StatusIm/Info.plist>
- Cryptomator: <https://github.com/cryptomator/ios/blob/develop/Cryptomator/Info.plist>
- Build-variable pattern (avoid committing UUID to git):
- Procivis One Wallet: <https://github.com/procivis/one-wallet/blob/main/ios/Wallet/Info.plist>
## Decision log
| Date | Decision | Rationale |
|---|---|---|
| 2026-06-08 | Temporarily set `ITSAppUsesNonExemptEncryption=<false/>` 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. |