Trust the Russian Trusted Root CA system-wide on macOS, but only for .ru and .рф names.
Russian government sites such as реестрповесток.рф use certificates chaining to the
Russian Trusted Root CA (Ministry of Digital Development). Browsers do not ship that root,
so they fail with NET::ERR_CERT_AUTHORITY_INVALID.
Importing the root as-is would let it vouch for any domain, and macOS keychain trust settings cannot restrict a root to a domain suffix.
The Russian root is re-parented under a locally generated, name-constrained CA:
Local RU-only Trust Anchor trusted; nameConstraints; key destroyed
└─ Local RU-only Constrained CA nameConstraints ru, xn--p1ai; EKU serverAuth; key destroyed
└─ Russian Trusted Root CA cross-certificate: same subject, public key and SKI as the original
└─ Russian Trusted Sub CA sent by the server
└─ site certificate
Only the local anchor is trusted. When a server's chain reaches the Russian root, the verifier
takes the cross-certificate path, and RFC 5280 name constraints on the local CAs apply to every
certificate below them. Names outside ru / xn--p1ai and all IP-address SANs are rejected.
Both local private keys are deleted as soon as the certificates are signed, so nothing else can ever be issued under the anchor.
| File | Role |
|---|---|
Makefile |
Downloads the Russian certificates, builds, verifies, installs |
make-anchor.sh |
Builds the three local certificates from a foreign root |
The repo holds no certificates. make build writes them all to build/:
| File | Role |
|---|---|
build/russian-root-ca.pem |
Downloaded Russian root; input only, never trust it |
build/russian-sub-ca.pem |
Downloaded Russian sub CA; used only to test the build |
build/local-anchor-root.pem |
Local root; the only certificate to mark as trusted |
build/local-constrained-ca.pem |
Constrained intermediate; install without trust |
build/russian-root-cross.pem |
Cross-certificate of the Russian root; install without trust |
Requires Homebrew OpenSSL 3 (brew install openssl@3).
make buildIt first runs make download, which fetches the root from Gosuslugi (gu-st.ru) over HTTPS, and the
sub CA from the Ministry's distribution point (nuc-cdp.digital.gov.ru, HTTP only). A new anchor is
built only when the downloaded root differs from the one in build/.
The sub CA is only a test input. At the end, the build checks with an explicit anchor and no keychain that the sub CA chains to the local anchor through the cross-certificate, with both OpenSSL and the macOS verifier.
The download prints the root's SHA-256 fingerprint. Check it before installing. The known value is
D2:6D:2D:02:31:B7:C3:9F:92:CC:73:85:12:BA:54:10:35:19:E4:40:5D:68:B5:BD:70:3E:97:88:CA:8E:CF:31.
sudo make installIt first runs make uninstall, so an anchor from an earlier build does not stay trusted. Only build/local-anchor-root.pem is marked as trusted; the other two are added without
trust. Then open https://реестрповесток.рф to check.
sudo make uninstallIt finds the installed certificates in the System keychain by their local issuer, so it does not
need build/. When nothing is installed, it does nothing.
- Applications with their own root store (Firefox, some CLI tools with bundled CA files) ignore the macOS keychain and stay untrusted.
- New sub CAs under the same Russian root work without changes. A new Russian root key needs a rebuild, and so does the cross-certificate's expiry, which is capped at the Russian root's own expiry.
- The permitted zones are set in
make-anchor.sh([nc]section). Changing them needs a rebuild and reinstall, since the old keys no longer exist.