Files
chanora/docs/release/export-compliance.md
T
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

11 KiB

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:

<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]):

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:

<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):

<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:

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

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.