tools

OpenSSL: Tools for TLS, Certificates, and Encryption

OpenSSL: Tools for TLS, Certificates, and Encryption

OpenSSL for TLS, X.509, RSA, and ECDSA certificates, PKI, s_client, and encryption. Practical commands for Linux, Windows, troubleshooting, and pentesting.

  • Posted on 2026-09-28
  • Reading time: 13 min

OpenSSL: The Ultimate Guide — Certificates, TLS, Encryption, and Security #

OpenSSL is the world's most widely used cryptographic library. It powers web server TLS connections, generates certificates for enterprise PKI, diagnoses handshake problems at 3 a.m., and converts between every certificate format ever invented. If you work with certificates, keys, or encrypted connections, you're using OpenSSL—often without knowing it.

This guide covers everything from an internal understanding of the TLS protocol to practical commands for every scenario—certificates, remote inspection, file encryption, private PKI, and offensive use in authorized contexts.


Versions and current status #

OpenSSL 3.5 LTS is the recommended production release, supported until April 2030. OpenSSL 4.0, released on April 14, 2026, is a feature release with breaking changes.

VersionStatusNote
4.0.xCurrent (2026)Breaking changes — deprecated algorithms disabled by default
3.5.x LTSRecommended buildingSupported until April 2030
3.0.xSecurity-onlyEOL September 2026
1.1.1☠️ EOLEnd of life September 2023 — migrate immediately
bash
# Verifica versione installata
openssl version -a
# OpenSSL 3.5.0 8 Apr 2025 (Library: OpenSSL 3.5.0 8 Apr 2025)

# Lista tutti i subcomandi disponibili
openssl help

# Installa su Debian/Ubuntu (3.x)
sudo apt install openssl libssl-dev

# macOS — LibreSSL di default (compatibile ma diverso), installa OpenSSL reale
brew install openssl
export PATH="/opt/homebrew/opt/openssl/bin:$PATH"

OpenSSL 4.0 major breaking change: Note: -ssl3, -tls1, -tls1_1 have been removed in OpenSSL 4.0, and algorithms like MD5, RC4, and DES are disabled by default. If you're working with legacy files (old PKCS#12, MD5 certificates), add -legacy -provider default.


How TLS works internally #

Before using the commands, understanding the TLS flow makes everything clearer.

The TLS handshake step by step #

text
[CLIENT]                              [SERVER]
    │                                     │
    │──── ClientHello ───────────────────►│
    │     (versioni TLS, cipher suites,   │
    │      estensioni, random client)     │
    │                                     │
    │◄─── ServerHello ────────────────────│
    │     (versione scelta, cipher scelto,│
    │      random server, session ID)     │
    │                                     │
    │◄─── Certificate ────────────────────│
    │     (certificato X.509 del server)  │
    │                                     │
    │◄─── ServerHelloDone ────────────────│
    │                                     │
    │──── ClientKeyExchange ─────────────►│
    │     (chiave pre-master cifrata con  │
    │      public key del server)         │
    │                                     │
    │══════ Derivazione chiave sessione ══│
    │      (entrambi calcolano la stessa  │
    │       session key dai random)       │
    │                                     │
    │──── ChangeCipherSpec ──────────────►│
    │──── Finished (cifrato) ────────────►│
    │◄─── ChangeCipherSpec ───────────────│
    │◄─── Finished (cifrato) ─────────────│
    │                                     │
    │══════ Trasferimento dati cifrato ═══│

In TLS 1.3 (the current default) the flow is shorter — only 1 round-trip instead of 2, and the key exchange always uses perfect forward secrecy.

The chain of trust — why the browser trusts #

