🛠 Outils IT
🛠 102 outils 📚 53 docs
🤖 Assistant ☀

OpenSSL - Aide-mémoire avancé

Conventions : les exemples visent OpenSSL 3.x (Linux, macOS, ou openssl.exe fourni avec Git for Windows). Noms et adresses fictifs (example.com, 192.0.2.0/24). Pour l'architecture d'une PKI, la révocation et ACME, voir PKI et gestion des certificats.

1. Versions, configuration et conventions

1.1 Branches en 2026

BrancheStatutRemarques
1.0.2 / 1.1.1Fin de vie publique (1.1.1 : septembre 2023)Encore présentes sur de vieilles distributions et appliances ; support étendu payant uniquement
3.0 (LTS)Fin de support en septembre 2026Base de RHEL 9, Debian 12, Ubuntu 22.04 : les distributions maintiennent leurs propres correctifs
3.5 (LTS)Support jusqu'en 2030Algorithmes post-quantiques ML-KEM, ML-DSA, SLH-DSA ; groupe hybride X25519MLKEM768 par défaut
3.x non LTSEnviron 13 mois de support chacuneNouvelles fonctions ; vérifier le calendrier sur openssl-library.org
openssl version -a          # version, options de compilation, OPENSSLDIR, MODULESDIR
openssl version -d          # répertoire de configuration (openssl.cnf, certs/)
openssl list -providers     # providers chargés (OpenSSL 3)
openssl help                # liste des sous-commandes ; "openssl <cmd> -help" pour les options

1.2 Passer les secrets proprement

Les options -passin / -passout acceptent plusieurs sources. pass: expose le secret dans ps et l'historique du shell : à éviter hors laboratoire.

SyntaxeSourceUsage
pass:secretLigne de commandeTests uniquement
env:VARVariable d'environnementCI/CD (variable masquée)
file:cheminPremière ligne d'un fichierScripts (fichier 600)
fd:NDescripteur de fichierPassage par pipe
stdinEntrée standardSaisie ou pipe

1.3 Formats et extensions de fichiers

FormatEncodageContenuExtensions usuelles
PEMBase64 + en-têtes -----BEGIN ...-----Un ou plusieurs objets (cert, clé, CSR, CRL).pem, .crt, .cer, .key, .csr
DERBinaire ASN.1Un seul objet.der, .cer, .crl
PKCS#7PEM ou DERCertificats et CRL, pas de clé.p7b, .p7c
PKCS#8PEM ou DERClé privée (tout algorithme), chiffrée ou non.key, .p8
PKCS#1PEM (BEGIN RSA PRIVATE KEY)Clé RSA « traditionnelle ».key
PKCS#12BinaireClé + certificat + chaîne, protégé par mot de passe.pfx, .p12
JKSBinaire (Java)Keystore Java propriétaire.jks, .keystore
L'extension ne dit rien : un .cer peut être PEM ou DER. Pour savoir : head -c 30 fichier (texte -----BEGIN = PEM) ou openssl asn1parse -in fichier -inform DER.

2. Génération et gestion des clés

genpkey est la commande unifiée (tout algorithme, sortie PKCS#8). genrsa et ecparam -genkey restent disponibles mais sont historiques.

# RSA 3072 bits (2048 minimum, 3072 recommandé pour une durée longue)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rsa.key

# ECDSA P-256 (prime256v1 / secp256r1) - choix par défaut pour un serveur TLS
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve -out ec256.key

# ECDSA P-384
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -pkeyopt ec_param_enc:named_curve -out ec384.key

# Ed25519 (SSH, signatures applicatives ; peu supporté par les AC TLS publiques)
openssl genpkey -algorithm ED25519 -out ed25519.key

# X25519 (échange de clés uniquement, pas de signature)
openssl genpkey -algorithm X25519 -out x25519.key

# Post-quantique (OpenSSL 3.5+) : signature ML-DSA, pour laboratoire
openssl genpkey -algorithm ML-DSA-65 -out mldsa65.key

# Restreindre les droits AVANT d'écrire la clé
umask 077; openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out srv.key

2.1 Chiffrer, déchiffrer, inspecter une clé

# Générer directement une clé chiffrée (AES-256, mot de passe depuis un fichier)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -aes-256-cbc -pass file:./cle.pass -out ec.key.enc

# Chiffrer une clé existante / retirer la protection (pour un service sans saisie)
openssl pkey -in srv.key -aes-256-cbc -out srv.key.enc
openssl pkey -in srv.key.enc -out srv.key

# Afficher les paramètres (taille, courbe) sans divulguer la clé dans les logs
openssl pkey -in srv.key -noout -text_pub
openssl pkey -in srv.key -noout -text | head -3

# Vérifier la cohérence interne d'une clé
openssl pkey -in srv.key -check -noout          # OpenSSL 3
openssl rsa -in rsa.key -check -noout           # RSA

# Extraire la clé publique
openssl pkey -in srv.key -pubout -out srv.pub

# PKCS#8 (BEGIN PRIVATE KEY) vers PKCS#1 (BEGIN RSA PRIVATE KEY) pour un vieux logiciel
openssl rsa -in rsa.key -traditional -out rsa-pkcs1.key
# EC "traditionnel" (BEGIN EC PRIVATE KEY)
openssl ec -in ec256.key -out ec256-trad.key

# Courbes disponibles
openssl ecparam -list_curves
AlgorithmeSécurité équivalenteTaille de signatureCompatibilité TLS
RSA 2048~112 bits256 octetsUniverselle
RSA 3072~128 bits384 octetsUniverselle, handshake plus lent
ECDSA P-256~128 bits~72 octetsTous les clients modernes
ECDSA P-384~192 bits~104 octetsTous les clients modernes
Ed25519~128 bits64 octetsTLS 1.3 côté bibliothèques, mais quasi absent des AC publiques

3. CSR avec SAN

3.1 En une ligne avec -addext

openssl req -new -key srv.key -out srv.csr \
    -subj "/C=FR/O=Example/CN=www.example.com" \
    -addext "subjectAltName=DNS:www.example.com,DNS:example.com,IP:192.0.2.10" \
    -addext "keyUsage=critical,digitalSignature" \
    -addext "extendedKeyUsage=serverAuth"

# Clé + CSR en une commande (-noenc remplace -nodes, déprécié en OpenSSL 3)
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
    -keyout srv.key -out srv.csr -subj "/CN=www.example.com" \
    -addext "subjectAltName=DNS:www.example.com,DNS:example.com"
Ce que l'AC conserve : une AC publique ne reprend en général que la clé publique et les noms (validés) ; elle impose ses propres KU/EKU, durée et politique. Les champs O, OU, L ne sont repris que pour un certificat OV/EV (le champ OU est d'ailleurs interdit dans les certificats publics depuis 2022).

3.2 Avec un fichier de configuration (reproductible, versionnable)

# srv.cnf
[ req ]
default_md         = sha256
prompt             = no
distinguished_name = dn
req_extensions     = req_ext

