mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-25 18:40:06 -04:00
Distrust compromised eMudhra intermediates in certifi and Deno (#854)
* Distrust compromised eMudhra intermediates in certifi and Deno The private keys of eight eMudhra intermediate CAs can be recovered from their certificates, so anyone can mint a trusted certificate for any host. * Require certifi>=2026.10.19; yt-dlp, requests and curl-cffi use its bundle, and 2026.10.19 removes the emSign ECC Root CA - G3 root they chain to. * Set DENO_TLS_CA_STORE=system for the API (systemd + Docker) and the archive container so Deno follows the apt-patched system store instead of roots that only change with a Deno upgrade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep Deno's bundled roots in the archive container browserless/chrome:1.61.1 is Ubuntu 22.04 whose newest ca-certificates is from 2023, older than Deno 2.8.3's bundled roots. The system store only becomes the better choice once the archive base image is upgraded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
cbf69e3013
commit
9ccf19b82b
5 changed files with 41 additions and 0 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
FROM python:3.13-trixie
|
FROM python:3.13-trixie
|
||||||
ENV DOCKER=true
|
ENV DOCKER=true
|
||||||
|
# Deno trusts the system store, which apt keeps current, instead of its bundled roots.
|
||||||
|
ENV DENO_TLS_CA_STORE=system
|
||||||
WORKDIR /opt/wrolpi
|
WORKDIR /opt/wrolpi
|
||||||
|
|
||||||
# Update dependencies for the services install.
|
# Update dependencies for the services install.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ Conflicts=wrolpi-api.service
|
||||||
Environment=PYTHONUNBUFFERED=1
|
Environment=PYTHONUNBUFFERED=1
|
||||||
# Sanic 25.x wants 'spawn' but our code uses 'fork' for multiprocessing.
|
# Sanic 25.x wants 'spawn' but our code uses 'fork' for multiprocessing.
|
||||||
Environment=SANIC_START_METHOD_SET=1
|
Environment=SANIC_START_METHOD_SET=1
|
||||||
|
# Deno (single-file, yt-dlp EJS) trusts the system store, which apt keeps current, instead of its
|
||||||
|
# bundled roots.
|
||||||
|
Environment=DENO_TLS_CA_STORE=system
|
||||||
# Required for yt-dlp to access GNOME keyring for browser cookie decryption.
|
# Required for yt-dlp to access GNOME keyring for browser cookie decryption.
|
||||||
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus
|
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus
|
||||||
ExecStart=/opt/wrolpi/venv/bin/python -m sanic main:api_app --host 0.0.0.0 --port 8081 -w 2 --reload --debug
|
ExecStart=/opt/wrolpi/venv/bin/python -m sanic main:api_app --host 0.0.0.0 --port 8081 -w 2 --reload --debug
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ Conflicts=wrolpi-api-dev.service
|
||||||
Environment=PYTHONUNBUFFERED=1
|
Environment=PYTHONUNBUFFERED=1
|
||||||
# Sanic 25.x wants 'spawn' but our code uses 'fork' for multiprocessing.
|
# Sanic 25.x wants 'spawn' but our code uses 'fork' for multiprocessing.
|
||||||
Environment=SANIC_START_METHOD_SET=1
|
Environment=SANIC_START_METHOD_SET=1
|
||||||
|
# Deno (single-file, yt-dlp EJS) trusts the system store, which apt keeps current, instead of its
|
||||||
|
# bundled roots.
|
||||||
|
Environment=DENO_TLS_CA_STORE=system
|
||||||
# Required for yt-dlp to access GNOME keyring for browser cookie decryption.
|
# Required for yt-dlp to access GNOME keyring for browser cookie decryption.
|
||||||
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus
|
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus
|
||||||
ExecStart=/opt/wrolpi/venv/bin/python -O -m sanic main:api_app --host 0.0.0.0 --port 8081 -w 5
|
ExecStart=/opt/wrolpi/venv/bin/python -O -m sanic main:api_app --host 0.0.0.0 --port 8081 -w 5
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ aiohttp==3.14.4
|
||||||
alembic==1.20.0
|
alembic==1.20.0
|
||||||
beautifulsoup4==4.15.0
|
beautifulsoup4==4.15.0
|
||||||
cachetools==7.2.1
|
cachetools==7.2.1
|
||||||
|
# yt-dlp, requests and curl-cffi trust certifi's bundle, not the system store. 2026.10.19 removes
|
||||||
|
# the root of the eMudhra intermediates whose private keys are recoverable.
|
||||||
|
certifi>=2026.10.19
|
||||||
cryptography==50.0.2
|
cryptography==50.0.2
|
||||||
ebooklib==0.20
|
ebooklib==0.20
|
||||||
feedparser==6.0.14
|
feedparser==6.0.14
|
||||||
|
|
|
||||||
30
wrolpi/test/test_trust_store.py
Normal file
30
wrolpi/test/test_trust_store.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""
|
||||||
|
Tests that WROLPi's TLS clients do not trust compromised certificate authorities.
|
||||||
|
"""
|
||||||
|
import certifi
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from wrolpi.vars import PROJECT_DIR
|
||||||
|
|
||||||
|
# Roots of the eMudhra intermediates whose private keys can be recovered from their certificates.
|
||||||
|
DISTRUSTED_ROOT_LABELS = (
|
||||||
|
'emSign ECC Root CA - G3',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('label', DISTRUSTED_ROOT_LABELS)
|
||||||
|
def test_certifi_distrusts_root(label):
|
||||||
|
"""certifi's bundle (used by yt-dlp, requests and curl-cffi) must not contain a distrusted root."""
|
||||||
|
labels = [line.split('"')[1] for line in certifi.contents().splitlines() if line.startswith('# Label: "')]
|
||||||
|
assert labels, 'certifi bundle has no labels; cannot verify distrusted roots are absent'
|
||||||
|
assert label not in labels
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('path,setting', [
|
||||||
|
('etc/raspberrypios/wrolpi-api.service', 'Environment=DENO_TLS_CA_STORE=system'),
|
||||||
|
('etc/raspberrypios/wrolpi-api-dev.service', 'Environment=DENO_TLS_CA_STORE=system'),
|
||||||
|
('docker/api/Dockerfile', 'ENV DENO_TLS_CA_STORE=system'),
|
||||||
|
])
|
||||||
|
def test_deno_uses_system_trust_store(path, setting):
|
||||||
|
"""Deno's bundled roots only change with a Deno upgrade; the system store is patched by apt."""
|
||||||
|
assert setting in (PROJECT_DIR / path).read_text().splitlines()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue