Zelfondertekend certificaat maken op Ubuntu 24.04
Maak een zelfondertekend TLS-certificaat dat Chrome accepteert op Ubuntu 24.04. Gebruik de juiste OpenSSL SAN-configuratie en vertrouw het certificaat zonder curl -k te gebruiken.
Wat u bouwt
Een zelfondertekend TLS-certificaat dat moderne browsers en clients daadwerkelijk accepteren, correcte subjectAltName, veilige rechten op sleutelbestanden, gekoppeld aan Nginx of Apache, plus het onderdeel dat bijna elke handleiding overslaat: zorgen dat uw clients het certificaat correct vertrouwen, in plaats van telkens op waarschuwingen te klikken en curl -k hard te coderen in scripts. Aan het einde vindt u een private CA met vijf commando's voor wanneer één interne service er zes worden.
Eerst de afweging, want een zelfondertekend certificaat is minder vaak het juiste gereedschap dan men denkt. Als de service bereikbaar is vanaf het publieke internet onder een echte DNS-naam, stop dan met lezen en haal in plaats daarvan een gratis Let's Encrypt-certificaat met certbot op Nginx of het Apache-equivalent. Dit kost niets, vernieuwt zichzelf en wordt door gangbare browsers en besturingssystemen al vertrouwd. Een zelfondertekend certificaat op een publieke site traint uw gebruikers om door beveiligingswaarschuwingen heen te klikken, wat een slechtere gewoonte is dan onversleuteld HTTP.
Zelfondertekend is het juiste gereedschap wanneer er geen publiek internet in het spel is: een beheerpaneel gekoppeld aan een WireGuard-tunneladres op uw VPS, een staging-omgeving op een privaat netwerk, verkeer tussen backends, een home-lab-apparaat, of als vervanging voor het tijdelijke certificaat dat Webmin zelf genereert op poort 10000. Let's Encrypt kan sowieso geen certificaten uitgeven voor 10.8.0.1 of git.internal.lan; geen enkele publieke CA plaatst een privaat IP-adres of een verzonnen TLD in een certificaat. Voor die namen bent u zelf de CA.
Alles hieronder draait op een verse Ubuntu 24.04-server, die OpenSSL 3.0.x bevat (gebruik openssl version om dit te bevestigen). Niets hiervan vereist internettoegang; het werkt volledig in een air-gapped omgeving.
Waarom de oude one-liner certificaten genereert die Chrome weigert
De opdracht die u in elke handleiding van vóór 2017 tegenkomt, ziet er als volgt uit:
# Do not run this: shown so you recognise it in old guides
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout selfsigned.key -out selfsigned.crtDeze opdracht stelt een reeks interactieve vragen, plaatst uw hostnaam in het veld Common Name en genereert een certificaat zonder subjectAltName-extensie. Dat certificaat is bij aankomst al ongeldig. Chrome is in versie 58, in april 2017, gestopt met het uitlezen van de Common Name. RFC 2818 had het matchen op CN al in het jaar 2000 als verouderd gemarkeerd, en Firefox en Safari gedragen zich op dezelfde manier. curl en de ssl-module van Python vallen nog wel terug op de Common Name wanneer een certificaat helemaal geen SAN bevat. Dit is de reden waarom een certificaat zonder SAN een snelle curl-test kan doorstaan, maar toch in elke browser faalt. Voor een browser identificeert een certificaat zijn server via de SAN-extensie of helemaal niet, en de browser meldt dit in exact deze bewoordingen:
NET::ERR_CERT_COMMON_NAME_INVALID
This server could not prove that it is git.internal.lan; its security
certificate does not specify Subject Alternative Names.Geen enkele aanpassing in de trust-store lost deze fout op, omdat het certificaat simpelweg niets benoemt. Als u op dit moment naar NET::ERR_CERT_COMMON_NAME_INVALID kijkt, bevat uw certificaat geen SAN (of een onjuiste) en moet u een nieuw certificaat aanmaken. Gelukkig is de oplossing slechts één opdracht.
Een certificaat genereren dat browsers accepteren: één commando
OpenSSL introduceerde de -addext-vlag in versie 1.1.1. Hierdoor zijn de complexe configuratiebestanden die in oude handleidingen werden gebruikt om een SAN toe te voegen niet langer nodig. Op Ubuntu 24.04:
sudo openssl req -x509 -newkey rsa:4096 -sha256 -days 730 -noenc \
-keyout /etc/ssl/private/git.internal.key \
-out /etc/ssl/certs/git.internal.crt \
-subj "/CN=git.internal.lan" \
-addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"Wat elke vlag doet:
-x509genereert direct een zelfondertekend certificaat in plaats van een ondertekeningsverzoek (CSR).-newkey rsa:4096genereert in dezelfde stap een nieuwe sleutel. RSA 4096 is compatibel met alle legacy-clients; als alle clients modern zijn, is-newkey ec -pkeyopt ec_paramgen_curve:P-256kleiner en sneller.-noencis de schrijfwijze in OpenSSL 3.x voor de oude-nodes: geen wachtwoordzin op de sleutel. Beide schrijfwijzen werken. Een sleutel met een wachtwoordzin zorgt ervoor dat Nginx bij elke herstart blijft wachten op invoer; voor een serversleutel wilt u dit dus niet.-days 730, twee jaar; meer informatie over dit getal vindt u in de sectie over verloopdata.-subjbeantwoordt de interactieve vragen direct. De CN is tegenwoordig cosmetisch, maar stel deze toch in op de primaire naam; sommige tools tonen deze namelijk.-addext "subjectAltName=..."is de belangrijkste vlag. Vermeld elke naam en elk IP-adres dat clients zullen gebruiken:DNS:-vermeldingen voor hostnamen (wildcards zoalsDNS:*.internal.lanzijn toegestaan),IP:-vermeldingen voor adressen. Als iemand naarhttps://10.8.0.1navigeert, moet deIP:10.8.0.1-vermelding aanwezig zijn; een SAN met alleen DNS levert anders opnieuwNET::ERR_CERT_COMMON_NAME_INVALIDop.
Controleer of de SAN daadwerkelijk is toegevoegd voordat u verdergaat:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -ext subjectAltNameCorrecte uitvoer:
X509v3 Subject Alternative Name:
DNS:git.internal.lan, IP Address:10.8.0.1Als in plaats daarvan No extensions in certificate wordt getoond, bevat het certificaat geen SAN en zullen browsers het weigeren. Genereer het certificaat opnieuw in plaats van door te gaan.
Beveilig de key
Een private key die leesbaar is voor elke gebruiker op de server is geen private key. Op een standaard Ubuntu 24.04-systeem is /etc/ssl/private al 700 root:root, waardoor alleen root het kan weergeven; het wordt pas 710 root:ssl-cert als er iets is dat het ssl-cert-pakket heeft binnengehaald (apache2 beveelt dit aan). Stel in ieder geval het bestand zelf expliciet in:
sudo chown root:root /etc/ssl/private/git.internal.key
sudo chmod 600 /etc/ssl/private/git.internal.keyZowel nginx als Apache lezen certificaten als root voordat ze hun privileges verlagen, dus root:root modus 600 werkt voor hen. Als de key bedoeld is voor een service die onder een eigen gebruiker draait en de key zelf laadt, zoals een Node-app, Gitea of een Python-daemon, chown deze dan naar die servicegebruiker, nog steeds met modus 600. Wat u nooit moet doen: modus 644, een kopie in een git-repository of een kopie in /tmp.
Koppel het aan nginx
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name git.internal.lan;
ssl_certificate /etc/ssl/certs/git.internal.crt;
ssl_certificate_key /etc/ssl/private/git.internal.key;
location / {
proxy_pass http://127.0.0.1:3000;
}
}sudo nginx -t && sudo systemctl reload nginxnginx -t moet syntax is ok en test is successful weergeven voordat de reload effect heeft. Als het in plaats daarvan SSL_CTX_use_PrivateKey_file() failed ... key values mismatch weergeeft, zijn het certificaat en de sleutel afkomstig van twee verschillende generatieruns; raadpleeg de sectie over foutmodi.
Koppel het aan Apache
sudo a2enmod ssl proxy proxy_httpssl is hier niet voldoende: de onderstaande vhost gebruikt ProxyPass, en zonder mod_proxy en mod_proxy_http mislukt de configuratietest met Invalid command 'ProxyPass', perhaps misspelled or defined by a module not included in the server configuration. Sla de vhost op als /etc/apache2/sites-available/git-internal.conf:
<VirtualHost *:443>
ServerName git.internal.lan
SSLEngine on
SSLCertificateFile /etc/ssl/certs/git.internal.crt
SSLCertificateKeyFile /etc/ssl/private/git.internal.key
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>sudo a2ensite git-internal
sudo apache2ctl configtest && sudo systemctl reload apache2configtest hoort Syntax OK te antwoorden. Test nu vanaf een client-machine:
curl -v https://git.internal.lan/en u krijgt een foutmelding:
curl: (60) SSL certificate problem: self-signed certificateDat is geen bug. Dat is TLS in werking: curl kent uw certificaat niet en weigert te communiceren met een server die het niet kan verifiëren. De volgende sectie bevat de werkelijke oplossing, en dat is niet wat de helft van het internet op dit moment doet.
Clients laten vertrouwen en de anti-patterns die u moet vermijden
Eerst de onjuiste oplossingen, benoemd naar wat ze zijn. curl -k (of --insecure) ingebakken in een script, verify=False in Python requests, NODE_TLS_REJECT_UNAUTHORIZED=0 in Node; geen van deze maakt uw certificaat betrouwbaar. Ze schakelen certificaatverificatie uit, wat betekent dat de client vrolijk communiceert met elke server die elk certificaat presenteert, inclusief een certificaat dat door een aanvaller in het pad is geplaatst. U behoudt de overhead van TLS en verliest de authenticatie die juist het doel was. Erger nog, deze vlaggen verspreiden zich: geplakt in een cron job, daarna een deploy-script, vervolgens in productiecode, totdat niemand meer weet welke verbindingen tijdelijk zouden zijn. Als een verify=False een debug-sessie overleeft, is het ontwerp onjuist.
De juiste oplossing is om elk client-OS te leren dat dit certificaat een vertrouwde root is. Op Ubuntu- en Debian-clients:
sudo cp git.internal.crt /usr/local/share/ca-certificates/git.internal.crt
sudo update-ca-certificatesDe regel die ertoe doet in de output (een Running hooks in /etc/ca-certificates/update.d...-blok volgt hierop):
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.Twee valkuilen in deze regels: het bestand moet eindigen op .crt, een .pem-extensie wordt stilzwijgend genegeerd en u krijgt 0 added zonder foutmelding. De inhoud moet PEM zijn; het bestand begint met -----BEGIN CERTIFICATE-----. Converteer een DER-binary eerst met openssl x509 -inform der -in file.der -out file.crt. Het toevoegen van het self-signed certificaat zelf als root werkt omdat een self-signed certificaat zijn eigen root is.
Daarna vertrouwen curl, wget, git, apt en al het andere dat OpenSSL gebruikt tegen de systeembundel, de server zonder enige vlag. Een handvol clients beheert eigen trust stores en vereist een individuele aanpak:
- Chrome/Chromium op Linux leest een NSS-database, niet de systeem-store:
sudo apt install libnss3-tools, daarnacertutil -d sql:$HOME/.local/share/pki/nssdb -A -t "C,," -n "git.internal" -i git.internal.crtper gebruiker. Dat pad is de standaard van Chrome sinds versie 146; als de gebruiker nog een verouderde~/.pki/nssdbheeft van een oudere installatie, blijft Chrome die lezen. Wijs-dop die machines dus naarsql:$HOME/.pki/nssdb. - Firefox heeft een eigen store: Instellingen → Privacy & Beveiliging → Certificaten → Importeren. Op Windows en macOS kunt u in plaats daarvan
security.enterprise_roots.enabledoptruezetten inabout:config, zodat de OS-store wordt gelezen; Mozilla documenteert die voorkeur voor Windows en macOS, niet voor Linux, dus gebruik op Ubuntu de importfunctie. - Python requests levert een eigen CA-bundel (certifi) mee en negeert de systeem-store: geef
verify="/usr/local/share/ca-certificates/git.internal.crt"mee of exporteerREQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt. - Node.js gebruikt standaard zijn eigen gebundelde roots: exporteer
NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/git.internal.crt, of laat het de systeem-store lezen die u zojuist heeft bijgewerkt met de vlag--use-system-ca(Node 23.9 en later op Linux) ofNODE_USE_SYSTEM_CA=1(Node 24.6 en 22.19 en later).
Op Windows-clients dubbelklikt u op het .crt en installeert u dit in Trusted Root Certification Authorities; op macOS voegt u het toe aan de System-sleutelhanger in Keychain Access en markeert u dit als Always Trust.
Eén root voor vele services: een kleine private CA
Vertrouwen per certificaat schaalt niet: zes services maal vier clientmachines betekent vierentwintig installaties van vertrouwensrelaties, en elke nieuwe service voegt er meer toe. De oplossing is een private CA; clients vertrouwen één root en u ondertekent het certificaat van elke service daarmee.
De gebruiksvriendelijke optie is mkcert, die in de Ubuntu 24.04-repositories zit en de NSS-stores beheert (Firefox, en Chrome met één kanttekening hieronder) die update-ca-certificates mist:
sudo apt install -y mkcert libnss3-tools
mkcert -install
mkcert git.internal.lan "*.internal.lan" 10.8.0.1mkcert -install maakt een root aan en registreert deze in de systeem-store, de NSS-stores van browsers die het kan vinden, en de Java-store wanneer JAVA_HOME is ingesteld. Node leest de systeem-store niet tenzij expliciet aangegeven, dus start Node-applicaties met --use-system-ca (of NODE_USE_SYSTEM_CA=1) zoals hierboven, of exporteer NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem". Het derde commando genereert git.internal.lan+2.pem en git.internal.lan+2-key.pem, klaar om in de nginx- of Apache-snippets van hierboven te plaatsen. Het ontwerp gaat uit van een ontwikkelmachine; de root-key bevindt zich op de machine waar -install is uitgevoerd, dus het is perfect voor een ontwikkel-laptop en ongeschikt voor een serverpark.
De kanttekening, per oktober 2026: mkcert zoekt alleen naar de NSS-database van Chrome op het verouderde ~/.pki/nssdb-pad, niet op ~/.local/share/pki/nssdb, dat Chrome sinds versie 146 standaard gebruikt. Voeg op een machine zonder de verouderde database de root voor Chrome zelf toe met het certutil-commando uit de vorige sectie, gebruikmakend van -i "$(mkcert -CAROOT)/rootCA.pem".
Voor servers voert standaard OpenSSL de volledige CA-procedure uit in vijf commando's:
openssl genrsa -out lab-ca.key 4096
openssl req -x509 -new -key lab-ca.key -sha256 -days 3650 \
-out lab-ca.crt -subj "/CN=Lab Internal CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign"
openssl genrsa -out git.key 2048
openssl req -new -key git.key -out git.csr -subj "/CN=git.internal.lan" \
-addext "subjectAltName=DNS:git.internal.lan,IP:10.8.0.1"
openssl x509 -req -in git.csr -CA lab-ca.crt -CAkey lab-ca.key \
-CAcreateserial -days 730 -sha256 -copy_extensions copy -out git.crtDe valkuil zit in het laatste commando: openssl x509 -req verwijdert standaard alle extensies uit de CSR, inclusief de SAN die u zorgvuldig heeft toegevoegd. -copy_extensions copy (een optie in OpenSSL 3.x, dus het werkt op 24.04) neemt deze over; laat u dit weg, dan heeft het ondertekende certificaat geen SAN en begroet Chrome u opnieuw met NET::ERR_CERT_COMMON_NAME_INVALID. Controleer dit met dezelfde openssl x509 -noout -ext subjectAltName-check als voorheen.
Distribueer lab-ca.crt naar clients via de bovenstaande stappen voor de trust-store, één keer per machine, voor altijd. Beveilig lab-ca.key als de kroonjuwelen die het nu zijn: modus 600, bij voorkeur bewaard op een machine die niet een van de servers is waarvoor het certificaten ondertekent, want wie dit bezit, kan een certificaat aanmaken voor elke naam die uw clients zullen vertrouwen.
Verloop en rotatie
De levensduur van certificaten van publieke CA's neemt snel af. Het CA/Browser Forum heeft de geldigheidsduur van nieuw uitgegeven, publiek vertrouwde certificaten in maart 2026 beperkt tot 200 dagen (voorheen 398). Dit wordt verder teruggebracht naar 100 dagen in 2027 en 47 dagen in maart 2029. Deze regels zijn echter alleen bindend voor publiek vertrouwde CA's. Uw private CA valt hier niet onder en browsers dwingen deze limieten niet af voor handmatig geïnstalleerde root-certificaten. Er is wel één praktische beperking: Apple-platformen weigeren elk TLS-servercertificaat dat langer dan 825 dagen geldig is, ongeacht de uitgever. Als iPhones of Macs verbinding maken, houd de leaf-certificaten dan op een geldigheidsduur van twee jaar of minder. -days 730 voldoet overal aan deze eis; een root-certificaat van tien jaar met leaf-certificaten van twee jaar is een gangbare configuratie voor interne netwerken.
Certificaten met een lange levensduur falen op slechts één manier: geruisloos en tegelijkertijd, op een datum die niemand zich meer herinnert. Controleer wat u heeft:
openssl x509 -in /etc/ssl/certs/git.internal.crt -noout -enddateZet de vernieuwing in een echte agenda of laat cron u 30 dagen van tevoren waarschuwen; openssl x509 -checkend 2592000 -in cert.crt geeft een non-zero exitcode zodra de verloopdatum binnen dat aantal seconden ligt. Als u al Uptime Kuma voor statusmonitoring gebruikt, markeren de HTTPS-monitors automatisch certificaten die bijna verlopen.
Rotatie bij een private CA is aangenaam saai: voer de CSR- en ondertekeningscommando's opnieuw uit, vervang de bestanden en herlaad de webserver. De root is niet gewijzigd, dus cliënten merken niets.
Foutmodi en de bijbehorende meldingen
NET::ERR_CERT_AUTHORITY_INVALID, de verwachte status voordat u vertrouwen instelt; dit is geen defect in het certificaat. Als dit blijft bestaan nadat u de root heeft geïnstalleerd: op Linux leest Chrome de NSS-database in plaats van het systeemarchief (zie de certutil-stap), en sinds Chrome 146 bevindt die database zich op ~/.local/share/pki/nssdb, tenzij er een verouderd ~/.pki/nssdb-bestand bestaat, waardoor een root die aan het andere pad is toegevoegd niet wordt herkend; of het gekopieerde bestand eindigde niet op .crt en update-ca-certificates gaf de melding 0 added; of de server presenteert een ander certificaat dan het certificaat dat u heeft vertrouwd; vergelijk de vingerafdrukken met openssl s_client -connect git.internal.lan:443 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256.
NET::ERR_CERT_COMMON_NAME_INVALID, het certificaat bevat geen SAN, of de SAN dekt de naam in de adresbalk niet. Het klassieke geval: de SAN vermeldt DNS:git.internal.lan, maar de gebruiker navigeerde naar https://10.8.0.1. Wijzigingen in het trust-store kunnen dit niet oplossen; geef het certificaat opnieuw uit met de ontbrekende vermelding.
curl: (60) SSL certificate problem: self-signed certificate, curl vertrouwt het certificaat niet. De variant self-signed certificate in certificate chain betekent hetzelfde voor een certificaat dat is ondertekend door uw private CA. Tijdelijke oplossing: curl --cacert lab-ca.crt https://...; permanente oplossing: het trust-store. Niet -k.
unable to load certificate ... Expecting: TRUSTED CERTIFICATE (of Expecting: CERTIFICATE REQUEST, of no start line), PEM-verwarring. U heeft OpenSSL het verkeerde type bestand gegeven: een key of CSR waar een certificaat werd verwacht, of een DER-binair bestand waar PEM werd verwacht. head -1 filename vertelt u wat u daadwerkelijk heeft; een certificaat begint met -----BEGIN CERTIFICATE-----. Converteer DER-bestanden met openssl x509 -inform der -in file.der -out file.crt.
nginx: [emerg] SSL_CTX_use_PrivateKey_file(...) failed (SSL: error ... key values mismatch), het certificaat en de key horen niet bij elkaar, meestal omdat het generatiecommando twee keer is uitgevoerd en de bestanden zijn verwisseld. Controleer dit met openssl x509 -in git.internal.crt -noout -pubkey | sha256sum versus openssl pkey -in git.internal.key -pubout | sha256sum; overeenkomende hashes betekenen een bijpassend paar. Als ze verschillen, genereer beide dan opnieuw als een paar.
FAQ
Waarom geeft Chrome nog steeds "Niet veilig" aan nadat ik een zelfondertekend certificaat heb aangemaakt?
Als de foutmelding NET::ERR_CERT_AUTHORITY_INVALID is, is het certificaat in orde, maar heeft Chrome simpelweg geen reden om het te vertrouwen. Installeer het certificaat (of uw private CA-root) in de trust store van de client. Houd er rekening mee dat Chrome op Linux de NSS-database gebruikt via certutil (op ~/.local/share/pki/nssdb sinds Chrome 146, of een legacy ~/.pki/nssdb indien aanwezig), en niet de systeem-store. Als de foutmelding NET::ERR_CERT_COMMON_NAME_INVALID is, ontbreekt in het certificaat een Subject Alternative Name die overeenkomt met de URL; het certificaat moet opnieuw worden uitgegeven met -addext "subjectAltName=...".
Hoe zorg ik ervoor dat curl een zelfondertekend certificaat vertrouwt zonder -k?
Kopieer het certificaat (PEM-formaat, .crt-extensie) naar /usr/local/share/ca-certificates/ en voer sudo update-ca-certificates uit; de uitvoer moet 1 added aangeven. Vanaf dat moment verifieert curl het certificaat zoals elk publiek certificaat. Voor een eenmalig verzoek zonder het systeem aan te passen, verifieert curl --cacert /path/to/cert.crt uitsluitend tegen dat bestand; -k schakelt verificatie volledig uit en hoort niet thuis in scripts.
Hoe lang kan een zelfondertekend certificaat geldig zijn?
Technisch gezien zo lang als u wilt. De limieten van het CA/Browser Forum (momenteel 200 dagen, 47 dagen vanaf 2029) zijn bindend voor publiek vertrouwde CA's, niet voor privaat vertrouwen. In de praktijk is het verstandig servercertificaten te beperken tot 825 dagen, omdat Apple-apparaten certificaten met een langere geldigheidsduur weigeren, ongeacht de uitgever. Een private root met een geldigheid van tien jaar en leaf-certificaten van twee jaar (-days 730) is een redelijke standaard. Noteer de verlenging in uw agenda, want een verlopen intern certificaat legt alles geruisloos plat op een datum die niemand zich herinnert.
Moet ik een zelfondertekend certificaat of Let's Encrypt gebruiken?
Als de service een publieke DNS-naam heeft en bereikbaar is vanaf het internet, gebruik dan altijd Let's Encrypt: het is gratis, geautomatiseerd en wordt al door de meeste browsers en besturingssystemen vertrouwd (raadpleeg de compatibiliteitslijst van Let's Encrypt als zeer oude apparaten verbinding moeten maken). Zelfondertekende certificaten (of een private CA) zijn bedoeld voor situaties waarvoor Let's Encrypt geen certificaten kan uitgeven: private IP-adressen, hostnamen die alleen intern bekend zijn zoals .lan, air-gapped netwerken en services die bewust achter een VPN zijn geplaatst. De keuze hangt af van bereikbaarheid en naamgeving, niet van de cryptografische sterkte; de cryptografie is identiek.
Waarom wordt mijn certificaat geweigerd, zelfs nadat ik het heb toegevoegd aan /usr/local/share/ca-certificates?
Controleer drie zaken. Het bestand moet eindigen op .crt; een .pem-extensie wordt stilzwijgend overgeslagen en update-ca-certificates rapporteert 0 added. De inhoud moet PEM-tekst zijn die begint met -----BEGIN CERTIFICATE-----, geen DER-binair bestand. Daarnaast moet de applicatie daadwerkelijk de systeem-store gebruiken. Chrome op Linux, Firefox, Python requests, Node.js (tenzij gestart met --use-system-ca) en Java onderhouden elk een eigen trust store en vereisen dat het certificaat afzonderlijk wordt toegevoegd.