text
Root CA (auto-firmata, nel trust store del OS/browser)
    └── Intermediate CA (firmata dalla Root)
            └── Certificato server (firmato dall'Intermediate)
                    └── Il tuo dominio

The browser trusts the server's certificate because it can trace the chain back to a Root CA already in its trust store (installed with the operating system). If the chain is incomplete or a CA is not trusted, the browser displays the error.


Certificate and key formats #

Understanding formats prevents half the errors. Certificate and key files exist in multiple formats—same information, different representations.

FormatExtensionCodingTypical content
PEM.pem, .crt, .cer, .keyBase64 with headerCert, key, CSR — the most common on Linux
THE.der, .cerBinarySame as PEM but binary — Java, Windows
PKCS # 12.pfx, .p12Encrypted binaryCert + private key + chain in one file
PKCS # 8.key, .pemPEM or DERPrivate key with metadata of the type
PKCS # 7.p7b, .p7cPEM or DERCertificates only (no key), chain
bash
# Riconosci il tipo di file PEM dall'header
head -1 file.pem
# -----BEGIN CERTIFICATE-----         → certificato X.509
# -----BEGIN PRIVATE KEY-----         → chiave privata PKCS#8
# -----BEGIN RSA PRIVATE KEY-----     → chiave RSA legacy (PKCS#1)
# -----BEGIN EC PRIVATE KEY-----      → chiave EC legacy
# -----BEGIN CERTIFICATE REQUEST----- → CSR

# Ispeziona qualsiasi PEM senza saperne il tipo
openssl asn1parse -in file.pem

Generating private keys #

The private key is the absolute secret. It is never sent via email, uploaded to third-party servers, or placed in a repository.

RSA #

RSA is the historical standard. RSA 2048-bit is the minimum accepted by all CAs. RSA 4096-bit offers a greater safety margin at the cost of slightly slower TLS handshakes.

bash
# RSA 4096 — buon bilanciamento sicurezza/compatibilità
openssl genrsa -out private.key 4096

# Con passphrase AES-256 (protegge la chiave se il file viene rubato)
openssl genrsa -aes256 -out private_enc.key 4096
# Verrà chiesta la passphrase — sceglila lunga e salvala

# Rimuovi passphrase da una chiave (necessario per web server che si avviano automaticamente)
openssl rsa -in private_enc.key -out private_nopass.key
# Inserisci la passphrase quando richiesta

# Ispeziona la chiave — modulus, exponent, ecc.
openssl rsa -in private.key -noout -text

# Estrai solo la chiave pubblica dalla privata
openssl rsa -in private.key -pubout -out public.key

# Verifica integrità chiave
openssl rsa -in private.key -check -noout
# RSA key ok

ECDSA and ED25519 — the present and the future #

ECDSA P-256 provides security equivalent to RSA 3072 with 3x faster handshakes. Use RSA 4096 only if you need compatibility with very old clients.

bash
# ECDSA con curva P-256 (NIST) — standard enterprise
openssl ecparam -name prime256v1 -genkey -noout -out ec_private.key

# ECDSA con curva P-384 (più sicura, leggermente più lenta)
openssl ecparam -name secp384r1 -genkey -noout -out ec_p384.key

# ED25519 — moderna, veloce, resistente ad alcune vulnerabilità side-channel
openssl genpkey -algorithm ED25519 -out ed25519_private.key

# Lista tutte le curve ellittiche supportate
openssl ecparam -list_curves

# Ispeziona chiave EC
openssl ec -in ec_private.key -noout -text

X.509 Certificates and CSRs #

CSR — Certificate Signing Request #

The CSR is the certificate signing request you send to a CA. It contains your public key and information about your domain/organization. The CA verifies it and returns the signed certificate to you.

bash
# Genera CSR dalla chiave privata esistente
openssl req -new -key private.key -out server.csr

# Genera chiave E CSR in un solo comando
openssl req -new -newkey rsa:4096 -nodes -keyout private.key -out server.csr

# CSR senza prompt interattivo — fornisci tutto via -subj
openssl req -new -key private.key -out server.csr \
  -subj "/C=IT/ST=Campania/L=Napoli/O=HackITA/OU=Security/CN=hackita.it"

# CSR con SAN (Subject Alternative Names) — obbligatorio per Chrome/Firefox moderni
# Crea file di configurazione
cat > san.cnf << EOF
[req]
default_bits = 4096
prompt = no
distinguished_name = dn
req_extensions = v3_req

[dn]
C=IT
ST=Campania
L=Napoli
O=HackITA
CN=hackita.it

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = hackita.it
DNS.2 = www.hackita.it
DNS.3 = api.hackita.it
EOF

openssl req -new -key private.key -out server_san.csr -config san.cnf

# Ispeziona la CSR — verifica il contenuto prima di mandarla
openssl req -in server.csr -noout -text
openssl req -in server.csr -noout -subject

Self-signed certificate (for testing/laboratory) #

A self-signed certificate is signed by the same key it certifies. The browser rejects it in production (because there's no trusted CA in the chain), but it's useful for internal testing.

bash
# Self-signed valido 365 giorni
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
  -subj "/CN=localhost"

# Self-signed con SAN — necessario per Chrome/Firefox anche in lab
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
  -days 3650 -nodes \
  -subj "/CN=myserver.local" \
  -addext "subjectAltName=DNS:myserver.local,DNS:localhost,IP:127.0.0.1"

# Verifica il certificato generato
openssl x509 -in cert.pem -noout -text

Certificate inspection #

Local files #

bash
# Mostra tutto il contenuto del certificato
openssl x509 -in cert.pem -noout -text

# Campi specifici — più veloci per script
openssl x509 -in cert.pem -noout -subject        # chi è
openssl x509 -in cert.pem -noout -issuer         # chi l'ha firmato
openssl x509 -in cert.pem -noout -dates          # validità
openssl x509 -in cert.pem -noout -serial         # numero seriale
openssl x509 -in cert.pem -noout -fingerprint -sha256  # fingerprint SHA256

# SAN — Subject Alternative Names (domini coperti)
openssl x509 -in cert.pem -noout -ext subjectAltName

# KeyUsage — cosa può fare il certificato
openssl x509 -in cert.pem -noout -ext keyUsage
openssl x509 -in cert.pem -noout -ext extendedKeyUsage

# Scade tra X giorni? (exit 0 = ancora valido)
openssl x509 -in cert.pem -noout -checkend 2592000   # 30 giorni
openssl x509 -in cert.pem -noout -checkend 0          # è già scaduto?

# Verifica che chiave e certificato siano la stessa coppia
openssl x509 -noout -modulus -in cert.pem | md5sum
openssl rsa  -noout -modulus -in private.key | md5sum
# Se i due MD5 coincidono → cert e chiave sono la stessa coppia

Remote Server — s_client #

s_client It's one of OpenSSL's most powerful tools. It connects you to any TLS service and displays everything: certificate, chain, negotiated cipher, and protocol version.

bash
# Connessione base — mostra tutta la handshake
openssl s_client -connect example.com:443

# Con SNI (Server Name Indication) — necessario per host con più certificati
openssl s_client -connect example.com:443 -servername example.com

# Solo il certificato del server — sopprime l'output della handshake
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
  openssl x509 -noout -text

# Date di scadenza del certificato remote
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
  openssl x509 -noout -dates

# SAN del certificato remoto
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
  openssl x509 -noout -ext subjectAltName

# Versione TLS e cipher negoziato
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
  grep -E "^(Protocol|Cipher)"

# Testa se il server supporta TLS 1.3
openssl s_client -connect example.com:443 -tls1_3 2>&1 | grep -E "Protocol|error"

# Testa TLS 1.2
openssl s_client -connect example.com:443 -tls1_2 2>&1 | grep Protocol

# Testa cipher suite specifica
openssl s_client -connect example.com:443 -cipher "ECDHE-RSA-AES256-GCM-SHA384"

# Mostra tutta la chain di certificati (root + intermediate + server)
openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null

# STARTTLS — per SMTP, IMAP, POP3, FTP che upgrade da plain a TLS
openssl s_client -connect mail.example.com:25  -starttls smtp
openssl s_client -connect mail.example.com:143 -starttls imap
openssl s_client -connect mail.example.com:110 -starttls pop3
openssl s_client -connect ftp.example.com:21   -starttls ftp

# Fingerprint SHA256 del certificato remoto
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
  openssl x509 -noout -fingerprint -sha256

Always note -servername: Without it, on shared hosts (CDN, shared hosting) you may receive the wrong certificate.


Build your own private CA #

A private PKI is essential for enterprise environments, pentesting labs, and internal certificates. It allows you to sign your certificates without paying for a public CA.

bash
# === STEP 1: Crea la Root CA ===
mkdir -p ca/{certs,private,newcerts}
chmod 700 ca/private
echo 01 > ca/serial
touch ca/index.txt

# Genera chiave Root CA (4096 bit, cifrata — proteggi questa chiave sopra ogni altra cosa)
openssl genrsa -aes256 -out ca/private/ca.key 4096
chmod 400 ca/private/ca.key

# Genera certificato Root CA — valido 10 anni
openssl req -new -x509 -days 3650 \
  -key ca/private/ca.key \
  -out ca/certs/ca.crt \
  -subj "/C=IT/ST=Campania/O=HackITA Lab CA/CN=HackITA Root CA"

# Verifica la Root CA
openssl x509 -in ca/certs/ca.crt -noout -text

# === STEP 2: Emetti certificato per un server ===

# Genera chiave per il server
openssl genrsa -out server.key 4096

# Genera CSR per il server
openssl req -new -key server.key -out server.csr \
  -subj "/C=IT/O=HackITA/CN=lab.hackita.it"

# Firma la CSR con la nostra Root CA
# Dobbiamo aggiungere i SAN durante la firma
cat > server_ext.cnf << EOF
[v3_req]
subjectAltName = DNS:lab.hackita.it, DNS:*.hackita.it, IP:10.10.10.1
EOF

openssl x509 -req -days 365 \
  -in server.csr \
  -CA ca/certs/ca.crt \
  -CAkey ca/private/ca.key \
  -CAcreateserial \
  -out server.crt \
  -extfile server_ext.cnf \
  -extensions v3_req

# Verifica che il certificato sia firmato correttamente dalla CA
openssl verify -CAfile ca/certs/ca.crt server.crt
# server.crt: OK

# === STEP 3: Installa la Root CA nel sistema ===
# Su Debian/Ubuntu
sudo cp ca/certs/ca.crt /usr/local/share/ca-certificates/hackita-lab-ca.crt
sudo update-ca-certificates

# Su Kali/RedHat/CentOS
sudo cp ca/certs/ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract

Converting between formats #

Format switching is the most common operation with OpenSSL — each application wants its own.

PEM ↔ DER #

bash
# PEM → DER (da testo Base64 a binario)
openssl x509 -in cert.pem -outform DER -out cert.der
openssl rsa   -in key.pem  -outform DER -out key.der

# DER → PEM (da binario a Base64)
openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem
openssl rsa   -in key.der  -inform DER -outform PEM -out key.pem

PEM ↔ PKCS#12 (.pfx/.p12) #

PKCS#12 bundles the certificate, private key, and chain into a single encrypted file. It's used by Windows, Java, and many applications that want everything in one file.

bash
# PEM → PKCS#12 (cert + chiave + eventuale chain)
openssl pkcs12 -export \
  -in cert.pem \
  -inkey private.key \
  -certfile ca.crt \
  -out bundle.pfx \
  -name "mio-certificato"

# PKCS#12 → PEM (estrai tutti i componenti)
openssl pkcs12 -in bundle.pfx -out bundle.pem -nodes
# -nodes = no passphrase sulla chiave estratta

# Estrai solo il certificato dal PKCS#12
openssl pkcs12 -in bundle.pfx -nokeys -out cert_only.pem

# Estrai solo la chiave privata
openssl pkcs12 -in bundle.pfx -nocerts -nodes -out key_only.pem

# File .pfx legacy (OpenSSL 3.x+) — aggiungere -legacy per vecchi export Windows
openssl pkcs12 -in old_export.pfx -out bundle.pem -nodes -legacy

PKCS#1 ↔ PKCS#8 #

bash
# RSA PKCS#1 → PKCS#8 (formato moderno)
openssl pkcs8 -topk8 -inform PEM -in rsa_pkcs1.key -out rsa_pkcs8.key -nocrypt

# PKCS#8 → PKCS#1
openssl rsa -in rsa_pkcs8.key -out rsa_pkcs1.key

File encryption — encryption/decryption #

OpenSSL can encrypt and decrypt arbitrary files. Useful for transferring sensitive files or protecting backups.

bash
# Cifra file con AES-256-CBC (password-based)
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 \
  -in file_originale.txt -out file_cifrato.enc
# Verrà chiesta la password

# Decifra
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -d \
  -in file_cifrato.enc -out file_recuperato.txt

# Con chiave esplicita in Base64 (per scripting)
KEY=$(openssl rand -hex 32)    # 256-bit key
IV=$(openssl rand -hex 16)     # 128-bit IV
openssl enc -aes-256-cbc -K $KEY -iv $IV -in file.txt -out file.enc

# Cifra con chiave pubblica RSA (per destinatario specifico)
openssl rsautl -encrypt -inkey public.key -pubin -in secret.txt -out secret.enc

# Decifra con chiave privata RSA
openssl rsautl -decrypt -inkey private.key -in secret.enc -out secret_dec.txt

Hashing and integrity verification #

bash
# Hash MD5, SHA1, SHA256, SHA512 di un file
openssl dgst -md5    file.bin
openssl dgst -sha1   file.bin
openssl dgst -sha256 file.bin
openssl dgst -sha512 file.bin

# Solo l'hash (senza il prefisso "MD5(file.bin)=")
openssl dgst -sha256 -r file.bin | awk '{print $1}'

# HMAC — hash con chiave segreta (per verifica autenticata)
openssl dgst -sha256 -hmac "chiavesegreta" file.bin

# Firma digitale — firma un file con la tua chiave privata
openssl dgst -sha256 -sign private.key -out firma.sig file.bin

# Verifica firma — verifica con la chiave pubblica del mittente
openssl dgst -sha256 -verify public.key -signature firma.sig file.bin
# Verified OK

# Genera password hash (per /etc/shadow o htpasswd)
openssl passwd -6 "mypassword"   # SHA-512 (crypt)
openssl passwd -apr1 "mypassword"  # MD5-APR (Apache)

# Genera bytes casuali crittograficamente sicuri
openssl rand -hex 32      # 32 byte in hex → chiave 256-bit
openssl rand -base64 48   # 48 byte in base64 → password random

OpenSSL in security — authorized offensive use #

OpenSSL is also an essential tool in authorized attack contexts—TLS inspection, certificate extraction, and PKI analysis of a target organization.

Listing a target's certificates #

Before a web pentest, certificate analysis often reveals valuable information: internal departments, subdomains, software stack.

bash
TARGET="target.com"

# Recupera e analizza il certificato
echo | openssl s_client -connect $TARGET:443 -servername $TARGET 2>/dev/null | \
  openssl x509 -noout -text | head -80

# Estrai SAN — spesso contiene subdomain interni
echo | openssl s_client -connect $TARGET:443 -servername $TARGET 2>/dev/null | \
  openssl x509 -noout -ext subjectAltName

# Certificate Transparency — tutti i certificati emessi per un dominio
# Usa crt.sh (API pubblica, non richiede OpenSSL ma complementare)
curl -s "https://crt.sh/?q=%25.$TARGET&output=json" | python3 -m json.tool | \
  grep '"name_value"' | sort -u

# Testa quali versioni TLS supporta il server
for VER in -tls1_2 -tls1_3; do
  result=$(echo | openssl s_client -connect $TARGET:443 -servername $TARGET $VER 2>&1 | grep "Protocol")
  echo "$VER: $result"
done

# Lista cipher suites accettate (brute-force delle cipher)
for CIPHER in $(openssl ciphers 'ALL:eNULL' | tr ':' ' '); do
  result=$(echo | openssl s_client -connect $TARGET:443 -cipher $CIPHER 2>&1)
  if echo "$result" | grep -q "Cipher is"; then
    echo "[+] $CIPHER"
  fi
done

ADCS Certificates — Use in Active Directory Environments #

In Windows environments with ADCS ( Active Directory Certificate Services ), OpenSSL is used to handle certificates generated during ESC8/ESC11 attacks.

bash
# Converti certificato .pem ricevuto da ntlmrelayx in .pfx
openssl pkcs12 -export -in dc01.crt -inkey dc01.key -out dc01.pfx -passout pass:

# Estrai hash NT dal certificato .pfx (via certipy o Rubeus)
# Vedi /articoli/ntlmrelayx e /articoli/golden-ticket

# Ispeziona un certificato ADCS — controlla OID di Extended Key Usage
openssl x509 -in adcs_cert.pem -noout -ext extendedKeyUsage
# 1.3.6.1.5.5.7.3.2 = Client Authentication
# 1.3.6.1.4.1.311.20.2.2 = Smart Card Logon
# 1.3.6.1.5.5.7.3.1 = Server Authentication

Cipher suite analysis and weaknesses #

bash
# Controlla se il server supporta ancora cipher deboli
WEAK_CIPHERS="RC4-SHA:RC4-MD5:DES-CBC-SHA:DES-CBC3-SHA:NULL-SHA"
echo | openssl s_client -connect target.com:443 -cipher $WEAK_CIPHERS 2>&1 | \
  grep -E "Cipher|error"

# Lista cipher disponibili per categoria
openssl ciphers -v 'HIGH:!aNULL:!MD5'     # solo cipher forti
openssl ciphers -v 'LOW:!aNULL:!eNULL'    # cipher deboli
openssl ciphers -v 'NULL'                  # cipher senza cifratura

# Verifica se il server è vulnerabile a renegotiation attacks
echo | openssl s_client -connect target.com:443 2>&1 | grep "Secure Renegotiation"
# "Secure Renegotiation IS supported" → ok
# "Secure Renegotiation IS NOT supported" → vulnerabile

Complete PKI for pentest labs #

A complete setup to simulate a realistic PKI infrastructure in a lab:

bash
#!/bin/bash
# setup_lab_pki.sh — crea CA + cert server + cert client per lab

DOMAIN="lab.local"
mkdir -p pki/{ca,server,client}/{certs,private}

# Root CA
openssl genrsa -out pki/ca/private/ca.key 4096
openssl req -x509 -new -nodes -key pki/ca/private/ca.key \
  -days 3650 -out pki/ca/certs/ca.crt \
  -subj "/CN=$DOMAIN Root CA/O=Lab CA"

# Server cert (es. per web server o C2)
openssl genrsa -out pki/server/private/server.key 4096
openssl req -new -key pki/server/private/server.key \
  -out pki/server/server.csr \
  -subj "/CN=server.$DOMAIN"
openssl x509 -req -days 365 \
  -in pki/server/server.csr \
  -CA pki/ca/certs/ca.crt \
  -CAkey pki/ca/private/ca.key \
  -CAcreateserial \
  -out pki/server/certs/server.crt \
  -extfile <(printf "subjectAltName=DNS:server.$DOMAIN,DNS:*.server.$DOMAIN")

# Client cert (mutual TLS — mTLS per C2 come Sliver)
openssl genrsa -out pki/client/private/client.key 4096
openssl req -new -key pki/client/private/client.key \
  -out pki/client/client.csr \
  -subj "/CN=operator.$DOMAIN"
openssl x509 -req -days 365 \
  -in pki/client/client.csr \
  -CA pki/ca/certs/ca.crt \
  -CAkey pki/ca/private/ca.key \
  -CAcreateserial \
  -out pki/client/certs/client.crt

echo "[+] PKI creata in ./pki/"
echo "    CA cert:      pki/ca/certs/ca.crt"
echo "    Server cert:  pki/server/certs/server.crt"
echo "    Client cert:  pki/client/certs/client.crt"

Troubleshooting — Common Mistakes and Solutions #

ErrorCauseSolution
unable to load Private KeyEncrypted key, missing passphraseAdd -passin pass:PASSWORD
PEM_read_bio_X509: no start lineFile is not valid PEM or is DERTry it now -inform DER or re-download the file
SSL handshake has read 0 bytesServer is not responding on that port or does not speak TLSCheck port, use -starttls if necessary
depth=0 ... error 18: self signedSelf-signed non-trusted certificateNormal for self-signed; in test uses -noverify
SSL alert number 40Server rejected TLS version or cipherTry it now -tls1_2 o -tls1_3 explicitly
Unsupported Algorithm (.pfx legacy)OpenSSL 3.x disables legacy algorithmsAdd -legacy -provider default
unable to get local issuer certificateIncomplete chainSmall Parts -CAfile ca_bundle.crt
certificate has expiredCertificate expiredRenew your certificate
wrong number of argumentsSyntax changed between versionsCheck it out openssl COMMAND --help
bash
# Debug generale — aumenta verbosità
openssl s_client -connect host:443 -debug 2>&1 | head -100

# Verifica che chiave e certificato matchino (modulus identici)
diff <(openssl x509 -noout -modulus -in cert.pem | md5sum) \
     <(openssl rsa  -noout -modulus -in key.pem  | md5sum) && echo "OK" || echo "MISMATCH"

# Verifica chain completa
openssl verify -CAfile ca_bundle.crt -untrusted intermediate.crt server.crt

OpenSSL in Automation — Bash and Python #

Bash script for deadline monitoring #

bash
#!/bin/bash
# check_cert_expiry.sh — controlla scadenza certificati remoti

HOSTS=("hackita.it:443" "github.com:443" "google.com:443")
WARN_DAYS=30

for host in "${HOSTS[@]}"; do
  expiry=$(echo | openssl s_client -connect $host -servername ${host%:*} 2>/dev/null | \
    openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
  
  if [ -z "$expiry" ]; then
    echo "[-] $host: impossibile connettersi"
    continue
  fi
  
  expiry_epoch=$(date -d "$expiry" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$expiry" +%s)
  now_epoch=$(date +%s)
  days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
  
  if [ $days_left -lt $WARN_DAYS ]; then
    echo "[!] $host: SCADE TRA $days_left GIORNI ($expiry)"
  else
    echo "[+] $host: ok ($days_left giorni rimanenti)"
  fi
done

Python — Certificate Inspection #

python
import ssl
import socket
from datetime import datetime

def get_cert_info(hostname: str, port: int = 443) -> dict:
    """Recupera informazioni sul certificato TLS di un host."""
    ctx = ssl.create_default_context()
    with socket.create_connection((hostname, port), timeout=10) as sock:
        with ctx.wrap_socket(sock, server_hostname=hostname) as ssock:
            cert = ssock.getpeercert()
            return {
                "subject": dict(x[0] for x in cert["subject"]),
                "issuer": dict(x[0] for x in cert["issuer"]),
                "not_before": cert["notBefore"],
                "not_after": cert["notAfter"],
                "san": cert.get("subjectAltName", []),
                "version": cert["version"],
            }

info = get_cert_info("hackita.it")
print(f"CN: {info['subject'].get('commonName')}")
print(f"Issuer: {info['issuer'].get('organizationName')}")
print(f"Scade: {info['not_after']}")
print(f"SAN: {[v for _, v in info['san']]}")

Comparison with alternatives #

toolFocusWhen to prefer it
OpenSSLEverything — keys, certs, TLS, cryptoDe-facto standard, maximum flexibility
cfssl (Cloudflare)PKI automationJSON-based, REST API, CI/CD
step-cli (Smallstep)Modern PKIACME, ergonomic CLI, provisioner
certbotLet's EncryptAutomatic renewal of public certificates
mkcertDev/labSelf-signed trusted locally without config
ageFile encryptionSimpler than openssl enc for end users

Quick Reference #

bash
# === CHIAVI ===
openssl genrsa -out key.pem 4096              # RSA 4096
openssl genrsa -aes256 -out key_enc.pem 4096  # RSA cifrata
openssl ecparam -name prime256v1 -genkey -noout -out ec.key  # ECDSA P-256
openssl genpkey -algorithm ED25519 -out ed25519.key           # ED25519
openssl rsa -in key.pem -pubout -out pub.key  # Estrai pubkey

# === CERTIFICATI ===
openssl req -new -key key.pem -out req.csr    # CSR
openssl req -in req.csr -noout -text          # Ispeziona CSR
openssl req -x509 -newkey rsa:4096 -keyout k.pem -out c.pem -days 365 -nodes  # Self-signed
openssl x509 -in cert.pem -noout -text        # Ispeziona cert
openssl x509 -in cert.pem -noout -dates       # Date validità
openssl x509 -in cert.pem -noout -ext subjectAltName  # SAN
openssl x509 -in cert.pem -noout -checkend 2592000    # Scade entro 30g?
openssl verify -CAfile ca.crt cert.pem        # Verifica chain

# === REMOTO ===
openssl s_client -connect host:443 -servername host   # Handshake completa
echo | openssl s_client -connect host:443 2>/dev/null | openssl x509 -noout -text
openssl s_client -connect host:443 -tls1_3            # Testa TLS 1.3
openssl s_client -connect host:25 -starttls smtp      # SMTP STARTTLS

# === CONVERSIONI ===
openssl x509 -in c.pem -outform DER -out c.der        # PEM→DER
openssl x509 -in c.der -inform DER -out c.pem         # DER→PEM
openssl pkcs12 -export -in c.pem -inkey k.pem -out b.pfx  # PEM→PKCS12
openssl pkcs12 -in b.pfx -out b.pem -nodes            # PKCS12→PEM

# === HASHING E CIFRATURA ===
openssl dgst -sha256 file                     # SHA256
openssl enc -aes-256-cbc -pbkdf2 -in f -out f.enc  # Cifra
openssl enc -aes-256-cbc -pbkdf2 -d -in f.enc -out f  # Decifra
openssl rand -hex 32                          # 32 byte random hex
openssl passwd -6 "password"                  # Hash password SHA-512

FAQ #

Why won't my browser accept my self-signed certificate even though it's valid? Modern browsers require SAN (Subject Alternative Names) — the CN field alone is not enough. Add -addext "subjectAltName=DNS:tuo-dominio" upon generation. You also need to install the Root CA in your browser/OS trust store.

What's the difference between RSA and ECDSA? RSA is the historical standard based on the difficulty of factoring large numbers. ECDSA uses elliptic curve mathematics—much shorter keys for the same security, faster handshakes. P-256 ECDSA is equivalent to RSA 3072. Use ECDSA in modern environments; RSA if you have compatibility constraints with very old systems.

What does he do -nodes in generating certificates? -nodes = “no DES” (historical abbreviation). In practice, this means: do not encrypt the private key with a passphrase. Useful for server certificates that start automatically (you can't enter the passphrase manually at startup).

How do I renew a certificate without changing the key? Generate a new CSR from the same private key, send it to the CA, and install the new certificate. The key remains the same—no configuration changes for applications using it.

OpenSSL 3.x vs. 4.0 — what's actually changed? For most CLI commands, nothing. The breaking changes in 4.0 mainly concern the C API (for developers using OpenSSL as a library) and the removal of legacy protocols (SSLv3, TLS 1.0/1.1). Your scripts should work unchanged.


Related Articles #


Sources and external references #

For use in authorized environments only.

#OpenSSL #TLS #certificates #PKI #Pentest

leave a message

I'm not a robot