{"slug": "six-government-passport-cas-that-python-rejects-and-openssl-accepts", "title": "Six government passport CAs that Python rejects and OpenSSL accepts", "summary": "A new open-source tool, extract_masterlist.py, parses ICAO/BSI CSCA Master Lists and exports country signing CA certificates as PEM bundles or TSV manifests, handling 581 entries across 112 countries in a test run. The tool defaults to an OpenSSL fallback because six live government-issued certificates from Austria, the UAE, and Japan fail strict DER parsing in Python's cryptography library due to trailing bytes in the signature AlgorithmIdentifier, and silently dropping them would cause passport validation failures. The project is available on GitHub and requires only the cryptography package, with OpenSSL optional for lenient parsing.", "body_md": "Parse an ICAO / BSI **CSCA Master List** (`.ml`\n\n) and export every Country\nSigning CA certificate inside it — as a PEM bundle, as a TSV manifest, or just\nas a count.\n\nOne file, one dependency, no framework.\n\n```\npython extract_masterlist.py DE_ML_2026-01-08.ml -o csca_bundle.pem -m manifest.tsv\nmaster list : DE_ML_2026-01-08.ml (891,227 bytes)\nentries     : 581\nparsed      : 581   (openssl fallback rescued 6)\nunparsable  : 0\nunique      : 581\ncountries   : 112\n\ntop issuers : CN=26, HU=21, BE=19, LU=12, TR=12, LV=11, AU=10, GR=10, MT=10, NL=10\n\nPEM bundle  -> csca_bundle.pem\nmanifest    -> manifest.tsv\n```\n\nA Master List is the trust anchor set for electronic passports: to validate the\nSOD on any eMRTD you need the issuing country's CSCA, and Master Lists are how\nstates distribute them in bulk. The format is specified in **ICAO Doc 9303\nPart 12** and **BSI TR-03129**:\n\n```\nContentInfo\n └─ SignedData\n     └─ encapContentInfo.eContent  (OCTET STRING)\n         └─ CscaMasterList ::= SEQUENCE {\n                version   INTEGER,\n                certList  SET OF Certificate\n            }\n```\n\nThat is not hard — but there is remarkably little public tooling that just\n*opens the file and gives you the certificates*. Most eMRTD code buries the\nparse inside a larger verification stack. This repo is the parse on its own.\n\nRun against a real Master List with `--strict`\n\nand six entries drop on the\nfloor:\n\n```\nentries     : 581\nparsed      : 575\nunparsable  : 6\n```\n\nAll six fail inside `cryptography`\n\n's Rust ASN.1 parser with:\n\n```\nParseError { kind: ExtraData, location: [\"Certificate::tbs_cert\",\n                                         \"TbsCertificate::signature_alg\"] }\n```\n\nThey are not junk. OpenSSL reads every one of them:\n\n| # | Subject |\n|---|---|\n| 48, 49 | `C=AT, O=GV, OU=BMI, CN=CSCA-AUSTRIA` |\n| 61 | `C=AE, O=MOI, OU=EPASS, CN=UAE CSCA 02` |\n| 84, 85, 90 | `C=JP, O=Japanese Government, OU=The Ministry of Foreign Affairs, CN=e-passportCSCA` |\n\nThese are live, government-issued CSCAs carrying trailing bytes in the\nsignature `AlgorithmIdentifier`\n\nthat a strict DER parser rejects. Austria,\nthe UAE and Japan are not edge cases you get to skip — silently dropping them\nmeans passports from those countries fail validation with a confusing\n\"unknown issuer\" instead of a real error.\n\nSo the default path falls back to `openssl x509`\n\nfor anything `cryptography`\n\nrefuses, and the manifest records which parser produced each row:\n\n```\ncountry  subject                      ...  parser\nAT       CN=CSCA-AUSTRIA,OU=BMI,...   ...  openssl\nAD       CN=CSCA-AND,OU=MJI,...       ...  cryptography\n```\n\nUse `--strict`\n\nif you want the lenient path off and the failures visible.\n\n```\npip install -r requirements.txt   # cryptography\n```\n\n`openssl`\n\non `PATH`\n\nis optional; without it, `--strict`\n\nbehaviour is the only\nbehaviour and the six certificates above are reported as unparsable.\n\n```\nextract_masterlist.py MASTERLIST [-o BUNDLE.pem] [-m MANIFEST.tsv]\n                                 [--keep-duplicates] [--strict]\n```\n\n| flag | effect |\n|---|---|\n`-o` , `--out` |\nwrite the concatenated PEM trust bundle |\n`-m` , `--manifest` |\nwrite a TSV row per certificate (country, subject, serial, validity, sig alg, SHA-256, size, parser) |\n`--keep-duplicates` |\nkeep every entry; default de-duplicates by SHA-256 |\n`--strict` |\nno OpenSSL fallback |\n\nWith no output flags it prints statistics and exits — useful for diffing two Master List releases.\n\nSee [ examples/manifest_sample.tsv](/Eginn-33/csca-masterlist-tools/blob/main/examples/manifest_sample.tsv) for the\nmanifest shape.\n\n**ICAO PKD**—[https://pkddownloadsg.icao.int/](https://pkddownloadsg.icao.int/)(the authoritative source)** German BSI**— publishes a national Master List that aggregates a large share of participating states\n\nNo Master List is bundled here, and `.gitignore`\n\nrefuses to commit one. Fetch\nyour own and keep it fresh: CSCAs roll over, and a stale trust store is how\nyou end up rejecting valid documents.\n\n[JMRTD](https://jmrtd.org/)— the long-running open-source eMRTD implementation (Java). Also publishes per-country CSCA certificates, useful when you want a handful of anchors rather than a whole Master List.[Kinegram eMRTD Connector](https://github.com/OVD-Kinegram-AG/emrtd-connector-sdk-ios)— open-source client for a commercial chip-verification service.\n\nNeither of them will hand you the certificates out of a `.ml`\n\nfile, which is\nwhat this repo is for.\n\nThis tool reads **public trust anchors** — the certificates states publish\nspecifically so that anyone can validate the passports they issue. It handles\nno private keys, no chip communication, and no passport data. It is the\nboring, public half of eMRTD work, which is exactly why it can be open.\n\nMIT", "url": "https://wpnews.pro/news/six-government-passport-cas-that-python-rejects-and-openssl-accepts", "canonical_source": "https://github.com/Eginn-33/csca-masterlist-tools", "published_at": "2026-08-26 19:19:11+00:00", "updated_at": "2026-08-26 19:44:14.127565+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["extract_masterlist.py", "OpenSSL", "cryptography", "ICAO", "BSI", "Austria", "UAE", "Japan"], "alternates": {"html": "https://wpnews.pro/news/six-government-passport-cas-that-python-rejects-and-openssl-accepts", "markdown": "https://wpnews.pro/news/six-government-passport-cas-that-python-rejects-and-openssl-accepts.md", "text": "https://wpnews.pro/news/six-government-passport-cas-that-python-rejects-and-openssl-accepts.txt", "jsonld": "https://wpnews.pro/news/six-government-passport-cas-that-python-rejects-and-openssl-accepts.jsonld"}}