[ dn ]
C  = FR
O  = Example
CN = www.example.com

[ req_ext ]
subjectAltName   = @alt_names
keyUsage         = critical, digitalSignature
extendedKeyUsage = serverAuth

[ alt_names ]
DNS.1 = www.example.com
DNS.2 = example.com
DNS.3 = api.example.com
IP.1  = 192.0.2.10
openssl req -new -config srv.cnf -key srv.key -out srv.csr
openssl req -in srv.csr -noout -text -verify     # contrôle : signature + extensions demandées

3.3 CSR depuis une clé ou un certificat existants

# Renouveler avec la même clé et les mêmes informations qu'un certificat existant
openssl x509 -x509toreq -in ancien.crt -signkey srv.key -copy_extensions copyall -out renouv.csr

# Certificat auto-signé rapide (lab, 30 jours)
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc -days 30 \
    -keyout lab.key -out lab.crt -subj "/CN=lab.example.com" \
    -addext "subjectAltName=DNS:lab.example.com"
Durée par défaut : sans -days, req -x509 et x509 -req émettent pour 30 jours. Et un certificat auto-signé n'a de sens que s'il est explicitement approuvé côté client ; pour plus de deux services, montez une AC de test (section suivante) ou une vraie PKI interne.

4. AC de test locale complète

Objectif : une racine, un intermédiaire, un certificat serveur et un certificat client, une CRL, puis un test de bout en bout avec s_server / s_client. Utile pour reproduire un problème de chaîne, tester du mTLS ou une configuration de proxy.

4.1 Fichier de configuration unique

# lab-ca.cnf
[ ca ]
default_ca = CA_inter

[ CA_inter ]
dir              = ./db
database         = $dir/index.txt
new_certs_dir    = $dir/newcerts
serial           = $dir/serial
crlnumber        = $dir/crlnumber
certificate      = ./inter.crt
private_key      = ./inter.key
default_md       = sha256
default_days     = 90
default_crl_days = 7
policy           = policy_any
copy_extensions  = none

[ policy_any ]
commonName = supplied

[ req ]
distinguished_name = dn
prompt             = no
[ dn ]
CN = placeholder

[ v3_root ]
basicConstraints       = critical, CA:TRUE
keyUsage               = critical, keyCertSign, cRLSign
subjectKeyIdentifier   = hash

[ v3_inter ]
basicConstraints       = critical, CA:TRUE, pathlen:0
keyUsage               = critical, keyCertSign, cRLSign
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always
crlDistributionPoints  = URI:http://pki.lab.example.com/root.crl

[ v3_server ]
basicConstraints       = critical, CA:FALSE
keyUsage               = critical, digitalSignature
extendedKeyUsage       = serverAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid
subjectAltName         = DNS:www.lab.example.com, DNS:lab.example.com, IP:127.0.0.1
crlDistributionPoints  = URI:http://pki.lab.example.com/inter.crl

[ v3_client ]
basicConstraints       = critical, CA:FALSE
keyUsage               = critical, digitalSignature
extendedKeyUsage       = clientAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid
subjectAltName         = email:svc-app@lab.example.com

4.2 Racine et intermédiaire

mkdir -p db/newcerts && touch db/index.txt
openssl rand -hex 16 > db/serial
echo 1000 > db/crlnumber

# Racine (10 ans)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out root.key
openssl req -x509 -new -config lab-ca.cnf -extensions v3_root -key root.key \
    -subj "/O=Lab Example/CN=Lab Root CA" -days 3650 -sha384 -out root.crt

# Intermédiaire (5 ans), signé par la racine
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out inter.key
openssl req -new -config lab-ca.cnf -key inter.key -subj "/O=Lab Example/CN=Lab Issuing CA" -out inter.csr
openssl x509 -req -in inter.csr -CA root.crt -CAkey root.key -CAcreateserial \
    -days 1825 -sha384 -extfile lab-ca.cnf -extensions v3_inter -out inter.crt

4.3 Certificats serveur et client

# Serveur
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out srv.key
openssl req -new -config lab-ca.cnf -key srv.key -subj "/CN=www.lab.example.com" -out srv.csr
openssl ca -batch -config lab-ca.cnf -extensions v3_server -in srv.csr -out srv.crt -notext

# Client (mTLS)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out client.key
openssl req -new -config lab-ca.cnf -key client.key -subj "/CN=svc-app" -out client.csr
openssl ca -batch -config lab-ca.cnf -extensions v3_client -in client.csr -out client.crt -notext

# Chaîne à servir : feuille puis intermédiaire (jamais la racine)
cat srv.crt inter.crt > srv.fullchain.pem
Pourquoi openssl ca pour les feuilles : il tient une base (index.txt) des certificats émis, ce qui permet la révocation et la génération de CRL. copy_extensions = none ignore les extensions de la CSR (le demandeur ne choisit pas ses SAN ni son EKU : c'est exactement la faille ESC1 d'ADCS transposée).

4.4 Révocation et CRL

openssl ca -config lab-ca.cnf -revoke client.crt -crl_reason keyCompromise
openssl ca -config lab-ca.cnf -gencrl -out inter.crl
openssl crl -in inter.crl -noout -text | head -20

# Vérifier avec contrôle de la CRL (feuille)
openssl verify -crl_check -CAfile root.crt -untrusted inter.crt -CRLfile inter.crl client.crt
# => error 23 at 0 depth lookup: certificate revoked

4.5 Test de bout en bout (TLS et mTLS)

# Terminal 1 : serveur de test, exige un certificat client
openssl s_server -accept 8443 -cert srv.crt -key srv.key -cert_chain inter.crt \
    -CAfile root.crt -Verify 2 -www

# Terminal 2 : client
openssl s_client -connect 127.0.0.1:8443 -servername www.lab.example.com \
    -CAfile root.crt -verify_hostname www.lab.example.com -verify_return_error \
    -cert client.crt -key client.key -cert_chain inter.crt </dev/null

curl --cacert root.crt --cert client.crt --key client.key \
    --resolve www.lab.example.com:8443:127.0.0.1 https://www.lab.example.com:8443/

-Verify 2 (majuscule) rend le certificat client obligatoire ; -verify 2 le demande sans l'exiger. -www renvoie une page d'état avec la session négociée.

5. Inspection de certificats, CSR, CRL

# Tout le contenu
openssl x509 -in cert.pem -noout -text

# Champs ciblés (beaucoup plus lisible dans un script)
openssl x509 -in cert.pem -noout -subject -issuer -serial -dates
openssl x509 -in cert.pem -noout -ext subjectAltName,keyUsage,extendedKeyUsage,basicConstraints
openssl x509 -in cert.pem -noout -ext authorityInfoAccess,crlDistributionPoints
openssl x509 -in cert.pem -noout -fingerprint -sha256
openssl x509 -in cert.pem -noout -enddate
openssl x509 -in cert.pem -noout -ocsp_uri
openssl x509 -in cert.pem -noout -nameopt RFC2253 -subject     # format "CN=...,O=..."

