emsign-g3-distrust 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. emsign_g3_distrust-0.2.0/LICENSE +21 -0
  2. emsign_g3_distrust-0.2.0/PKG-INFO +182 -0
  3. emsign_g3_distrust-0.2.0/README.md +155 -0
  4. emsign_g3_distrust-0.2.0/pyproject.toml +54 -0
  5. emsign_g3_distrust-0.2.0/setup.cfg +4 -0
  6. emsign_g3_distrust-0.2.0/src/emsign_g3/__init__.py +3 -0
  7. emsign_g3_distrust-0.2.0/src/emsign_g3/cli.py +79 -0
  8. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMDVTLSCAG3B.pem +21 -0
  9. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMDVTLSCAG3C.pem +21 -0
  10. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMEVTLSCAG3B.pem +21 -0
  11. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMEVTLSCAG3C.pem +21 -0
  12. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMOVCSCAG3B.pem +20 -0
  13. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMOVCSCAG3C.pem +20 -0
  14. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMOVTLSCAG3B.pem +21 -0
  15. emsign_g3_distrust-0.2.0/src/emsign_g3/data/certs/EMOVTLSCAG3C.pem +21 -0
  16. emsign_g3_distrust-0.2.0/src/emsign_g3/data/indicators.csv +12 -0
  17. emsign_g3_distrust-0.2.0/src/emsign_g3/distrust.py +202 -0
  18. emsign_g3_distrust-0.2.0/src/emsign_g3/elastic.py +71 -0
  19. emsign_g3_distrust-0.2.0/src/emsign_g3/export.py +187 -0
  20. emsign_g3_distrust-0.2.0/src/emsign_g3/indicators.py +73 -0
  21. emsign_g3_distrust-0.2.0/src/emsign_g3/paths.py +78 -0
  22. emsign_g3_distrust-0.2.0/src/emsign_g3/scan.py +248 -0
  23. emsign_g3_distrust-0.2.0/src/emsign_g3/siem_artifacts.py +58 -0
  24. emsign_g3_distrust-0.2.0/src/emsign_g3/sigma.py +114 -0
  25. emsign_g3_distrust-0.2.0/src/emsign_g3_distrust.egg-info/PKG-INFO +182 -0
  26. emsign_g3_distrust-0.2.0/src/emsign_g3_distrust.egg-info/SOURCES.txt +35 -0
  27. emsign_g3_distrust-0.2.0/src/emsign_g3_distrust.egg-info/dependency_links.txt +1 -0
  28. emsign_g3_distrust-0.2.0/src/emsign_g3_distrust.egg-info/entry_points.txt +2 -0
  29. emsign_g3_distrust-0.2.0/src/emsign_g3_distrust.egg-info/requires.txt +4 -0
  30. emsign_g3_distrust-0.2.0/src/emsign_g3_distrust.egg-info/top_level.txt +1 -0
  31. emsign_g3_distrust-0.2.0/tests/test_committed_rules.py +6 -0
  32. emsign_g3_distrust-0.2.0/tests/test_distrust_load_certs.py +24 -0
  33. emsign_g3_distrust-0.2.0/tests/test_elastic.py +14 -0
  34. emsign_g3_distrust-0.2.0/tests/test_export.py +18 -0
  35. emsign_g3_distrust-0.2.0/tests/test_indicators.py +47 -0
  36. emsign_g3_distrust-0.2.0/tests/test_scan_blob.py +14 -0
  37. emsign_g3_distrust-0.2.0/tests/test_sigma.py +22 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jacob Durham
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,182 @@
1
+ Metadata-Version: 2.4
2
+ Name: emsign-g3-distrust
3
+ Version: 0.2.0
4
+ Summary: Detect and deny compromised eMudhra/emSign G3 intermediate CAs (Mozilla Bug 2083449)
5
+ Author: jacobyoby
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/jacobyoby/emsign-g3-distrust
8
+ Project-URL: Mozilla Bug, https://bugzilla.mozilla.org/show_bug.cgi?id=2083449
9
+ Keywords: security,tls,pki,suricata,emudhra
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Security :: Cryptography
19
+ Classifier: Topic :: System :: Systems Administration
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=7; extra == "dev"
25
+ Requires-Dist: ruff>=0.4; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # Deny the compromised eMudhra / emSign G3 intermediate CAs
29
+
30
+ ![CI](https://github.com/jacobyoby/emsign-g3-distrust/actions/workflows/ci.yml/badge.svg)
31
+
32
+ In October 2026, the private keys of **eight eMudhra intermediate CA certificates**
33
+ were found to be trivially recoverable (P-384 keys generated with private scalars
34
+ below 256). They were revoked `cACompromise` on 2026-10-18 and distrusted by the
35
+ Mozilla, Chrome, Microsoft and Apple root programs — see
36
+ [Mozilla Bug 2083449](https://bugzilla.mozilla.org/show_bug.cgi?id=2083449).
37
+
38
+ Because a leaked private key cannot be un-leaked, **anyone** can mint a validly-signed
39
+ certificate for **any** domain (6 TLS keys) or **any** publisher (2 code-signing keys)
40
+ that chains to these intermediates. Such a forgery is accepted by any client that still
41
+ trusts the emSign G3 roots and has not received the distrust push — and a forged leaf
42
+ need carry no revocation pointer, so a client that only checks the *leaf's* revocation
43
+ will not catch it. This repo helps you **detect and deny** that path.
44
+
45
+ > This repository deliberately contains **no private keys** — only the public
46
+ > certificates, their fingerprints, and tooling to distrust them.
47
+
48
+ ## The eight compromised intermediates
49
+
50
+ | CA | Type | SHA-256 | Serial |
51
+ |----|------|---------|--------|
52
+ | EM DV TLS CA - G3B | TLS | `42c4accd…ba1493` | A4AEE678F23362B4C0E460B772F214 |
53
+ | EM DV TLS CA - G3C | TLS | `0164d7ce…934d19` | 588B2E3C2BB8CDA13E1A1209254321 |
54
+ | EM EV TLS CA - G3B | TLS | `e7568fe6…333838` | C7C41EFE92D825F05EAE841A4A82C1 |
55
+ | EM EV TLS CA - G3C | TLS | `432ec25f…0261f3` | 8009928A64107601AF05FA2F19F109 |
56
+ | EM OV TLS CA - G3B | TLS | `98b89662…83bc25b` | 6CADA367FB1C100088120EA202D568 |
57
+ | EM OV TLS CA - G3C | TLS | `cb6e1516…bf9c7c3f` | 296926C227A3A1526392B19482A504 |
58
+ | EM OV CS CA - G3B | Code signing | `9e39de28…b067b4` | 7818933F8F85B4619A2B35FBA83D0A |
59
+ | EM OV CS CA - G3C | Code signing | `4b2460a4…630b1` | 544B7F922C31AE220A4A922916F6E6 |
60
+
61
+ Roots: `emSign Root TLS CA - G3` (`7dd78d5f…2746ed8d`), `emSign Root CS CA - G3`
62
+ (`f2edaaff…aba34a5`). Full machine-readable list in [`indicators.csv`](indicators.csv),
63
+ PEMs in [`certs/`](certs/).
64
+
65
+ ## Install
66
+
67
+ Requires Python 3.10+ and `openssl` on PATH for distrust fingerprint checks.
68
+
69
+ ```bash
70
+ pip install -e .
71
+ emsign-g3 scan
72
+ emsign-g3 export-indicators --verify
73
+ ```
74
+
75
+ Override data paths when needed: `EMSIGN_G3_INDICATORS_CSV`, `EMSIGN_G3_CERTS_DIR`.
76
+
77
+ Legacy entry points (`python3 tools/…`) remain as thin shims and work without install.
78
+
79
+ ## Tools
80
+
81
+ - **`emsign-g3`** (CLI) — `scan`, `distrust`, `export-indicators` subcommands (see below).
82
+ - **`tools/emsign_trust_scanner.py`** — shim for `emsign-g3 scan`.
83
+ - **`tools/emsign_distrust.py`** — shim for `emsign-g3 distrust`.
84
+ - **`tools/emsign-g3-distrust.rules`** — Suricata/Snort rules that drop TLS whose leaf
85
+ is issued by any of the eight (matches `tls.cert_issuer`). Deploy inline or behind a
86
+ decrypting proxy. Verified to fire on Suricata 8.
87
+ - **`tools/suricata_livefire_test.sh`** — replays a recorded real-world handshake
88
+ (`tests/fixtures/`) through the rules and checks they fire. No root, no network.
89
+ - **`tools/record_handshake_fixture.py`** — how that fixture was recorded: a TLS 1.2
90
+ handshake with a public researcher demo host, captured without root.
91
+ - **`src/emsign_g3/`** — installable package; loads [`indicators.csv`](indicators.csv) via
92
+ `emsign_g3.indicators`.
93
+ - **`tools/export_siem_indicators.py`** — shim for `emsign-g3 export-indicators`.
94
+
95
+ ## Operator playbook
96
+
97
+ ### Network detection (Suricata)
98
+
99
+ 1. Ship `tools/emsign-g3-distrust.rules` to your Suricata sensor (inline IPS or tap IDS).
100
+ 2. For passive IDS, change rule actions from `drop` to `alert` in the rules file.
101
+ 3. Validate offline before deploy:
102
+
103
+ ```bash
104
+ tools/suricata_livefire_test.sh
105
+ ```
106
+
107
+ Expect `PASS` and sid `92083401` on the recorded DV G3B fixture. Suricata must parse
108
+ TLS (`tls_events` > 0 in the script output).
109
+
110
+ 4. Correlate production alerts on `signature` containing `Bug2083449` or sid
111
+ `92083401`–`92083408` (see [`indicators.csv`](indicators.csv) `suricata_sid` column).
112
+
113
+ ### Host hardening (trust stores)
114
+
115
+ 1. Inventory (read-only):
116
+
117
+ ```bash
118
+ emsign-g3 scan
119
+ emsign-g3 scan --json # MDM / fleet collection
120
+ ```
121
+
122
+ 2. Plan explicit distrust of the **eight intermediates** (dry-run first):
123
+
124
+ ```bash
125
+ emsign-g3 distrust
126
+ sudo emsign-g3 distrust --apply
127
+ ```
128
+
129
+ PEMs load from `certs/` by default; fingerprints are checked against `indicators.csv`.
130
+
131
+ 3. Roll back with `emsign-g3 distrust --undo` (add `--apply` to execute).
132
+
133
+ ### SIEM / SOAR indicators
134
+
135
+ - **Canonical table:** [`indicators.csv`](indicators.csv) — eight compromised intermediates,
136
+ three related trust anchors, SHA-256 fingerprints, serials, Suricata SIDs, and
137
+ `tls.cert_issuer` match strings.
138
+ - **Bulk export:**
139
+
140
+ ```bash
141
+ emsign-g3 export-indicators
142
+ emsign-g3 export-indicators --ndjson
143
+ emsign-g3 export-indicators --verify # PEMs vs CSV
144
+ emsign-g3 export-indicators --format sigma --output-dir rules/sigma/
145
+ emsign-g3 export-indicators --format elastic-kql --output-dir rules/elastic/
146
+ emsign-g3 export-indicators --check-committed-rules
147
+ ```
148
+
149
+ Committed copies live under [`rules/sigma/`](rules/sigma/) and [`rules/elastic/`](rules/elastic/)
150
+ (regenerate with [`tools/regenerate_detection_rules.sh`](tools/regenerate_detection_rules.sh)).
151
+
152
+ Use host fields (`sha256_fingerprint`) against scanner/MDM output; use network fields
153
+ (`suricata.sid`, `tls_cert_issuer_match`) against Suricata `eve.json`.
154
+
155
+ **Sigma** and **Elastic KQL** exports are starter detections mapped to Suricata EVE
156
+ (`tls.issuerdn`, `alert.signature_id`). Tune field names before production alerting.
157
+
158
+ ## Releases
159
+
160
+ Tagged releases (`v*`) build wheels, attach indicator bundles and rule tarballs, and
161
+ publish to PyPI when trusted publishing is configured. See [`RELEASE.md`](RELEASE.md).
162
+
163
+ ## Development
164
+
165
+ ```bash
166
+ pip install -e ".[dev]"
167
+ pytest
168
+ ruff check src tests
169
+ emsign-g3 export-indicators --verify
170
+ emsign-g3 export-indicators --check-committed-rules
171
+ tools/suricata_livefire_test.sh # optional; requires Suricata
172
+ ```
173
+
174
+ Keep [`indicators.csv`](indicators.csv) in sync with
175
+ [`src/emsign_g3/data/indicators.csv`](src/emsign_g3/data/indicators.csv) (enforced by tests).
176
+
177
+ ## The durable fix
178
+
179
+ Trust-store distrust reaches browsers via OneCRL / CRLSet and OS CA updates. The long
180
+ tail — non-browser TLS clients, embedded devices, Java/Node/`certifi` bundles, code
181
+ signing — updates on its own schedule. Use the scanner to find exposed clients and the
182
+ distruster/IDS rules to deny the keys until every client has dropped the roots.
@@ -0,0 +1,155 @@
1
+ # Deny the compromised eMudhra / emSign G3 intermediate CAs
2
+
3
+ ![CI](https://github.com/jacobyoby/emsign-g3-distrust/actions/workflows/ci.yml/badge.svg)
4
+
5
+ In October 2026, the private keys of **eight eMudhra intermediate CA certificates**
6
+ were found to be trivially recoverable (P-384 keys generated with private scalars
7
+ below 256). They were revoked `cACompromise` on 2026-10-18 and distrusted by the
8
+ Mozilla, Chrome, Microsoft and Apple root programs — see
9
+ [Mozilla Bug 2083449](https://bugzilla.mozilla.org/show_bug.cgi?id=2083449).
10
+
11
+ Because a leaked private key cannot be un-leaked, **anyone** can mint a validly-signed
12
+ certificate for **any** domain (6 TLS keys) or **any** publisher (2 code-signing keys)
13
+ that chains to these intermediates. Such a forgery is accepted by any client that still
14
+ trusts the emSign G3 roots and has not received the distrust push — and a forged leaf
15
+ need carry no revocation pointer, so a client that only checks the *leaf's* revocation
16
+ will not catch it. This repo helps you **detect and deny** that path.
17
+
18
+ > This repository deliberately contains **no private keys** — only the public
19
+ > certificates, their fingerprints, and tooling to distrust them.
20
+
21
+ ## The eight compromised intermediates
22
+
23
+ | CA | Type | SHA-256 | Serial |
24
+ |----|------|---------|--------|
25
+ | EM DV TLS CA - G3B | TLS | `42c4accd…ba1493` | A4AEE678F23362B4C0E460B772F214 |
26
+ | EM DV TLS CA - G3C | TLS | `0164d7ce…934d19` | 588B2E3C2BB8CDA13E1A1209254321 |
27
+ | EM EV TLS CA - G3B | TLS | `e7568fe6…333838` | C7C41EFE92D825F05EAE841A4A82C1 |
28
+ | EM EV TLS CA - G3C | TLS | `432ec25f…0261f3` | 8009928A64107601AF05FA2F19F109 |
29
+ | EM OV TLS CA - G3B | TLS | `98b89662…83bc25b` | 6CADA367FB1C100088120EA202D568 |
30
+ | EM OV TLS CA - G3C | TLS | `cb6e1516…bf9c7c3f` | 296926C227A3A1526392B19482A504 |
31
+ | EM OV CS CA - G3B | Code signing | `9e39de28…b067b4` | 7818933F8F85B4619A2B35FBA83D0A |
32
+ | EM OV CS CA - G3C | Code signing | `4b2460a4…630b1` | 544B7F922C31AE220A4A922916F6E6 |
33
+
34
+ Roots: `emSign Root TLS CA - G3` (`7dd78d5f…2746ed8d`), `emSign Root CS CA - G3`
35
+ (`f2edaaff…aba34a5`). Full machine-readable list in [`indicators.csv`](indicators.csv),
36
+ PEMs in [`certs/`](certs/).
37
+
38
+ ## Install
39
+
40
+ Requires Python 3.10+ and `openssl` on PATH for distrust fingerprint checks.
41
+
42
+ ```bash
43
+ pip install -e .
44
+ emsign-g3 scan
45
+ emsign-g3 export-indicators --verify
46
+ ```
47
+
48
+ Override data paths when needed: `EMSIGN_G3_INDICATORS_CSV`, `EMSIGN_G3_CERTS_DIR`.
49
+
50
+ Legacy entry points (`python3 tools/…`) remain as thin shims and work without install.
51
+
52
+ ## Tools
53
+
54
+ - **`emsign-g3`** (CLI) — `scan`, `distrust`, `export-indicators` subcommands (see below).
55
+ - **`tools/emsign_trust_scanner.py`** — shim for `emsign-g3 scan`.
56
+ - **`tools/emsign_distrust.py`** — shim for `emsign-g3 distrust`.
57
+ - **`tools/emsign-g3-distrust.rules`** — Suricata/Snort rules that drop TLS whose leaf
58
+ is issued by any of the eight (matches `tls.cert_issuer`). Deploy inline or behind a
59
+ decrypting proxy. Verified to fire on Suricata 8.
60
+ - **`tools/suricata_livefire_test.sh`** — replays a recorded real-world handshake
61
+ (`tests/fixtures/`) through the rules and checks they fire. No root, no network.
62
+ - **`tools/record_handshake_fixture.py`** — how that fixture was recorded: a TLS 1.2
63
+ handshake with a public researcher demo host, captured without root.
64
+ - **`src/emsign_g3/`** — installable package; loads [`indicators.csv`](indicators.csv) via
65
+ `emsign_g3.indicators`.
66
+ - **`tools/export_siem_indicators.py`** — shim for `emsign-g3 export-indicators`.
67
+
68
+ ## Operator playbook
69
+
70
+ ### Network detection (Suricata)
71
+
72
+ 1. Ship `tools/emsign-g3-distrust.rules` to your Suricata sensor (inline IPS or tap IDS).
73
+ 2. For passive IDS, change rule actions from `drop` to `alert` in the rules file.
74
+ 3. Validate offline before deploy:
75
+
76
+ ```bash
77
+ tools/suricata_livefire_test.sh
78
+ ```
79
+
80
+ Expect `PASS` and sid `92083401` on the recorded DV G3B fixture. Suricata must parse
81
+ TLS (`tls_events` > 0 in the script output).
82
+
83
+ 4. Correlate production alerts on `signature` containing `Bug2083449` or sid
84
+ `92083401`–`92083408` (see [`indicators.csv`](indicators.csv) `suricata_sid` column).
85
+
86
+ ### Host hardening (trust stores)
87
+
88
+ 1. Inventory (read-only):
89
+
90
+ ```bash
91
+ emsign-g3 scan
92
+ emsign-g3 scan --json # MDM / fleet collection
93
+ ```
94
+
95
+ 2. Plan explicit distrust of the **eight intermediates** (dry-run first):
96
+
97
+ ```bash
98
+ emsign-g3 distrust
99
+ sudo emsign-g3 distrust --apply
100
+ ```
101
+
102
+ PEMs load from `certs/` by default; fingerprints are checked against `indicators.csv`.
103
+
104
+ 3. Roll back with `emsign-g3 distrust --undo` (add `--apply` to execute).
105
+
106
+ ### SIEM / SOAR indicators
107
+
108
+ - **Canonical table:** [`indicators.csv`](indicators.csv) — eight compromised intermediates,
109
+ three related trust anchors, SHA-256 fingerprints, serials, Suricata SIDs, and
110
+ `tls.cert_issuer` match strings.
111
+ - **Bulk export:**
112
+
113
+ ```bash
114
+ emsign-g3 export-indicators
115
+ emsign-g3 export-indicators --ndjson
116
+ emsign-g3 export-indicators --verify # PEMs vs CSV
117
+ emsign-g3 export-indicators --format sigma --output-dir rules/sigma/
118
+ emsign-g3 export-indicators --format elastic-kql --output-dir rules/elastic/
119
+ emsign-g3 export-indicators --check-committed-rules
120
+ ```
121
+
122
+ Committed copies live under [`rules/sigma/`](rules/sigma/) and [`rules/elastic/`](rules/elastic/)
123
+ (regenerate with [`tools/regenerate_detection_rules.sh`](tools/regenerate_detection_rules.sh)).
124
+
125
+ Use host fields (`sha256_fingerprint`) against scanner/MDM output; use network fields
126
+ (`suricata.sid`, `tls_cert_issuer_match`) against Suricata `eve.json`.
127
+
128
+ **Sigma** and **Elastic KQL** exports are starter detections mapped to Suricata EVE
129
+ (`tls.issuerdn`, `alert.signature_id`). Tune field names before production alerting.
130
+
131
+ ## Releases
132
+
133
+ Tagged releases (`v*`) build wheels, attach indicator bundles and rule tarballs, and
134
+ publish to PyPI when trusted publishing is configured. See [`RELEASE.md`](RELEASE.md).
135
+
136
+ ## Development
137
+
138
+ ```bash
139
+ pip install -e ".[dev]"
140
+ pytest
141
+ ruff check src tests
142
+ emsign-g3 export-indicators --verify
143
+ emsign-g3 export-indicators --check-committed-rules
144
+ tools/suricata_livefire_test.sh # optional; requires Suricata
145
+ ```
146
+
147
+ Keep [`indicators.csv`](indicators.csv) in sync with
148
+ [`src/emsign_g3/data/indicators.csv`](src/emsign_g3/data/indicators.csv) (enforced by tests).
149
+
150
+ ## The durable fix
151
+
152
+ Trust-store distrust reaches browsers via OneCRL / CRLSet and OS CA updates. The long
153
+ tail — non-browser TLS clients, embedded devices, Java/Node/`certifi` bundles, code
154
+ signing — updates on its own schedule. Use the scanner to find exposed clients and the
155
+ distruster/IDS rules to deny the keys until every client has dropped the roots.
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "emsign-g3-distrust"
7
+ version = "0.2.0"
8
+ description = "Detect and deny compromised eMudhra/emSign G3 intermediate CAs (Mozilla Bug 2083449)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "jacobyoby" }]
13
+ keywords = ["security", "tls", "pki", "suricata", "emudhra"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Environment :: Console",
17
+ "Intended Audience :: System Administrators",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Security :: Cryptography",
24
+ "Topic :: System :: Systems Administration",
25
+ ]
26
+ dependencies = []
27
+
28
+ [project.optional-dependencies]
29
+ dev = ["pytest>=7", "ruff>=0.4"]
30
+
31
+ [project.scripts]
32
+ emsign-g3 = "emsign_g3.cli:main"
33
+
34
+ [project.urls]
35
+ Repository = "https://github.com/jacobyoby/emsign-g3-distrust"
36
+ "Mozilla Bug" = "https://bugzilla.mozilla.org/show_bug.cgi?id=2083449"
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+
41
+ [tool.setuptools.package-data]
42
+ emsign_g3 = ["data/indicators.csv", "data/certs/*.pem"]
43
+
44
+ [tool.pytest.ini_options]
45
+ testpaths = ["tests"]
46
+ pythonpath = ["src"]
47
+
48
+ [tool.ruff]
49
+ target-version = "py310"
50
+ line-length = 100
51
+ src = ["src", "tests"]
52
+
53
+ [tool.ruff.lint]
54
+ select = ["E", "F", "I", "UP"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Defensive tooling for eMudhra/emSign G3 CA distrust (Mozilla Bug 2083449)."""
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,79 @@
1
+ """Unified CLI for emsign-g3 distrust tooling."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+
6
+ from emsign_g3.distrust import run_distrust
7
+ from emsign_g3.export import run_export
8
+ from emsign_g3.paths import default_certs_dir, indicators_csv_path
9
+ from emsign_g3.scan import run_scan
10
+
11
+
12
+ def main(argv: list[str] | None = None) -> int:
13
+ parser = argparse.ArgumentParser(
14
+ prog="emsign-g3",
15
+ description="Detect and deny compromised eMudhra/emSign G3 intermediates (Bug 2083449).",
16
+ )
17
+ sub = parser.add_subparsers(dest="command", required=True)
18
+
19
+ scan_p = sub.add_parser("scan", help="inventory trust stores (read-only)")
20
+ scan_p.add_argument("--json", action="store_true", help="machine-readable output")
21
+
22
+ dist_p = sub.add_parser("distrust", help="plan or apply intermediate blocklist")
23
+ dist_p.add_argument("--apply", action="store_true", help="execute (default: dry run)")
24
+ dist_p.add_argument("--undo", action="store_true", help="roll back instead of distrust")
25
+ dist_p.add_argument(
26
+ "--certs-dir",
27
+ default=None,
28
+ help=f"directory with eight verified PEMs (default: {default_certs_dir()})",
29
+ )
30
+
31
+ exp_p = sub.add_parser("export-indicators", help="SIEM/SOAR indicator bundle")
32
+ exp_p.add_argument("--csv", default=None, help="path to indicators.csv")
33
+ exp_p.add_argument(
34
+ "--format",
35
+ choices=("json", "ndjson", "sigma", "elastic-kql"),
36
+ default="json",
37
+ help="output format (default: json)",
38
+ )
39
+ exp_p.add_argument(
40
+ "--ndjson",
41
+ action="store_true",
42
+ help="shorthand for --format ndjson (deprecated)",
43
+ )
44
+ exp_p.add_argument("--verify", action="store_true", help="verify PEMs match CSV")
45
+ exp_p.add_argument("--certs-dir", default=None, help="PEM directory for --verify")
46
+ exp_p.add_argument(
47
+ "--output-dir",
48
+ default=None,
49
+ help="write --format sigma or elastic-kql files to this directory",
50
+ )
51
+ exp_p.add_argument(
52
+ "--check-committed-rules",
53
+ action="store_true",
54
+ help="verify rules/sigma and rules/elastic match generators",
55
+ )
56
+
57
+ args = parser.parse_args(argv)
58
+
59
+ if args.command == "scan":
60
+ return run_scan(as_json=args.json)
61
+ if args.command == "distrust":
62
+ return run_distrust(apply=args.apply, undo=args.undo, certs_dir=args.certs_dir)
63
+ if args.command == "export-indicators":
64
+ return run_export(
65
+ csv_path=args.csv or indicators_csv_path(),
66
+ fmt=args.format,
67
+ ndjson=args.ndjson,
68
+ verify=args.verify,
69
+ certs_dir=args.certs_dir,
70
+ output_dir=args.output_dir,
71
+ check_committed_rules=args.check_committed_rules,
72
+ )
73
+
74
+ parser.error(f"unknown command: {args.command}")
75
+ return 2
76
+
77
+
78
+ if __name__ == "__main__":
79
+ raise SystemExit(main())
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDaDCCAu6gAwIBAgIQAKSu5njyM2K0wORgt3LyFDAKBggqhkjOPQQDAzBWMQsw
3
+ CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
4
+ ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTU1
5
+ NDA4WhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11
6
+ ZGhyYSBCVjEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C
7
+ AQYFK4EEACIDYgAE557ZwEqXc8RzXlERHahawr1eZKs3S4DhLLwgOOweTw47gS/J
8
+ hZ4eZ6+wTi+LyX90hbplqpEe6KTkW2LVzAPVa+Z4s8OMtNyTfKJGDiOEU8iSk10p
9
+ 1E+R4VYGtjzO2rRoo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
10
+ WUIgkFQwHQYDVR0OBBYEFOIeL+ccGTkOVUtiwSAkVzUkiiUUMB0GA1UdJQQWMBQG
11
+ CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
12
+ KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
13
+ BAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
14
+ aHR0cDovL29jc3AtYi5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
15
+ b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQi5wN2MwNwYDVR0f
16
+ BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
17
+ cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
18
+ AwMDaAAwZQIwLmsGXi6oFMJ2klkcEMXMug6gvxQWZWkewiDWVzQyl2L6z6DuQfPO
19
+ Ibh1grvdULDCAjEAxZvLlxUavG69J6wnSjC8XBbqNIQsJ6CE2QdNOe84Ptxb6VG8
20
+ gt2TlfJbHii+KNvK
21
+ -----END CERTIFICATE-----
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDaDCCAu6gAwIBAgIPWIsuPCu4zaE+GhIJJUMhMAoGCCqGSM49BAMDMFYxCzAJ
3
+ BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
4
+ MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNTM1
5
+ MDlaFw00MDA0MjgxODMwMDBaMEAxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtlTXVk
6
+ aHJhIEluYzEbMBkGA1UEAwwSRU0gRFYgVExTIENBIC0gRzNDMHYwEAYHKoZIzj0C
7
+ AQYFK4EEACIDYgAEOnp4YsjETTJN3WkDOmeCwO/u/kBV5ooSP6A3G6O9kZRRTuFy
8
+ pDPjYw8CvRiAN9nlFJ+bd9uUooHfmHsv6oiLdL3+j9pMEJnubKGVZv4+8OX2sJpV
9
+ bMyLpQVh3xsqRB0Bo4IBljCCAZIwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
10
+ WUIgkFQwHQYDVR0OBBYEFK5+EFw8KZbBqEcnBVnx4D3U5QrzMB0GA1UdJQQWMBQG
11
+ CCsGAQUFBwMBBggrBgEFBQcDAjBdBgNVHSAEVjBUMDkGCysGAQQBg44hAQABMCow
12
+ KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
13
+ BAGDjiEBAmQwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
14
+ aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
15
+ b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRFZUTFNDQUczQy5wN2MwNwYDVR0f
16
+ BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
17
+ cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
18
+ AwMDaAAwZQIxAMEN2HWMocbuWdy1d33pH6JpMvP/V/DIS5PtZbv1Q7TXEbxrcyxg
19
+ yuddOJscYDJJlAIwB4sH1BpbScDzkdD4tJBSwrG/1Mx82vb8YaySehNuu1+1oXNd
20
+ AEKwaJ0mVzScy2+6
21
+ -----END CERTIFICATE-----
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDaDCCAu2gAwIBAgIQAMfEHv6S2CXwXq6EGkqCwTAKBggqhkjOPQQDAzBWMQsw
3
+ CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
4
+ ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTYw
5
+ MzMxWhcNNDAwNDI4MTgzMDAwWjA/MQswCQYDVQQGEwJOTDETMBEGA1UECgwKZU11
6
+ ZGhyYSBCVjEbMBkGA1UEAwwSRU0gRVYgVExTIENBIC0gRzNCMHYwEAYHKoZIzj0C
7
+ AQYFK4EEACIDYgAEJduoWmTTl9oLEFLp6lRuSHvv6pydnWigxerc/u91ppu11vwB
8
+ 9Cv7ym60C81kwHZ+Nv/QXZeoE8WqDGyVMOec9fCGZGjxOAZCCqXIUYQLHiUlQOeQ
9
+ 5LZUw4Uu1krx6GV9o4IBlTCCAZEwHwYDVR0jBBgwFoAU4TqrIXzx401UrtRyt/2L
10
+ WUIgkFQwHQYDVR0OBBYEFD7cINmJRpiHe4c/2IFHslwV2EcGMB0GA1UdJQQWMBQG
11
+ CCsGAQUFBwMBBggrBgEFBQcDAjBcBgNVHSAEVTBTMDkGCysGAQQBg44hAQABMCow
12
+ KAYIKwYBBQUHAgEWHGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDQYLKwYB
13
+ BAGDjiEBAngwBwYFZ4EMAQEwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho
14
+ dHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv
15
+ c2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1FVlRMU0NBRzNCLnA3YzA3BgNVHR8E
16
+ MDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy
17
+ bDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD
18
+ AwNpADBmAjEA9Jq999oaOUKhFwopw33iCmt0OHIn3gjT43GfuOHR/YckXdwoNdDA
19
+ lIEhz0NgRO3/AjEAvY/a3OMvktIZLYjn+WLKmp0QhrIMV+e6EpS7j4GVeOKouNp6
20
+ MN/P+ByGeiRMghzB
21
+ -----END CERTIFICATE-----
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDaDCCAu6gAwIBAgIQAIAJkopkEHYBrwX6LxnxCTAKBggqhkjOPQQDAzBWMQsw
3
+ CQYDVQQGEwJJTjElMCMGA1UECgwcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
4
+ ZDEgMB4GA1UEAwwXZW1TaWduIFJvb3QgVExTIENBIC0gRzMwHhcNMjUwNDMwMTUz
5
+ OTMxWhcNNDAwNDI4MTgzMDAwWjBAMQswCQYDVQQGEwJVUzEUMBIGA1UECgwLZU11
6
+ ZGhyYSBJbmMxGzAZBgNVBAMMEkVNIEVWIFRMUyBDQSAtIEczQzB2MBAGByqGSM49
7
+ AgEGBSuBBAAiA2IABC1W6Cmm+4LGSkaX2WCvlR6QZ66R+SbTQwbaSKiq63hptqZ+
8
+ bSdCbgRCqgOzbhmI3/Y2UU7hzwf1uks/8qBmRa59MdWGatMao9JG6wsxd+6Zy3Vm
9
+ xRbOdICKZo+R8MR/yqOCAZUwggGRMB8GA1UdIwQYMBaAFOE6qyF88eNNVK7Ucrf9
10
+ i1lCIJBUMB0GA1UdDgQWBBSmJV6AqU2385Z8G8eR35K87kvrXzAdBgNVHSUEFjAU
11
+ BggrBgEFBQcDAQYIKwYBBQUHAwIwXAYDVR0gBFUwUzA5BgsrBgEEAYOOIQEAATAq
12
+ MCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMA0GCysG
13
+ AQQBg44hAQJ4MAcGBWeBDAEBMHUGCCsGAQUFBwEBBGkwZzAkBggrBgEFBQcwAYYY
14
+ aHR0cDovL29jc3AtYy5lbXNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw
15
+ b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL0VNRVZUTFNDQUczQy5wN2MwNwYDVR0f
16
+ BDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290dGxzY2FnMy5j
17
+ cmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwCgYIKoZIzj0E
18
+ AwMDaAAwZQIwBy1wTnzH4lXDTy2PD91ysLjvnlVN3JbJmc1BIMEU8TOLkYVHibMc
19
+ 9HeyonikFSfmAjEA6uE3QRxlrZTz/1/lXPTEMUhoauAtycagtlNFp79kjhvNa2/f
20
+ Aal1GNxsOutLnr0Y
21
+ -----END CERTIFICATE-----
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDWzCCAuCgAwIBAgIPeBiTP4+FtGGaKzX7qD0KMAoGCCqGSM49BAMDMFUxCzAJ
3
+ BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
4
+ MR8wHQYDVQQDDBZlbVNpZ24gUm9vdCBDUyBDQSAtIEczMB4XDTI1MDQzMDE2MDgy
5
+ N1oXDTQwMDQyODE4MzAwMFowPjELMAkGA1UEBhMCTkwxEzARBgNVBAoMCmVNdWRo
6
+ cmEgQlYxGjAYBgNVBAMMEUVNIE9WIENTIENBIC0gRzNCMHYwEAYHKoZIzj0CAQYF
7
+ K4EEACIDYgAEqrsPsGZqz88B+tUr/P1MK/LLPDSX3nOVDlgZth/mlQmHQcjEkUOb
8
+ NKBDHK/+W/m0wcjorgAB+fTcitgsWfNjnpbNbD1NsM7+wmw9YlF7N3YTcnQ/jord
9
+ d7EAZPKr5eBQo4IBizCCAYcwHwYDVR0jBBgwFoAUaHQD+IXKjVRQVx0W4MjeRQ2r
10
+ zS0wHQYDVR0OBBYEFHn66OzP2w11jaRY1p+27dx8Sd7mMBMGA1UdJQQMMAoGCCsG
11
+ AQUFBwMDMF4GA1UdIARXMFUwOQYLKwYBBAGDjiEBAAEwKjAoBggrBgEFBQcCARYc
12
+ aHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTAOBgwrBgEEAYOOIQECgUgwCAYG
13
+ Z4EMAQQBMHQGCCsGAQUFBwEBBGgwZjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3At
14
+ Yi5lbXNpZ24uY29tMD4GCCsGAQUFBzAChjJodHRwOi8vcmVwb3NpdG9yeS5lbXNp
15
+ Z24uY29tL2NlcnRzL0VNT1ZDU0NBRzNCLnA3YzA2BgNVHR8ELzAtMCugKaAnhiVo
16
+ dHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3Rjc2NhZzMuY3JsMA4GA1UdDwEB/wQE
17
+ AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMAoGCCqGSM49BAMDA2kAMGYCMQC/zr03
18
+ YEELsNKqzUtH2dVFi4BaKFdyrr/6G1dIWp8KAVgsw2/u4lyyboUDaC9jDvICMQC9
19
+ HTxku84tNX9dmHOtH7aC2Nu/JM0jTf6KjZAvovCJzzv1IFWSZpVLZibynMLXOrM=
20
+ -----END CERTIFICATE-----
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDWzCCAuGgAwIBAgIPVEt/kiwxriIKSpIpFvbmMAoGCCqGSM49BAMDMFUxCzAJ
3
+ BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
4
+ MR8wHQYDVQQDDBZlbVNpZ24gUm9vdCBDUyBDQSAtIEczMB4XDTI1MDQzMDE2Mzg0
5
+ MFoXDTQwMDQyODE4MzAwMFowPzELMAkGA1UEBhMCVVMxFDASBgNVBAoMC2VNdWRo
6
+ cmEgSW5jMRowGAYDVQQDDBFFTSBPViBDUyBDQSAtIEczQzB2MBAGByqGSM49AgEG
7
+ BSuBBAAiA2IABLnw4GNHAqacpqrdRDz9YsQbm6SyCSRpfXl052kaEm+5avs+NML9
8
+ O8X0gwYfJl3CpYQ2NHMjUQQ2so8E84YjYwZ5gOJQPgJTLWVGI1pxZaJZoe9Jb3Qb
9
+ X97neHII5Lj676OCAYswggGHMB8GA1UdIwQYMBaAFGh0A/iFyo1UUFcdFuDI3kUN
10
+ q80tMB0GA1UdDgQWBBTub3MpjW+/p7Mbw5U09hVWRHhmtzATBgNVHSUEDDAKBggr
11
+ BgEFBQcDAzBeBgNVHSAEVzBVMDkGCysGAQQBg44hAQABMCowKAYIKwYBBQUHAgEW
12
+ HGh0dHA6Ly9yZXBvc2l0b3J5LmVtc2lnbi5jb20wDgYMKwYBBAGDjiEBAoFIMAgG
13
+ BmeBDAEEATB0BggrBgEFBQcBAQRoMGYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw
14
+ LWMuZW1zaWduLmNvbTA+BggrBgEFBQcwAoYyaHR0cDovL3JlcG9zaXRvcnkuZW1z
15
+ aWduLmNvbS9jZXJ0cy9FTU9WQ1NDQUczQy5wN2MwNgYDVR0fBC8wLTAroCmgJ4Yl
16
+ aHR0cDovL2NybC5lbXNpZ24uY29tLz9yb290Y3NjYWczLmNybDAOBgNVHQ8BAf8E
17
+ BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQDAwNoADBlAjEA8yPg
18
+ 8sntOhLwV2QXJ5LEaKSpo/fnE3uOgTadK73fDhyjiqr0Io9GVuQTYqBPbQ2TAjBg
19
+ euApmBS486+iei03lRrp139dPw6k28jjGNvWsAU7A1N86J1zPJVDEyVH+nMAWC0=
20
+ -----END CERTIFICATE-----
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDZjCCAu2gAwIBAgIPbK2jZ/scEACIEg6iAtVoMAoGCCqGSM49BAMDMFYxCzAJ
3
+ BgNVBAYTAklOMSUwIwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVk
4
+ MSAwHgYDVQQDDBdlbVNpZ24gUm9vdCBUTFMgQ0EgLSBHMzAeFw0yNTA0MzAxNjAw
5
+ MTJaFw00MDA0MjgxODMwMDBaMD8xCzAJBgNVBAYTAk5MMRMwEQYDVQQKDAplTXVk
6
+ aHJhIEJWMRswGQYDVQQDDBJFTSBPViBUTFMgQ0EgLSBHM0IwdjAQBgcqhkjOPQIB
7
+ BgUrgQQAIgNiAARziXqg6zz9yosSQC/68KvE4SErr43ud4rJ7i1tuD+sKAxeBWOK
8
+ 56Ks1xwyKo42HN659pxDArndjXPRzGyqsswK7k4hbOl53VGKSvS2JuVoTN1lgDft
9
+ DIVOTMEvTPhkbQ2jggGWMIIBkjAfBgNVHSMEGDAWgBThOqshfPHjTVSu1HK3/YtZ
10
+ QiCQVDAdBgNVHQ4EFgQUm9hlUa/n5yw3rQjuaRnZvzeErgowHQYDVR0lBBYwFAYI
11
+ KwYBBQUHAwEGCCsGAQUFBwMCMF0GA1UdIARWMFQwOQYLKwYBBAGDjiEBAAEwKjAo
12
+ BggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTANBgsrBgEE
13
+ AYOOIQECbjAIBgZngQwBAgIwdQYIKwYBBQUHAQEEaTBnMCQGCCsGAQUFBzABhhho
14
+ dHRwOi8vb2NzcC1iLmVtc2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv
15
+ c2l0b3J5LmVtc2lnbi5jb20vY2VydHMvRU1PVlRMU0NBRzNCLnA3YzA3BgNVHR8E
16
+ MDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2lnbi5jb20vP3Jvb3R0bHNjYWczLmNy
17
+ bDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAKBggqhkjOPQQD
18
+ AwNnADBkAjBAk+5BizdJhrED3wb7F2Gm7bWI60dlNd075nghT2TrR4NWKZtJZcbc
19
+ 28xxIY/NONICMF6mPdsjosaqmvEMWqKcBh4vsIvXSKnQj5o8zrFB4oKS+accjYTe
20
+ 8Dz3bQjauvy9uw==
21
+ -----END CERTIFICATE-----