Repository navigation
How to contribute CSCA/DSC coverage for additional countries (IL, PT)? #1962
Description
Activity
Hi @dagangilat thanks for the issue! You're correct that we currently don't rely on
common/pubkeys/public_keys_parsed.jsonWe're currently working on our CSCA pipeline to make it more transparent for our users so it would be great if there's a legitimate source / public link for the CSCAs you have. TIA!Edit: You can find the supported signature algorithms here
Thanks @Nesopie for the quick response and the pointer to the circuit file!
I checked the supported algorithms — both countries use standard RSA-SHA256, which maps to existing circuit IDs:
Country CSCA Algorithm Circuit ID Israel RSA-4096 / SHA-256 / e=65537 10(rsa_sha256_65537_4096)Portugal RSA-3072 or 4096 / SHA-256 14or10So no circuit changes needed — just the CSCA certificates.
Sources I've found
Important discovery: Neither Israel nor Portugal is an ICAO PKD participant (participants list), so their CSCAs aren't in the ICAO master list.
Best bet — German BSI Master List
The BSI publishes a compiled CSCA master list covering 114 countries via bilateral exchange (more than the PKD's 109). It's freely downloadable:- Portal: https://www.bsi.bund.de/EN/Themen/Oeffentliche-Verwaltung/Elektronische-Identitaeten/Public-Key-Infrastrukturen/CSCA/csca_node.html
- Direct download: https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/ElekAusweise/CSCA/GermanMasterList.zip?__blob=publicationFile&v=103 (493KB, 581 certs, issued 2026-01-08)
I haven't confirmed IL/PT are in there yet — tools like nicocha/CSCA-masterlist or ciarancarolan/eMRTD-PKD can parse the
.mlfile to extract individual PEM certs per country. Happy to do this and submit the extracted certs if that's helpful.Portugal — direct government source
Portugal's IRN (Instituto dos Registos e do Notariado) publishes their CSCA directly:- Info page: https://irn.justica.gov.pt/Documentos-de-Identificacao/Certificados-CSCA
- PKI certificates: https://pki2.cartaodecidadao.pt/publico/entidade-certificacao-cc/certificados
Israel
No public government CSCA page exists. The BSI master list (bilateral exchange) is likely the only public path. If it's not there, I have physical access to a current Israeli biometric ID and can extract the CSCA from the SOD via NFC if that would help as a starting point for cross-verification.Other references
A few other projects maintaining CSCA registries that might be useful for your pipeline:
- psvz/icao — pre-extracted CSCA/DSC certs from ICAO LDIF files
- ZKPassport registry explorer — browseable certificate registry
- Rarimo passport-zk-circuits — on-chain CSCA registry (Keccak256 hashed)
Next steps from my side
- Download and parse the BSI master list to confirm IL/PT presence
- If present, extract the PEM certs and share them here
- If not, extract Portugal's from the IRN source and Israel's from a physical document via NFC
Update: CSCA certificates extracted and verified
I downloaded and parsed the German BSI CSCA Master List (issued 2026-01-08, 581 certificates, 116 countries). Both Israel and Portugal are present despite not being ICAO PKD participants — Germany obtained them via bilateral exchange.
Source: BSI Master List ZIP (493KB, freely downloadable)
Extracted PEM files: https://gist.github.com/dagangilat/2a3447ed370b9e6d251f39678f48698b
Extraction method
The
.mlfile is CMS-signed. Extract and parse with:# 1. Extract CMS content openssl cms -inform DER -in DE_ML_2026-01-08-12-20-54.ml -verify -noverify -out ml_content.der # 2. Parse ASN.1 structure (SET of 581 X.509 certs) openssl asn1parse -inform DER -in ml_content.der
Then iterate over all
d=2 SEQUENCEentries, extract each as DER, parse withopenssl x509, and filter by country code.Full Python extraction script
import subprocess, re, os with open('ml_content.der', 'rb') as f: data = f.read() r = subprocess.run( ['openssl', 'asn1parse', '-inform', 'DER', '-in', 'ml_content.der'], capture_output=True, text=True ) certs = [] for line in r.stdout.split('\n'): m = re.match(r'\s*(\d+):d=2\s+hl=(\d+)\s+l=\s*(\d+)\s+cons:\s*SEQUENCE', line) if m: certs.append((int(m.group(1)), int(m.group(2)), int(m.group(3)))) for cc in ['IL', 'PT']: os.makedirs(f'csca_certs/{cc}', exist_ok=True) count = {'IL': 0, 'PT': 0} for offset, hl, length in certs: cert_der = data[offset:offset+hl+length] with open('tmp.der', 'wb') as f: f.write(cert_der) r2 = subprocess.run( ['openssl', 'x509', '-inform', 'DER', '-in', 'tmp.der', '-noout', '-subject'], capture_output=True, text=True ) if r2.returncode != 0: continue subject = r2.stdout.strip() for cc in ['IL', 'PT']: if re.search(rf'\bC\s*=\s*{cc}\b', subject): count[cc] += 1 pem = subprocess.run( ['openssl', 'x509', '-inform', 'DER', '-in', 'tmp.der', '-outform', 'PEM'], capture_output=True, text=True ) with open(f'csca_certs/{cc}/{cc}_csca_{count[cc]:02d}.pem', 'w') as f: f.write(pem.stdout) print(f'{cc}_csca_{count[cc]:02d}.pem — {subject}') break os.remove('tmp.der')
Israel — 5 CSCA certificates (Issuer: PIBA)
# CN Algorithm Key Valid 1 EPPCSCA ecdsa-with-SHA384 384-bit secp384r1 2023-07 → 2039-01 2 EPPCSCA rsassaPss 384-bit 2023-07 → 2039-01 3 EPPCSCA sha256WithRSA 4096-bit 2018-08 → 2034-02 4 EPPCSCA rsassaPss 4096-bit 2013-05 → 2028-11 5 EPPCSCA rsassaPss 4096-bit 2018-08 → 2034-02 Portugal — 6 CSCA certificates (Republica Portuguesa — ICAO MRTD PKI)
# CN Algorithm Key Valid 1 ECN Documentos de Viagem 006 sha256WithRSA 4096-bit 2019-06 → 2027-11 2 ENC 006 007 (crosslink) sha256WithRSA 4096-bit 2022-06 → 2027-11 3 ECN Crosslink 007-008 sha512WithRSA 4096-bit 2023-10 → 2030-08 4 ECN Crosslink 007-008 sha512WithRSA 4096-bit 2024-03 → 2030-08 5 ECN Documentos de Viagem 008 sha512WithRSA 4096-bit 2023-10 → 2037-01 6 ECN Documentos de Viagem 007 sha512WithRSA 4096-bit 2022-06 → 2030-08
Algorithm compatibility with Self circuits
Cross-referenced against
signatureAlgorithm.circom:Algorithm Circuit ID Status RSA-SHA256 / 4096 / e=65537 10Supported RSA-SHA512 / 4096 / e=65537 15Supported RSA-PSS SHA256 / 4096 12Supported ECDSA-SHA384 / secp384r1 9Supported All algorithms are already covered by existing circuits. No circuit changes needed.
Let me know what else you need from my side — happy to open a PR if there's a target directory for these.
Hi @dagangilat, thank you for this! We already parse the German / Netherlands masterlist and after de duplicating by SKI we have 3 certs for Israel and Portugal
Adding on to this, we already have these certs in our current tree. Can you tell us what exactly was failing / the error message you received when you created the proof? Thanks!
Hi @Nesopie, thanks for looking into this!
Good news — I retested today and both Israeli biometric passport and Portuguese biometric passport verify successfully in the Self app. Full ZK proofs generated, both show as HI-SECURITY. So the passport path is working for IL and PT.What does fail is ID cards — specifically the Israeli biometric national ID card (Teudat Zehut) and the Portuguese Cartão de Cidadão. Here's the exact flow for the Israeli ID card case:
- Select Israel → select "ID card" type
- App asks to scan an MRZ line, but the Israeli ID card doesn't have a standard passport-style MRZ
- To get past that step, I pointed the camera at my Israeli passport's MRZ instead — MRZ read succeeded
- Then held the ID card to the NFC reader for the chip scan
- Failed with: "There was a problem reading the chip" — presumably because the MRZ data (from the passport) doesn't match the chip data on the ID card
The Portuguese Cartão de Cidadão had the same issue — no compatible MRZ on the card to scan.
Summary of 4 documents tested:
Document Result Israeli Passport ✅ SUCCESS — full ZK proof, HI-SECURITY Portuguese Passport ✅ SUCCESS — full ZK proof, HI-SECURITY Israeli ID Card (Teudat Zehut) ❌ FAIL — MRZ/chip mismatch, NFC read fails Portuguese Cartão de Cidadão ❌ FAIL — same issue, no compatible MRZ on card Device: iPhone 13 (MLPK3HB/A), iOS 26.4.1, latest Self app version. Happy to test further or provide additional details. Thanks again for the quick responses!
Hi! Can you confirm that the MRZ on the Israeli and Portugese ID Cards has 3 lines? This seems like an NFC reading issue. Tagging @seshanthS, for the NFC issue
Hi @Nesopie,
Thanks for looking into this!
Here's a full update after retesting all four documents.Passports — both working:
Both the Israeli and Portuguese biometric passports now verify successfully with full ZK proofs (HI-SECURITY). The passport path is fully working for IL and PT.ID cards — MRZ scan fails, but alternative method works:
-
Israeli Biometric ID Card (Teudat Zehut): The app prompts to "Align the animation with the MRZ on the passport," but the Israeli biometric ID card has no MRZ lines at all. There is no way to proceed past this step. (The Israeli biometric passport has 2 MRZ lines and verifies successfully.)
-
Portuguese Cartão de Cidadão: Same prompt — "Align the animation with the MRZ on the passport." The Portuguese biometric ID card does have 3 MRZ lines (TD1 format), but the app doesn't recognize them. (The Portuguese biometric passport has 2 MRZ lines in TD3 format and verifies successfully.)
-
Workaround — "Try a different method": After the NFC scan failure, I used the "Try a different method" button and was able to successfully add and verify both the Israeli biometric ID card and the Portuguese Cartão de Cidadão.
The core issue seems to be that the MRZ scanner only supports the 2-line TD3 (passport) format and doesn't handle TD1 (ID card) format — or in the Israeli case, the complete absence of an MRZ. The alternative verification method does work for both cards.
Device: iPhone 13, iOS 26.4.1.
-
Hi Self team — I'm building a proof-of-humanity layer for Foundation, a governance platform on Solana, and Self is our high-trust ePassport path. First, thanks for the work — the SDK integration was straightforward and Phase 1 of our rollout is live on devnet.
Per your contribution guidelines, opening this issue before starting work. I'd like to contribute country coverage for Israel and Portugal and want to check with you on the right workflow before doing the work.
What I observed
Parsing
common/pubkeys/public_keys_parsed.jsonat HEAD:Live scans confirm the registry state: a current Israeli biometric national ID and a Portuguese Cartão de Cidadão (ePassport) both fail verification in the Self mobile app — neither document produces a successful proof. Both countries are ICAO PKD participants, so CSCA/DSC material is publicly available.
What I'm unsure about
Is
public_keys_parsed.jsonstill the right place to contribute? The file was last updated 2024-12-02, and I understand the on-chain Identity Registry on Celo is the authoritative trust anchor circuits verify against. If a PR to the JSON file no longer changes runtime behavior, what's the correct path — a registry update viacontracts/scripts/setRegistry.ts, coordination with the team for a batch update, or something else?Signature algorithm compatibility. Before I prepare IL/PT DSC material, is there a documented list of signature algorithms / curve parameters currently supported by the circuits? I want to avoid submitting keys that would require circuit changes to verify.
Preferred source format. Do you prefer raw PKD master list extracts, pre-parsed JSON in the existing schema, or something else?
Happy to do the work — just want to make sure it lands somewhere useful. A Discord channel or different repo for this kind of contribution would also work if GitHub isn't the right venue.
Thanks!
— Dagan Gilat, Founder @ Foundation