# Expire dans moins de 30 jours ? (code retour 1 si oui)
openssl x509 -in cert.pem -noout -checkend 2592000

# Certificat DER
openssl x509 -in cert.der -inform DER -noout -text

# Tous les certificats d'un bundle PEM (fullchain, ca-bundle)
openssl storeutl -noout -text -certs bundle.pem | grep -E "^[0-9]+: Certificate|Subject:|Issuer:|Not After"
# alternative compatible 1.1.1
openssl crl2pkcs7 -nocrl -certfile bundle.pem | openssl pkcs7 -print_certs -noout

# CSR
openssl req -in srv.csr -noout -text -verify
openssl req -in srv.csr -noout -subject

# CRL (souvent en DER)
openssl crl -in inter.crl -inform DER -noout -text
openssl crl -in inter.crl -inform DER -noout -lastupdate -nextupdate

# Structure ASN.1 brute (extension inconnue, débogage d'encodage)
openssl asn1parse -in cert.pem -i

# Empreinte SPKI (pinning, HPKP hérité, cert-manager, certaines API)
openssl x509 -in cert.pem -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256 -binary | openssl base64

# Hash de sujet pour un répertoire de confiance (CApath)
openssl x509 -in root.crt -noout -subject_hash
openssl rehash /etc/ssl/mesac/

5.1 Lecture rapide d'un x509 -text

