Parse an ICAO / BSI CSCA Master List (.ml
) and export every Country Signing CA certificate inside it β as a PEM bundle, as a TSV manifest, or just as a count.
One file, one dependency, no framework.
python extract_masterlist.py DE_ML_2026-01-08.ml -o csca_bundle.pem -m manifest.tsv
master list : DE_ML_2026-01-08.ml (891,227 bytes)
entries : 581
parsed : 581 (openssl fallback rescued 6)
unparsable : 0
unique : 581
countries : 112
top issuers : CN=26, HU=21, BE=19, LU=12, TR=12, LV=11, AU=10, GR=10, MT=10, NL=10
PEM bundle -> csca_bundle.pem
manifest -> manifest.tsv
A Master List is the trust anchor set for electronic passports: to validate the SOD on any eMRTD you need the issuing country's CSCA, and Master Lists are how states distribute them in bulk. The format is specified in ICAO Doc 9303 Part 12 and BSI TR-03129:
ContentInfo
ββ SignedData
ββ encapContentInfo.eContent (OCTET STRING)
ββ CscaMasterList ::= SEQUENCE {
version INTEGER,
certList SET OF Certificate
}
That is not hard β but there is remarkably little public tooling that just opens the file and gives you the certificates. Most eMRTD code buries the parse inside a larger verification stack. This repo is the parse on its own.
Run against a real Master List with --strict
and six entries drop on the floor:
entries : 581
parsed : 575
unparsable : 6
All six fail inside cryptography
's Rust ASN.1 parser with:
ParseError { kind: ExtraData, location: ["Certificate::tbs_cert",
"TbsCertificate::signature_alg"] }
They are not junk. OpenSSL reads every one of them:
| # | Subject |
|---|---|
| 48, 49 | C=AT, O=GV, OU=BMI, CN=CSCA-AUSTRIA |
| 61 | C=AE, O=MOI, OU=EPASS, CN=UAE CSCA 02 |
| 84, 85, 90 | C=JP, O=Japanese Government, OU=The Ministry of Foreign Affairs, CN=e-passportCSCA |
These are live, government-issued CSCAs carrying trailing bytes in the
signature AlgorithmIdentifier
that a strict DER parser rejects. Austria, the UAE and Japan are not edge cases you get to skip β silently dropping them means passports from those countries fail validation with a confusing "unknown issuer" instead of a real error.
So the default path falls back to openssl x509
for anything cryptography
refuses, and the manifest records which parser produced each row:
country subject ... parser
AT CN=CSCA-AUSTRIA,OU=BMI,... ... openssl
AD CN=CSCA-AND,OU=MJI,... ... cryptography
Use --strict
if you want the lenient path off and the failures visible.
pip install -r requirements.txt # cryptography
openssl
on PATH
is optional; without it, --strict
behaviour is the only behaviour and the six certificates above are reported as unparsable.
extract_masterlist.py MASTERLIST [-o BUNDLE.pem] [-m MANIFEST.tsv]
[--keep-duplicates] [--strict]
| flag | effect |
|---|---|
-o , --out |
|
| write the concatenated PEM trust bundle | |
-m , --manifest |
|
| write a TSV row per certificate (country, subject, serial, validity, sig alg, SHA-256, size, parser) | |
--keep-duplicates |
|
| keep every entry; default de-duplicates by SHA-256 | |
--strict |
|
| no OpenSSL fallback |
With no output flags it prints statistics and exits β useful for diffing two Master List releases.
See examples/manifest_sample.tsv for the manifest shape.
ICAO PKDβhttps://pkddownloadsg.icao.int/(the authoritative source)** German BSI**β publishes a national Master List that aggregates a large share of participating states
No Master List is bundled here, and .gitignore
refuses to commit one. Fetch your own and keep it fresh: CSCAs roll over, and a stale trust store is how you end up rejecting valid documents.
JMRTDβ 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β open-source client for a commercial chip-verification service.
Neither of them will hand you the certificates out of a .ml
file, which is what this repo is for.
This tool reads public trust anchors β the certificates states publish specifically so that anyone can validate the passports they issue. It handles no private keys, no chip communication, and no passport data. It is the boring, public half of eMRTD work, which is exactly why it can be open.
MIT