LigneÀ vérifier
Signature Algorithmsha256WithRSAEncryption, ecdsa-with-SHA256/384 ; jamais SHA-1 / MD5
Issuer / SubjectIdentiques = auto-signé (racine ou certificat de lab)
ValidityDates en UTC (GMT) ; comparer à l'horloge de la machine
Public-Key(2048 bit) / (256 bit) et la courbe NIST CURVE: P-256
X509v3 Subject Alternative NameTous les noms utilisés par les clients
X509v3 Basic ConstraintsCA:FALSE pour une feuille ; CA:TRUE, pathlen:0 pour un intermédiaire
Authority Information AccessCA Issuers - URI (et OCSP s'il existe encore)
CT Precertificate SCTsPrésents pour un certificat public

6. Diagnostiquer un serveur avec s_client

# Connexion de base : chaîne envoyée, vérification, protocole, suite
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null

# Résumé compact (protocole, suite, groupe, signataire, vérification)
openssl s_client -connect www.example.com:443 -servername www.example.com -brief </dev/null

# Échouer franchement si la chaîne ou le nom ne sont pas valides
openssl s_client -connect www.example.com:443 -servername www.example.com \
    -verify_return_error -verify_hostname www.example.com </dev/null

# Utiliser une AC interne pour la vérification
openssl s_client -connect intranet.corp.example.com:443 -CAfile corp-root.pem </dev/null

# Réponse OCSP agrafée (stapling)
openssl s_client -connect www.example.com:443 -servername www.example.com -status </dev/null 2>/dev/null | grep -A 15 "OCSP response"

# ALPN (HTTP/2) et cible IP précise (un nœud derrière un LB)
openssl s_client -connect 192.0.2.21:443 -servername www.example.com -alpn h2,http/1.1 </dev/null | grep -i alpn

# Forcer IPv4 / IPv6, passer par un proxy HTTP CONNECT
openssl s_client -4 -connect www.example.com:443 </dev/null
openssl s_client -connect www.example.com:443 -proxy 10.0.0.3:3128 -servername www.example.com </dev/null

# Reprise de session (tickets / PSK TLS 1.3)
openssl s_client -connect www.example.com:443 -servername www.example.com -reconnect </dev/null | grep -E "^(New|Reused)"

# Journal des secrets pour déchiffrer une capture dans Wireshark (lab uniquement)
openssl s_client -connect www.example.com:443 -keylogfile /tmp/tls-keys.log </dev/null

# Trace détaillée de la négociation
openssl s_client -connect www.example.com:443 -servername www.example.com -msg -state </dev/null

6.1 Extraire les certificats du serveur

# Feuille seule
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null \
    | openssl x509 -outform PEM > feuille.pem

# Toute la chaîne envoyée, un fichier par certificat (cert0.pem = feuille)
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null 2>/dev/null \
    | awk '/BEGIN CERT/{n++; f="cert" n-1 ".pem"} /BEGIN CERT/,/END CERT/{print > f}'

# Dates d'expiration de chaque certificat envoyé
for f in cert*.pem; do echo "$f : $(openssl x509 -in "$f" -noout -subject -enddate)"; done

6.2 Lire la sortie

LigneInterprétation
Certificate chain avec 0 s: / i:Liste envoyée par le serveur : chaque i: doit être le s: de la ligne suivante
Verify return code: 0 (ok)Chaîne valide vers une racine du magasin utilisé
20 (unable to get local issuer certificate)Intermédiaire manquant ou racine absente du magasin
21 (unable to verify the first certificate)Le serveur n'envoie que la feuille
10 (certificate has expired)Un certificat de la chaîne est expiré (regarder la profondeur indiquée)
18 / 19 (self-signed certificate (in certificate chain))Auto-signé, ou racine non approuvée
62 (hostname mismatch)Nom absent du SAN (avec -verify_hostname)
Peer signature type, Negotiated TLS1.3 groupAlgorithme de signature et groupe d'échange (X25519, X25519MLKEM768...)
Secure Renegotiation IS NOT supportedNormal en TLS 1.3
Magasin de confiance : s_client utilise le magasin d'OpenSSL (OPENSSLDIR/certs), pas celui de Windows ni celui de Java. Sur Windows (Git Bash), un Verify return code: 20 peut simplement signifier qu'OpenSSL ne connaît pas la racine : passer -CAfile explicitement.

7. Vérifier une chaîne, une CRL, l'OCSP

# Chaîne : la racine dans -CAfile (ancre), les intermédiaires dans -untrusted
openssl verify -CAfile root.pem -untrusted intermediate.pem leaf.pem

# Afficher le chemin construit
openssl verify -show_chain -CAfile root.pem -untrusted intermediate.pem leaf.pem

# Avec le magasin système (intermédiaires en -untrusted)
openssl verify -untrusted intermediate.pem leaf.pem

# Contrôler l'usage et le nom
openssl verify -purpose sslserver -verify_hostname www.example.com -CAfile root.pem -untrusted intermediate.pem leaf.pem

# Vérifier à une date donnée (epoch) : utile après un renouvellement d'intermédiaire
openssl verify -attime $(date -d "2027-01-15" +%s) -CAfile root.pem -untrusted intermediate.pem leaf.pem

# CRL : feuille seule (-crl_check) ou toute la chaîne (-crl_check_all)
curl -s -o inter.crl "$(openssl x509 -in leaf.pem -noout -ext crlDistributionPoints | grep -o 'http[^ ]*')"
openssl crl -in inter.crl -inform DER -out inter.crl.pem       # les CRL publiées sont en général en DER
openssl verify -crl_check -CAfile root.pem -untrusted intermediate.pem -CRLfile inter.crl.pem leaf.pem

# OCSP (si l'AC en propose encore)
OCSP_URL=$(openssl x509 -in leaf.pem -noout -ocsp_uri)
openssl ocsp -issuer intermediate.pem -cert leaf.pem -url "$OCSP_URL" -resp_text -noverify | grep -E "Cert Status|This Update|Next Update"
-CAfile vs -untrusted : mettre l'intermédiaire dans -CAfile fait de lui une ancre de confiance : la vérification réussit même si la racine est inconnue ou expirée, et masque le problème. Seules les racines vont dans -CAfile. Avec OpenSSL 1.1.0+, -partial_chain rend ce comportement explicite.

8. Conversions de formats (PEM, DER, PKCS#7, PKCS#12, JKS)

8.1 PEM, DER, PKCS#7

# Certificat PEM <-> DER
openssl x509 -in cert.pem -outform DER -out cert.der
openssl x509 -in cert.der -inform DER -out cert.pem

# Clé PEM <-> DER
openssl pkey -in srv.key -outform DER -out srv.key.der
openssl pkey -in srv.key.der -inform DER -out srv.key

# CRL DER -> PEM
openssl crl -in ca.crl -inform DER -out ca.crl.pem

# PEM (chaîne) -> PKCS#7 (.p7b, import Windows/Java d'une chaîne)
openssl crl2pkcs7 -nocrl -certfile fullchain.pem -out chain.p7b

# PKCS#7 -> PEM (souvent livré par les AC commerciales et ADCS)
openssl pkcs7 -in chain.p7b -print_certs -out chain.pem
openssl pkcs7 -in chain.p7b -inform DER -print_certs -out chain.pem

8.2 PKCS#12 / PFX

# Créer un PFX : clé + certificat + chaîne, avec un nom convivial
openssl pkcs12 -export -inkey srv.key -in srv.crt -certfile inter.crt \
    -name "www.example.com 2026" -out srv.pfx -passout file:./pfx.pass

# PFX compatible avec les anciens Windows (Server 2016 et antérieurs) et vieux Java :
# OpenSSL 3 chiffre par défaut en AES-256-CBC + PBKDF2 + MAC SHA-256, illisible pour eux
openssl pkcs12 -export -inkey srv.key -in srv.crt -certfile inter.crt -out srv-compat.pfx \
    -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1 -passout file:./pfx.pass

# Lire / inspecter un PFX (algorithmes utilisés, sans afficher la clé)
openssl pkcs12 -in srv.pfx -info -noout -passin file:./pfx.pass

# Vieux PFX (RC2-40, export Windows ancien) : erreur "unsupported" en OpenSSL 3
openssl pkcs12 -in ancien.pfx -legacy -info -noout
# ou explicitement
openssl pkcs12 -in ancien.pfx -provider legacy -provider default -info -noout

# Extraire
openssl pkcs12 -in srv.pfx -nocerts -noenc -out srv.key          # clé en clair (protéger le fichier)
openssl pkcs12 -in srv.pfx -clcerts -nokeys -out srv.crt         # certificat feuille
openssl pkcs12 -in srv.pfx -cacerts -nokeys -out chain.pem       # intermédiaires
openssl pkcs12 -in srv.pfx -noenc -out tout.pem                  # tout (clé + certs)

# Re-chiffrer un vieux PFX au format moderne (en deux temps, sans fichier intermédiaire)
openssl pkcs12 -in ancien.pfx -legacy -noenc -passin file:./old.pass \
  | openssl pkcs12 -export -out moderne.pfx -passout file:./pfx.pass
Mot de passe vide vs absent : -passout pass: crée un PFX avec un mot de passe vide (intégrité MAC calculée avec une chaîne vide) ; -nomac / -keypbe NONE créent un PFX réellement non protégé. Windows, Java et Azure ne réagissent pas de la même façon aux deux cas : certains outils refusent un mot de passe vide, d'autres exigent qu'il n'y en ait pas. En production, toujours un vrai mot de passe, transmis par un canal séparé.

8.3 Java : JKS et PKCS12 avec keytool

# PFX -> JKS (depuis Java 9, PKCS12 est le format par défaut : préférer garder le .p12)
keytool -importkeystore -srckeystore srv.p12 -srcstoretype PKCS12 \
    -destkeystore srv.jks -deststoretype JKS

# JKS -> PKCS12 (puis openssl pour obtenir du PEM)
keytool -importkeystore -srckeystore ancien.jks -srcstoretype JKS \
    -destkeystore ancien.p12 -deststoretype PKCS12
openssl pkcs12 -in ancien.p12 -noenc -out ancien.pem

# Truststore : ajouter une AC interne
keytool -importcert -alias corp-root -file corp-root.crt -keystore truststore.p12 -storetype PKCS12
keytool -importcert -alias corp-root -file corp-root.crt -cacerts       # magasin global du JDK

# Lister
keytool -list -v -keystore srv.p12 -storetype PKCS12 | grep -E "Alias|Valid|Owner|Issuer"

8.4 Assembler les fichiers attendus par chaque logiciel

LogicielAttenduCommande
nginxssl_certificate = feuille + intermédiaires ; clé séparéecat srv.crt inter.crt > fullchain.pem
Apache 2.4.8+SSLCertificateFile peut contenir la chaîne (SSLCertificateChainFile est obsolète)Idem nginx
HAProxyUn seul PEM : certificat, chaîne, clécat srv.crt inter.crt srv.key > /etc/haproxy/certs/www.pem
IIS / Windows / AzurePFX avec chaîneopenssl pkcs12 -export ...
Tomcat / JavaPKCS12 (ou JKS)openssl pkcs12 -export ... -name tomcat
Kubernetes Secret TLStls.crt = fullchain, tls.keykubectl create secret tls www --cert=fullchain.pem --key=srv.key
Postfix / DovecotFullchain + clé (ou fichier combiné clé d'abord pour Postfix smtpd_tls_chain_files)Voir la documentation de la version

9. Appariement clé / certificat / CSR

Méthode universelle (RSA, ECDSA, Ed25519) : comparer l'empreinte de la clé publique extraite de chaque objet. Les trois empreintes doivent être identiques.

openssl pkey -in srv.key -pubout -outform DER | openssl dgst -sha256
openssl x509 -in srv.crt -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256
openssl req  -in srv.csr -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256

# Variante historique, RSA uniquement (modulus)
openssl rsa  -in srv.key -noout -modulus | openssl sha256
openssl x509 -in srv.crt -noout -modulus | openssl sha256
# Fonction shell : retrouver la clé d'un certificat parmi un répertoire de clés
match_key() {
  local crt="$1"; shift
  local ref; ref=$(openssl x509 -in "$crt" -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256 -r | cut -d' ' -f1)
  for k in "$@"; do
    h=$(openssl pkey -in "$k" -pubout -outform DER 2>/dev/null | openssl dgst -sha256 -r | cut -d' ' -f1)
    [ "$h" = "$ref" ] && echo "MATCH : $k"
  done
}
match_key srv.crt /etc/ssl/private/*.key
Intermédiaire attendu : pour savoir si inter.crt est bien l'émetteur de srv.crt, comparer l'Authority Key Identifier de la feuille au Subject Key Identifier de l'intermédiaire : openssl x509 -in srv.crt -noout -ext authorityKeyIdentifier et openssl x509 -in inter.crt -noout -ext subjectKeyIdentifier, ou plus simplement openssl verify -partial_chain -CAfile inter.crt srv.crt.

10. Chiffrement, signature, hash et HMAC

10.1 Chiffrement symétrique de fichiers (enc)

# Chiffrer : AES-256-CBC, clé dérivée par PBKDF2 avec beaucoup d'itérations, sel aléatoire
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 600000 -in dump.sql -out dump.sql.enc -pass file:./backup.pass

# Déchiffrer : EXACTEMENT les mêmes options (-pbkdf2, -iter, algorithme)
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -in dump.sql.enc -out dump.sql -pass file:./backup.pass

# Sortie Base64 (copier-coller)
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -a -in note.txt -out note.txt.b64 -pass file:./backup.pass
Limites de enc : sans -pbkdf2, la clé est dérivée par EVP_BytesToKey en une seule itération (attaque par dictionnaire triviale) et OpenSSL l'indique par un avertissement. enc ne supporte pas les modes authentifiés (GCM) : un fichier altéré peut se déchiffrer en données corrompues sans erreur. Pour des sauvegardes, préférer age, GnuPG, ou openssl cms (ci-dessous) ; voir Stratégie de sauvegarde.

10.2 Chiffrement asymétrique

# RSA brut : uniquement de petites données (< taille de clé - padding), OAEP obligatoire
openssl pkeyutl -encrypt -pubin -inkey dest.pub -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 \
    -in secret.bin -out secret.bin.enc
openssl pkeyutl -decrypt -inkey dest.key -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 \
    -in secret.bin.enc -out secret.bin

# Fichier de taille quelconque : CMS (chiffrement hybride, AES-256-GCM, destinataire = certificat)
openssl cms -encrypt -aes-256-gcm -recip dest.crt -binary -in gros.tar -outform DER -out gros.tar.cms
openssl cms -decrypt -inform DER -in gros.tar.cms -recip dest.crt -inkey dest.key -binary -out gros.tar

10.3 Signature et vérification

# RSA / ECDSA : signature d'un condensat SHA-256
openssl dgst -sha256 -sign signer.key -out release.tar.gz.sig release.tar.gz
openssl dgst -sha256 -verify signer.pub -signature release.tar.gz.sig release.tar.gz    # "Verified OK"

# Ed25519 : pas de pré-hachage, utiliser pkeyutl -rawin
openssl pkeyutl -sign -inkey ed25519.key -rawin -in message.txt -out message.sig
openssl pkeyutl -verify -pubin -inkey ed25519.pub -rawin -in message.txt -sigfile message.sig

# Signature CMS/S-MIME détachée avec certificat (vérifiable par un tiers)
openssl cms -sign -signer signer.crt -inkey signer.key -certfile inter.crt -binary -in doc.pdf -outform DER -out doc.pdf.p7s
openssl cms -verify -inform DER -in doc.pdf.p7s -content doc.pdf -CAfile root.crt -binary -out /dev/null

10.4 Hash, HMAC, aléatoire, mots de passe

# Empreintes
openssl dgst -sha256 fichier.iso
openssl dgst -sha3-256 fichier.iso
openssl dgst -sha256 -r fichier.iso            # format "hash *fichier" compatible sha256sum

# HMAC
openssl dgst -sha256 -hmac "$HMAC_KEY" payload.json
openssl mac -digest SHA256 -macopt hexkey:$(cat hmac.hex) -in payload.json HMAC     # OpenSSL 3

# Vérifier une signature de webhook (exemple générique : HMAC-SHA256 en hexadécimal)
printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -r | cut -d' ' -f1

# Aléatoire cryptographique (secrets, jetons, clés)
openssl rand -hex 32
openssl rand -base64 48 | tr -d '\n'

# Hash de mot de passe pour /etc/shadow (SHA-512 crypt)
openssl passwd -6

# Base64 sans retour à la ligne / décodage
openssl base64 -A -in bin.dat
openssl base64 -d -in data.b64 -out data.bin

11. Tester protocoles et suites

11.1 Protocoles

# Le serveur accepte-t-il TLS 1.3 ? TLS 1.2 ?
openssl s_client -connect www.example.com:443 -servername www.example.com -tls1_3 </dev/null 2>&1 | grep -E "Protocol|Cipher is"
openssl s_client -connect www.example.com:443 -servername www.example.com -tls1_2 </dev/null 2>&1 | grep -E "Protocol|Cipher is"

# Protocoles obsolètes : OpenSSL 3 les refuse au niveau de sécurité par défaut (SHA-1 dans le PRF)
openssl s_client -connect www.example.com:443 -servername www.example.com -tls1_1 -cipher 'DEFAULT:@SECLEVEL=0' </dev/null
openssl s_client -connect www.example.com:443 -servername www.example.com -tls1   -cipher 'DEFAULT:@SECLEVEL=0' </dev/null
# "no protocols available" = c'est le CLIENT qui ne sait plus ; "alert protocol version" = le serveur refuse

11.2 Suites

TLS 1.2 et TLS 1.3 ont deux listes distinctes : -cipher (TLS ≤ 1.2, syntaxe OpenSSL) et -ciphersuites (TLS 1.3, noms IANA).

# Une suite TLS 1.2 précise
openssl s_client -connect www.example.com:443 -servername www.example.com -tls1_2 \
    -cipher 'ECDHE-ECDSA-AES128-GCM-SHA256' </dev/null 2>&1 | grep "Cipher is"

# Une suite TLS 1.3 précise
openssl s_client -connect www.example.com:443 -servername www.example.com -tls1_3 \
    -ciphersuites 'TLS_CHACHA20_POLY1305_SHA256' </dev/null 2>&1 | grep "Cipher is"

# Groupes d'échange de clés (dont l'hybride post-quantique, OpenSSL 3.5+)
openssl s_client -connect www.example.com:443 -servername www.example.com -groups X25519MLKEM768 </dev/null 2>&1 | grep -i group

# Développer une chaîne de suites (avec noms IANA)
openssl ciphers -v -stdname -tls1_2 'ECDHE+AESGCM:ECDHE+CHACHA20:!aNULL'
openssl ciphers -s -v -tls1_3
#!/usr/bin/env bash
# enum_ciphers.sh - suites TLS 1.2 et 1.3 acceptées par un serveur
H="${1:?hôte}"; P="${2:-443}"
for c in $(openssl ciphers 'ALL:COMPLEMENTOFALL:@SECLEVEL=0' | tr ':' ' '); do
  if openssl s_client -connect "$H:$P" -servername "$H" -tls1_2 -cipher "$c:@SECLEVEL=0" </dev/null >/dev/null 2>&1; then
    echo "TLS1.2 $c"
  fi
done
for s in TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256; do
  if openssl s_client -connect "$H:$P" -servername "$H" -tls1_3 -ciphersuites "$s" </dev/null >/dev/null 2>&1; then
    echo "TLS1.3 $s"
  fi
done
Outils complémentaires : nmap --script ssl-enum-ciphers -p 443 www.example.com (classe les suites de A à F), testssl.sh (audit complet, vulnérabilités), et l'outil Cipher Suite du site pour décoder une suite. Pour la configuration serveur cible, voir SSL Labs et Apache.

11.3 Signatures et certificats multiples

# Obtenir le certificat ECDSA d'un serveur qui sert RSA + ECDSA
openssl s_client -connect www.example.com:443 -servername www.example.com -sigalgs 'ECDSA+SHA256' </dev/null 2>/dev/null | openssl x509 -noout -text | grep "Public Key Algorithm"
openssl s_client -connect www.example.com:443 -servername www.example.com -sigalgs 'RSA-PSS+SHA256:RSA+SHA256' </dev/null 2>/dev/null | openssl x509 -noout -text | grep "Public Key Algorithm"

# Comportement sans SNI (certificat par défaut du serveur)
openssl s_client -connect 192.0.2.21:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -subject

12. STARTTLS et protocoles applicatifs

ServicePortModeCommande
SMTP soumission587STARTTLS-starttls smtp
SMTP relais25STARTTLS-starttls smtp -name relais.example.com
SMTPS465TLS direct(aucune option)
IMAP / IMAPS143 / 993STARTTLS / direct-starttls imap / direct
POP3 / POP3S110 / 995STARTTLS / direct-starttls pop3 / direct
LDAP / LDAPS389 / 636StartTLS / direct-starttls ldap / direct
PostgreSQL5432Négociation SSLRequest (ou TLS direct en PG 17+)-starttls postgres (ou -alpn postgresql en TLS direct)
MySQL / MariaDB3306Négociation dans le handshake-starttls mysql
FTP explicite21AUTH TLS-starttls ftp
XMPP5222STARTTLS-starttls xmpp -xmpphost example.com
RDP / SQL Server (TDS < 8)3389 / 1433TLS encapsuléNon supporté par s_client : nmap --script ssl-cert
# SMTP : certificat, protocole et EHLO du serveur
openssl s_client -connect mail.example.com:587 -starttls smtp -servername mail.example.com -crlf -brief </dev/null

# Session SMTP interactive chiffrée (taper EHLO, puis QUIT)
openssl s_client -connect mail.example.com:587 -starttls smtp -crlf -quiet

# LDAP StartTLS (contrôleur de domaine) et LDAPS
openssl s_client -connect dc01.corp.example.com:389 -starttls ldap -showcerts </dev/null
openssl s_client -connect dc01.corp.example.com:636 -showcerts </dev/null

# PostgreSQL et MySQL : le certificat serveur est-il celui attendu ?
openssl s_client -connect db01.corp.example.com:5432 -starttls postgres </dev/null 2>/dev/null | openssl x509 -noout -subject -enddate
openssl s_client -connect db02.corp.example.com:3306 -starttls mysql   </dev/null 2>/dev/null | openssl x509 -noout -subject -enddate

# Expiration de tous les services d'un serveur de messagerie
for spec in "587 smtp" "143 imap" "110 pop3" "993 -" "995 -" "465 -"; do
  set -- $spec
  opt=""; [ "$2" != "-" ] && opt="-starttls $2"
  printf "%-5s " "$1"
  openssl s_client -connect mail.example.com:$1 $opt -servername mail.example.com </dev/null 2>/dev/null \
    | openssl x509 -noout -enddate 2>/dev/null || echo "KO"
done
SMTP entre serveurs : sur le port 25, la plupart des MTA acceptent un certificat non vérifiable (chiffrement opportuniste) sauf si MTA-STS ou DANE l'imposent. Un certificat expiré sur le MX peut donc passer inaperçu jusqu'à ce qu'un domaine partenaire publie MTA-STS en mode enforce. Voir Microsoft 365 / Exchange pour les connecteurs TLS.

13. Performance : speed et s_time

# Opérations asymétriques par seconde (signatures = coût côté serveur TLS)
openssl speed -seconds 3 rsa2048 rsa3072 rsa4096 ecdsap256 ecdsap384 ed25519

# Chiffrement symétrique via EVP (utilise AES-NI / ARMv8 Crypto)
openssl speed -seconds 3 -evp aes-128-gcm
openssl speed -seconds 3 -evp aes-256-gcm
openssl speed -seconds 3 -evp chacha20-poly1305

# Tous les cœurs
openssl speed -multi $(nproc) -evp aes-256-gcm

# Mesurer le gain d'AES-NI (masque qui désactive AES-NI et PCLMULQDQ, x86_64)
OPENSSL_ia32cap="~0x200000200000000" openssl speed -seconds 3 -evp aes-128-gcm

# Échange de clés (OpenSSL 3.x : ecdh, et kem pour ML-KEM en 3.5+)
openssl speed -seconds 3 ecdhx25519 ecdhp256
# Handshakes par seconde contre un serveur réel
openssl s_time -connect www.example.com:443 -new -time 10        # sessions complètes
openssl s_time -connect www.example.com:443 -reuse -time 10      # avec reprise de session
Constat typiqueInterprétationAction
rsa2048 sign/s ≈ 10 à 20 fois plus lent que ecdsap256 sign/sLe handshake RSA coûte cher en CPU serveurCertificat ECDSA (ou double RSA + ECDSA)
AES-GCM > plusieurs Go/s par cœurAES-NI actifRien à faire ; le chiffrement de données n'est pas le goulot
AES-GCM lent, ChaCha20 plus rapideCPU sans accélération AES (ARM d'entrée de gamme, VM avec CPU masqué)Vérifier le modèle de CPU exposé par l'hyperviseur (flag aes)
-reuse >> -newLa reprise de session fonctionnePartager les clés de tickets entre nœuds d'un cluster

14. OpenSSL 3 : providers, legacy, FIPS

14.1 Les providers

ProviderContenuChargé par défaut
defaultAlgorithmes modernesOui
legacyMD4, RC2, RC4, DES, Blowfish, CAST, IDEA, SEED, Whirlpool...Non
fipsModule validé FIPS 140 (sous-ensemble approuvé)Non (activation explicite)
baseEncodeurs/décodeurs sans algorithmesAvec fips
tiers (pkcs11, oqsprovider, tpm2)HSM, TPM, algorithmes expérimentauxNon
# Activer ponctuellement
openssl list -providers
openssl list -cipher-algorithms -provider legacy -provider default | grep -i rc2
openssl pkcs12 -in ancien.pfx -provider legacy -provider default -info -noout

# Répertoire des modules et configuration
openssl version -m          # MODULESDIR (legacy.so, fips.so)
export OPENSSL_MODULES=/usr/lib/x86_64-linux-gnu/ossl-modules
export OPENSSL_CONF=/etc/ssl/openssl-legacy.cnf
# openssl-legacy.cnf : default + legacy actifs pour une application
openssl_conf = openssl_init

[ openssl_init ]
providers = provider_sect

[ provider_sect ]
default = default_sect
legacy  = legacy_sect

[ default_sect ]
activate = 1

[ legacy_sect ]
activate = 1
Ne pas activer legacy globalement : modifiez un fichier de configuration dédié et pointez-y une application via OPENSSL_CONF, plutôt que /etc/ssl/openssl.cnf. Activer le provider legacy pour tout le système réintroduit RC4 et DES partout.

14.2 Niveaux de sécurité (SECLEVEL)

NiveauExigences principalesUsage
0Aucune restrictionTests de compatibilité uniquement
1 (défaut amont)RSA/DH ≥ 1024, ≥ 80 bits ; en OpenSSL 3, plus de SHA-1 en signature ni de TLS < 1.2Défaut
2RSA/DH ≥ 2048, ≥ 112 bitsDéfaut sur Debian/Ubuntu, RHEL (politiques crypto)
3RSA/DH ≥ 3072, ≥ 128 bits, pas de reprise de session sans PFSEnvironnements durcis

Symptômes typiques : ca md too weak (certificat signé en SHA-1), ee key too small (RSA 1024), dh key too small. Sur RHEL/Fedora, update-crypto-policies --show donne la politique système (DEFAULT, LEGACY, FUTURE, FIPS) qui pilote OpenSSL, GnuTLS, NSS et Java.

14.3 FIPS

# OpenSSL compilé depuis les sources avec enable-fips : installer le module
openssl fipsinstall -out /usr/local/ssl/fipsmodule.cnf -module /usr/local/lib64/ossl-modules/fips.so

# openssl.cnf : inclure le module et l'activer
#   .include /usr/local/ssl/fipsmodule.cnf
#   [ provider_sect ]
#   fips = fips_sect
#   base = base_sect
#   [ base_sect ]
#   activate = 1
#   [ algorithm_sect ]
#   default_properties = fips=yes

openssl list -providers                     # doit afficher "fips" actif
openssl md5 /etc/hostname                   # doit échouer en mode FIPS strict
Distributions : sur RHEL et dérivées, le mode FIPS est une configuration du système entier (activé à l'installation ou par l'outil fourni selon la version), utilisant le module certifié de la distribution : ne pas recompiler OpenSSL soi-même dans ce cas. Seule une version précise du module, listée dans le certificat CMVP, est « validée FIPS ».

14.4 Changements de comportement 1.1.1 → 3.x

Sujet1.1.13.x
openssl rsa en sortiePKCS#1 (BEGIN RSA PRIVATE KEY)PKCS#8 (BEGIN PRIVATE KEY) ; -traditional pour PKCS#1
-nodesStandardDéprécié au profit de -noenc (toujours accepté)
PKCS#12 exportRC2-40 / 3DES, MAC SHA-1AES-256-CBC, PBKDF2, MAC SHA-256
RC2, RC4, DES, MD4DisponiblesProvider legacy
TLS 1.0 / 1.1DisponiblesSeulement avec @SECLEVEL=0
Renegociation non sécuriséeTolérée côté clientRefusée (unsafe legacy renegotiation disabled) : option UnsafeLegacyServerConnect pour un vieux serveur
EnginesMécanisme standardDépréciés, remplacés par les providers

15. Équivalents Windows : certutil et PowerShell

BesoinOpenSSLWindows natif
Afficher un certificatopenssl x509 -text -noout -in c.pemcertutil -dump c.cer
Vérifier chaîne + révocationopenssl verify -crl_check ...certutil -verify -urlfetch c.cer
Hash d'un fichieropenssl dgst -sha256 fGet-FileHash f -Algorithm SHA256 / certutil -hashfile f SHA256
DER → PEMopenssl x509 -inform DER ...certutil -encode c.der c.pem
PEM → DERopenssl x509 -outform DER ...certutil -decode c.pem c.der
Créer une CSRopenssl req -new ...certreq -new req.inf req.csr
Auto-signéopenssl req -x509 ...New-SelfSignedCertificate
Exporter PFXopenssl pkcs12 -export ...Export-PfxCertificate
Importer PFX-Import-PfxCertificate
Aléatoireopenssl rand -hex 32[Security.Cryptography.RandomNumberGenerator]::GetBytes(32) (PowerShell 7)
Tester un serveur TLSopenssl s_clientScript SslStream ci-dessous

15.1 CSR avec certreq (clé générée dans le magasin machine)

; req.inf
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=www.example.com"
KeyAlgorithm = RSA
KeyLength = 3072
HashAlgorithm = SHA256
Exportable = FALSE
MachineKeySet = TRUE
ProviderName = "Microsoft Software Key Storage Provider"
RequestType = PKCS10
KeyUsage = 0xa0

[EnhancedKeyUsageExtension]
OID = 1.3.6.1.5.5.7.3.1

[Extensions]
2.5.29.17 = "{text}"
_continue_ = "dns=www.example.com&"
_continue_ = "dns=example.com"
certreq -new req.inf www.csr
# ... soumission à l'AC (ou ADCS : certreq -submit -config "srv-ca\Example Issuing CA 01" -attrib "CertificateTemplate:EX-ServeurWeb" www.csr www.cer)
certreq -accept www.cer          # associe le certificat à la clé privée en attente

# Certificat sans clé après import : réassocier (sur la machine qui a généré la CSR)
certutil -repairstore my "<numéro_de_série>"

15.2 PowerShell

# Auto-signé ECDSA de lab, 90 jours
New-SelfSignedCertificate -DnsName "lab.example.com","192.0.2.10" -CertStoreLocation Cert:\LocalMachine\My `
    -KeyAlgorithm ECDSA_nistP256 -HashAlgorithm SHA256 -NotAfter (Get-Date).AddDays(90) -KeyExportPolicy NonExportable

# Export / import PFX (mot de passe saisi, jamais en clair dans le script)
$pwd = Read-Host -AsSecureString "Mot de passe PFX"
Export-PfxCertificate -Cert Cert:\LocalMachine\My\<empreinte> -FilePath C:\temp\srv.pfx -Password $pwd -ChainOption BuildChain
Import-PfxCertificate -FilePath C:\temp\srv.pfx -CertStoreLocation Cert:\LocalMachine\My -Password $pwd

# Exporter le certificat (sans clé) en PEM
$c = Get-Item Cert:\LocalMachine\My\<empreinte>
"-----BEGIN CERTIFICATE-----`n" + [Convert]::ToBase64String($c.RawData, 'InsertLineBreaks') + "`n-----END CERTIFICATE-----" |
    Out-File -FilePath C:\temp\srv.pem -Encoding ascii

# PowerShell 7 : charger une paire PEM (cert + clé)
$x = [System.Security.Cryptography.X509Certificates.X509Certificate2]::CreateFromPemFile("C:\temp\srv.crt", "C:\temp\srv.key")
$x.HasPrivateKey
# PowerShell 7 : équivalent minimal de s_client (protocole, suite, certificat)
$h = "www.example.com"
$tcp = [System.Net.Sockets.TcpClient]::new($h, 443)
# Callback qui accepte tout : INSPECTION uniquement, jamais dans un vrai client
$ssl = [System.Net.Security.SslStream]::new($tcp.GetStream(), $false, { $true })
$ssl.AuthenticateAsClient($h)
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$ssl.RemoteCertificate
[pscustomobject]@{
    Protocole = $ssl.SslProtocol
    Suite     = $ssl.NegotiatedCipherSuite
    Sujet     = $cert.Subject
    Emetteur  = $cert.Issuer
    Expire    = $cert.NotAfter
    Empreinte = $cert.Thumbprint
}
$ssl.Dispose(); $tcp.Dispose()

# Validation de chaîne côté Windows (CryptoAPI, avec révocation)
$chain = [System.Security.Cryptography.X509Certificates.X509Chain]::new()
$chain.ChainPolicy.RevocationMode = 'Online'
$chain.Build($cert); $chain.ChainStatus | Format-Table Status, StatusInformation
Protocoles Windows (SChannel) : les protocoles et suites acceptés par IIS, RDP ou WinRM sont réglés dans le registre SChannel et par Get-TlsCipherSuite / Disable-TlsCipherSuite, pas par OpenSSL. Voir Windows Server et Sécurité PowerShell.

16. Pièges et tableau récapitulatif

16.1 Pièges fréquents

SymptômeCauseCorrection
unable to load certificate / no start lineFichier DER lu comme PEM, ou BOM UTF-8 en début de fichier (édité sous Windows, Set-Content -Encoding UTF8 de PowerShell 5)-inform DER ; retirer le BOM : sed -i '1s/^\xEF\xBB\xBF//' f.pem ; en PowerShell 5 écrire en ascii
Erreurs aléatoires de parsing, chaîne tronquéeFins de ligne CRLF ou deux blocs collés (-----END CERTIFICATE----------BEGIN) après concaténationsed -i 's/\r$//' f.pem ; vérifier que chaque fichier se termine par un saut de ligne avant cat
Navigateur OK, clients API KOOrdre ou contenu de la chaîne : feuille absente en tête, intermédiaire manquant ou erronéOrdre : feuille, intermédiaire(s) du plus bas au plus haut ; pas de racine
key values mismatch (nginx), SSL_CTX_use_PrivateKeyClé et certificat non appariésComparer les empreintes de clé publique (section 9)
Import PFX refusé sous un ancien Windows / Java : mot de passe incorrectPFX OpenSSL 3 (AES/PBKDF2) non supportéRéexporter en -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1
unsupported ... RC2-40-CBC à la lecture d'un PFXVieux PFX, algorithme dans le provider legacy-legacy
PFX accepté par un outil, refusé par un autreMot de passe vide vs absence de mot de passeToujours poser un mot de passe réel
bad decrypt avec enc -dOptions différentes (-pbkdf2, -iter, -md : défaut MD5 avant 1.1.0, SHA-256 après)Rejouer avec les options exactes du chiffrement ; essayer -md md5 pour un fichier ancien
Firefox : SEC_ERROR_REUSED_ISSUER_AND_SERIALNuméro de série réutilisé par une AC de test (-set_serial 01)-CAcreateserial ou série aléatoire ; supprimer l'exception dans le navigateur
Certificat valide 30 jours au lieu d'un an-days oubliéToujours préciser -days
Extensions absentes du certificat signéx509 -req ignore les extensions de la CSR-extfile/-extensions ou -copy_extensions copyall (en connaissance de cause)
Mot de passe visible dans ps / l'historique-passin pass:...file:, env:, fd:
Clé refusée par un vieux logiciel (expecting: ANY PRIVATE KEY, « format non supporté »)PKCS#8 attendu en PKCS#1 ou inversementopenssl rsa -traditional / openssl pkey
Connexion vers une IP sans SNI : mauvais certificatPas de -servername (ou serveur sans vhost par défaut)Toujours -servername ; tester -noservername pour voir le certificat par défaut
s_client reste bloquéAttente sur stdinRediriger </dev/null (ou -ign_eof / timeout 10)

16.2 Tableau récapitulatif

BesoinCommande
Clé ECDSA P-256openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out k.key
Clé RSA 3072openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out k.key
Clé Ed25519openssl genpkey -algorithm ED25519 -out k.key
CSR avec SANopenssl req -new -key k.key -subj "/CN=a.example.com" -addext "subjectAltName=DNS:a.example.com" -out r.csr
Auto-signé de labopenssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc -days 30 -keyout k -out c -subj "/CN=x" -addext "subjectAltName=DNS:x"
Signer une CSRopenssl x509 -req -in r.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 90 -extfile e.cnf -extensions v3_server -out c.crt
Lire un certificatopenssl x509 -in c.pem -noout -subject -issuer -dates -ext subjectAltName
Lire une CSRopenssl req -in r.csr -noout -text -verify
Chaîne d'un serveuropenssl s_client -connect h:443 -servername h -showcerts </dev/null
Expiration d'un serveuropenssl s_client -connect h:443 -servername h </dev/null 2>/dev/null | openssl x509 -noout -enddate
Expire sous N jours ?openssl x509 -in c.pem -noout -checkend $((N*86400))
Vérifier une chaîneopenssl verify -CAfile root.pem -untrusted inter.pem leaf.pem
Appariementopenssl pkey -in k -pubout -outform DER | openssl dgst -sha256 vs openssl x509 -in c -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256
PEM → DERopenssl x509 -in c.pem -outform DER -out c.der
P7B → PEMopenssl pkcs7 -in c.p7b -print_certs -out c.pem
PEM → PFXopenssl pkcs12 -export -inkey k -in c -certfile chain.pem -out f.pfx
PFX → PEMopenssl pkcs12 -in f.pfx -noenc -out all.pem (-legacy si ancien)
PFX → JKSkeytool -importkeystore -srckeystore f.p12 -srcstoretype PKCS12 -destkeystore k.jks -deststoretype JKS
Tester TLS 1.2 + suiteopenssl s_client -connect h:443 -tls1_2 -cipher ECDHE-RSA-AES128-GCM-SHA256
Tester TLS 1.3 + suiteopenssl s_client -connect h:443 -tls1_3 -ciphersuites TLS_AES_256_GCM_SHA384
STARTTLS SMTPopenssl s_client -connect h:587 -starttls smtp -crlf
Chiffrer un fichieropenssl enc -aes-256-cbc -salt -pbkdf2 -iter 600000 -in f -out f.enc
Signer / vérifieropenssl dgst -sha256 -sign k -out s f / openssl dgst -sha256 -verify pub -signature s f
HMACopenssl dgst -sha256 -hmac "$KEY" f
Aléatoireopenssl rand -hex 32
Benchmarkopenssl speed -evp aes-256-gcm ; openssl speed ecdsap256 rsa2048
Providersopenssl list -providers