OpenSSL Certificates

Certificate generation, inspection, and conversion with OpenSSL.

Certificate Fundamentals

# X.509 CERTIFICATE STRUCTURE
# - Version (v3 most common)
# - Serial Number (unique per CA)
# - Signature Algorithm (SHA256withRSA, etc.)
# - Issuer (CA that signed)
# - Validity (Not Before, Not After)
# - Subject (who cert is for)
# - Public Key
# - Extensions (SAN, Key Usage, etc.)
# - Signature (CA's signature over above)

# VIEW CERTIFICATE
openssl x509 -in cert.pem -noout -text
# Full details

# COMMON VIEW OPTIONS
openssl x509 -in cert.pem -noout -subject      # Subject only
openssl x509 -in cert.pem -noout -issuer       # Issuer only
openssl x509 -in cert.pem -noout -dates        # Validity dates
openssl x509 -in cert.pem -noout -serial       # Serial number
openssl x509 -in cert.pem -noout -fingerprint  # SHA-1 fingerprint
openssl x509 -in cert.pem -noout -fingerprint -sha256  # SHA-256

# MULTIPLE FIELDS
openssl x509 -in cert.pem -noout -subject -issuer -dates

# SUBJECT/ISSUER FORMAT
openssl x509 -in cert.pem -noout -subject -nameopt RFC2253
# Output: CN=hostname,O=Organization,C=US

openssl x509 -in cert.pem -noout -subject -nameopt oneline
# Output: CN = hostname, O = Organization, C = US

# VIEW EXTENSIONS
openssl x509 -in cert.pem -noout -ext subjectAltName
openssl x509 -in cert.pem -noout -ext keyUsage
openssl x509 -in cert.pem -noout -ext extendedKeyUsage

# CERTIFICATE CHAIN
openssl crl2pkcs7 -nocrl -certfile chain.pem | \
    openssl pkcs7 -print_certs -noout
# Lists all certs in chain

# COUNT CERTS IN CHAIN
grep -c 'BEGIN CERTIFICATE' chain.pem

Remote Certificate Inspection

# FETCH REMOTE CERTIFICATE
echo | openssl s_client -connect host:443 2>/dev/null | \
    openssl x509 -noout -subject -dates

# WITH SNI (Server Name Indication)
echo | openssl s_client -connect host:443 -servername host.example.com 2>/dev/null | \
    openssl x509 -noout -text

# SAVE REMOTE CERTIFICATE
echo | openssl s_client -connect host:443 2>/dev/null | \
    openssl x509 > remote-cert.pem

# FETCH FULL CHAIN
echo | openssl s_client -connect host:443 -showcerts 2>/dev/null | \
    awk '/BEGIN CERT/,/END CERT/' > chain.pem

# CONNECTION DETAILS
openssl s_client -connect host:443 -brief
# Output: CONNECTION ESTABLISHED
#         Protocol: TLSv1.3
#         Cipher: TLS_AES_256_GCM_SHA384

# TLS VERSION TESTING
openssl s_client -connect host:443 -tls1_2    # Force TLS 1.2
openssl s_client -connect host:443 -tls1_3    # Force TLS 1.3

# CHECK CERTIFICATE EXPIRY (one-liner)
echo | openssl s_client -connect host:443 2>/dev/null | \
    openssl x509 -noout -enddate | cut -d= -f2

# DAYS UNTIL EXPIRY
EXPIRY=$(echo | openssl s_client -connect host:443 2>/dev/null | \
    openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
echo "Days until expiry: $DAYS"

# INFRASTRUCTURE PATTERNS

# Check ISE certificate
echo | openssl s_client -connect ise-01.inside.domusdigitalis.dev:443 2>/dev/null | \
    openssl x509 -noout -subject -issuer -dates

# Check Vault certificate
echo | openssl s_client -connect vault-01.inside.domusdigitalis.dev:8200 2>/dev/null | \
    openssl x509 -noout -subject -dates

# Check multiple hosts
for host in ise-01 vault-01 grafana; do
    FQDN="${host}.inside.domusdigitalis.dev"
    EXPIRY=$(echo | openssl s_client -connect "$FQDN:443" 2>/dev/null | \
        openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
    echo "$host: $EXPIRY"
done

# Check certificate chain validity
echo | openssl s_client -connect host:443 -CAfile /etc/ssl/certs/ca-certificates.crt 2>&1 | \
    grep "Verify return code"
# Output: Verify return code: 0 (ok)

Certificate Chain Verification

# VERIFY CERTIFICATE AGAINST CA
openssl verify -CAfile ca.pem cert.pem
# Output: cert.pem: OK

# VERIFY WITH INTERMEDIATE
openssl verify -CAfile root.pem -untrusted intermediate.pem cert.pem

# VERIFY CHAIN FILE
openssl verify -CAfile chain.pem cert.pem

# VERBOSE VERIFICATION
openssl verify -verbose -CAfile ca.pem cert.pem
# Shows full chain

# VERIFY PARTIAL CHAIN
openssl verify -partial_chain -CAfile intermediate.pem cert.pem
# OK if intermediate is trusted (even without root)

# CHECK CHAIN ORDER
# Correct order: leaf -> intermediate -> root
openssl crl2pkcs7 -nocrl -certfile chain.pem | \
    openssl pkcs7 -print_certs -noout | \
    grep -E "subject=|issuer="

# BUILD CORRECT CHAIN
cat leaf.pem intermediate.pem root.pem > full-chain.pem

# VERIFY KEY MATCHES CERTIFICATE
CERT_MOD=$(openssl x509 -in cert.pem -noout -modulus | sha256sum)
KEY_MOD=$(openssl rsa -in key.pem -noout -modulus | sha256sum)
[ "$CERT_MOD" = "$KEY_MOD" ] && echo "Match" || echo "MISMATCH!"

# FOR EC KEYS
CERT_PUB=$(openssl x509 -in cert.pem -noout -pubkey | sha256sum)
KEY_PUB=$(openssl ec -in key.pem -pubout 2>/dev/null | sha256sum)
[ "$CERT_PUB" = "$KEY_PUB" ] && echo "Match" || echo "MISMATCH!"

# INFRASTRUCTURE PATTERNS

# Verify EAP-TLS certificate chain
openssl verify \
    -CAfile ~/.secrets/certs/d000/DOMUS-ROOT-CA.pem \
    -untrusted ~/.secrets/certs/d000/DOMUS-ISSUING-CA.pem \
    /etc/ssl/certs/modestus-razer-eaptls.pem

# Verify against system CA store
openssl verify -CApath /etc/ssl/certs/ cert.pem

# Verify ISE trusts our CA chain
# (via ISE API)
netapi ise api-call openapi GET '/api/v1/certs/trusted-certificate?size=100' | \
    jq -r '.response[].friendlyName' | grep -i domus

# Check DOMUS PKI chain
echo "=== Root CA ==="
openssl x509 -in ~/.secrets/certs/d000/DOMUS-ROOT-CA.pem -noout -subject -dates
echo "=== Issuing CA ==="
openssl x509 -in ~/.secrets/certs/d000/DOMUS-ISSUING-CA.pem -noout -subject -issuer -dates

Vault PKI Certificate Issuance

# VAULT PKI OVERVIEW
# pki/      - Root CA (offline)
# pki_int/  - Issuing CA (issues certificates)

# LIST PKI ROLES
vault list pki_int/roles

# VIEW ROLE CONFIGURATION
vault read pki_int/roles/domus-client

# ISSUE CERTIFICATE
vault write pki_int/issue/domus-client \
    common_name="hostname.inside.domusdigitalis.dev" \
    ttl="8760h"
# Returns: certificate, issuing_ca, private_key, serial_number

# ISSUE WITH SAN
vault write pki_int/issue/domus-client \
    common_name="hostname.inside.domusdigitalis.dev" \
    alt_names="alias.inside.domusdigitalis.dev,another.example.com" \
    ip_sans="10.50.1.100" \
    ttl="8760h"

# SAVE TO FILES
vault write -format=json pki_int/issue/domus-client \
    common_name="hostname.inside.domusdigitalis.dev" \
    ttl="8760h" > /tmp/cert.json

jq -r '.data.certificate' /tmp/cert.json > /tmp/cert.pem
jq -r '.data.private_key' /tmp/cert.json > /tmp/key.pem
jq -r '.data.issuing_ca' /tmp/cert.json > /tmp/ca.pem

# VERIFY ISSUED CERTIFICATE
openssl x509 -in /tmp/cert.pem -noout -subject -issuer -dates

# LIST ISSUED CERTIFICATES
vault list pki_int/certs

# VIEW CERTIFICATE BY SERIAL
vault read pki_int/cert/12:34:56:78:90:ab:cd:ef

# REVOKE CERTIFICATE
vault write pki_int/revoke serial_number="12:34:56:78:90:ab:cd:ef"

# TIDY CERTIFICATES (cleanup expired)
vault write pki_int/tidy \
    tidy_cert_store=true \
    tidy_revoked_certs=true \
    safety_buffer="72h"

# INFRASTRUCTURE PATTERNS

# Issue EAP-TLS certificate
HOSTNAME="modestus-razer"
vault write -format=json pki_int/issue/domus-client \
    common_name="${HOSTNAME}.inside.domusdigitalis.dev" \
    ttl="8760h" > /tmp/eaptls-cert.json

jq -r '.data.certificate' /tmp/eaptls-cert.json > /etc/ssl/certs/${HOSTNAME}-eaptls.pem
jq -r '.data.private_key' /tmp/eaptls-cert.json > /etc/ssl/private/${HOSTNAME}-eaptls.key
chmod 600 /etc/ssl/private/${HOSTNAME}-eaptls.key

# Issue server certificate (with SANs)
vault write -format=json pki_int/issue/domus-server \
    common_name="grafana.inside.domusdigitalis.dev" \
    alt_names="prometheus.inside.domusdigitalis.dev,alertmanager.inside.domusdigitalis.dev" \
    ip_sans="10.50.1.130" \
    ttl="8760h" > /tmp/server-cert.json

# Get CA chain for trust configuration
vault read -field=certificate pki/cert/ca > DOMUS-ROOT-CA.pem
vault read -field=certificate pki_int/cert/ca > DOMUS-ISSUING-CA.pem
cat DOMUS-ISSUING-CA.pem DOMUS-ROOT-CA.pem > DOMUS-CA-CHAIN.pem

SSH Certificates

# SSH CERTIFICATES VS KEYS
# Keys: public/private keypair, manual distribution
# Certs: signed by CA, automatic trust, expiry, principals

# VIEW SSH CERTIFICATE
ssh-keygen -Lf ~/.ssh/id_ed25519_vault-cert.pub
# Output:
# Type: ssh-ed25519-cert-v01@openssh.com
# Public key: SHA256:abc123...
# Signing CA: SHA256:def456...
# Key ID: "evan-domus"
# Serial: 1234567890
# Valid: from 2024-01-15T10:00:00 to 2024-01-15T18:00:00
# Principals:
#     evanusmodestus
#     admin
#     root
# Critical Options: (none)
# Extensions:
#     permit-pty

# VAULT SSH CA SIGNING
vault write -field=signed_key ssh/sign/domus-client \
    public_key=@$HOME/.ssh/id_ed25519_vault.pub \
    valid_principals="evanusmodestus,admin,root,ansible" \
    > ~/.ssh/id_ed25519_vault-cert.pub

# CHECK CERTIFICATE VALIDITY
ssh-keygen -Lf ~/.ssh/id_ed25519_vault-cert.pub | grep -E "Valid:|Principals:"

# CHECK IF EXPIRED
VALID_TO=$(ssh-keygen -Lf ~/.ssh/id_ed25519_vault-cert.pub | grep "Valid:" | awk '{print $5}')
VALID_EPOCH=$(date -d "$VALID_TO" +%s 2>/dev/null || echo 0)
NOW_EPOCH=$(date +%s)
if [ $NOW_EPOCH -gt $VALID_EPOCH ]; then
    echo "Certificate EXPIRED!"
else
    HOURS_LEFT=$(( (VALID_EPOCH - NOW_EPOCH) / 3600 ))
    echo "Valid for $HOURS_LEFT more hours"
fi

# SSH CA TRUST CONFIGURATION
# On SSH server (/etc/ssh/sshd_config):
# TrustedUserCAKeys /etc/ssh/vault-ca.pub

# Get CA public key from Vault
vault read -field=public_key ssh/config/ca > vault-ca.pub

# AUTHORIZED PRINCIPALS
# On SSH server (/etc/ssh/sshd_config):
# AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u

# Create principals file
echo "evanusmodestus" > /etc/ssh/auth_principals/evanusmodestus
echo -e "admin\nroot" >> /etc/ssh/auth_principals/evanusmodestus

# HOST CERTIFICATES
# Sign host key with CA
vault write ssh/sign/host-signer \
    cert_type=host \
    public_key=@/etc/ssh/ssh_host_ed25519_key.pub \
    > /etc/ssh/ssh_host_ed25519_key-cert.pub

# INFRASTRUCTURE PATTERNS

# Re-sign SSH certificate (daily)
~/.local/bin/vault-ssh-sign

# Test connectivity
~/.local/bin/vault-ssh-test

# Debug SSH cert issues
ssh -vvv host.example.com 2>&1 | grep -E "certificate|principal|key"

Certificate Generation (Self-Signed & CSR)

# GENERATE SELF-SIGNED CERTIFICATE
openssl req -x509 -nodes -days 365 \
    -newkey rsa:2048 \
    -keyout key.pem \
    -out cert.pem \
    -subj "/CN=localhost"

# WITH EXTENSIONS (SAN)
openssl req -x509 -nodes -days 365 \
    -newkey rsa:2048 \
    -keyout key.pem \
    -out cert.pem \
    -subj "/CN=myserver.local" \
    -addext "subjectAltName=DNS:myserver.local,DNS:localhost,IP:127.0.0.1"

# ELLIPTIC CURVE (faster, smaller)
openssl req -x509 -nodes -days 365 \
    -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
    -keyout key.pem \
    -out cert.pem \
    -subj "/CN=myserver.local"

# GENERATE CSR (Certificate Signing Request)
openssl req -new \
    -newkey rsa:2048 \
    -nodes \
    -keyout key.pem \
    -out request.csr \
    -subj "/CN=myserver.example.com/O=My Org/C=US"

# CSR WITH SAN (config file method)
cat > csr.conf << 'EOF'
[req]
distinguished_name = req_dn
req_extensions = req_ext
prompt = no

[req_dn]
CN = myserver.example.com
O = My Organization
C = US

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = myserver.example.com
DNS.2 = www.myserver.example.com
IP.1 = 10.0.0.100
EOF

openssl req -new -newkey rsa:2048 -nodes \
    -keyout key.pem -out request.csr \
    -config csr.conf

# VIEW CSR
openssl req -in request.csr -noout -text

# VERIFY CSR
openssl req -in request.csr -noout -verify
# Output: verify OK

# SIGN CSR WITH CA
openssl x509 -req \
    -in request.csr \
    -CA ca.pem \
    -CAkey ca-key.pem \
    -CAcreateserial \
    -out signed-cert.pem \
    -days 365 \
    -extfile csr.conf \
    -extensions req_ext

# GENERATE CA (for testing)
openssl req -x509 -nodes -days 3650 \
    -newkey rsa:4096 \
    -keyout ca-key.pem \
    -out ca.pem \
    -subj "/CN=Test CA/O=Test Org/C=US"

# PKCS#12 CONVERSION
# PEM to PKCS#12 (for Windows/browsers)
openssl pkcs12 -export \
    -inkey key.pem \
    -in cert.pem \
    -certfile ca.pem \
    -out cert.p12

# PKCS#12 to PEM
openssl pkcs12 -in cert.p12 -out extracted.pem -nodes

Certificate Format Conversion

# PEM (Base64, most common on Linux)
# -----BEGIN CERTIFICATE-----
# MIIBkTCB+wI...
# -----END CERTIFICATE-----

# DER (Binary, used by Java, Windows)
# Binary blob, no headers

# PKCS#12/PFX (Archive format, key + cert + chain)
# Binary, password protected

# PEM TO DER
openssl x509 -in cert.pem -outform DER -out cert.der
openssl rsa -in key.pem -outform DER -out key.der

# DER TO PEM
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 TO PKCS#12
openssl pkcs12 -export \
    -in cert.pem \
    -inkey key.pem \
    -certfile ca-chain.pem \
    -out cert.p12 \
    -name "My Certificate"
# Prompts for export password

# PKCS#12 TO PEM
openssl pkcs12 -in cert.p12 -out all.pem -nodes
# Contains key, cert, and chain in one file

# EXTRACT JUST CERTIFICATE
openssl pkcs12 -in cert.p12 -nokeys -out cert.pem

# EXTRACT JUST KEY
openssl pkcs12 -in cert.p12 -nocerts -nodes -out key.pem

# EXTRACT CA CERTIFICATES
openssl pkcs12 -in cert.p12 -cacerts -nokeys -out ca-chain.pem

# PKCS#7 (certificate chain, no key)
# PEM chain to PKCS#7
openssl crl2pkcs7 -nocrl -certfile chain.pem -out chain.p7b

# PKCS#7 to PEM
openssl pkcs7 -in chain.p7b -print_certs -out chain.pem

# VIEW PKCS#12 INFO
openssl pkcs12 -in cert.p12 -info -nokeys
# Shows certificate details without extracting

# VIEW PKCS#12 CONTENTS
openssl pkcs12 -in cert.p12 -info -nodes 2>/dev/null | \
    grep -E "subject=|issuer=|friendlyName"

# INFRASTRUCTURE PATTERNS

# Export Vault cert as PKCS#12 for Windows
vault write -format=json pki_int/issue/domus-client \
    common_name="winpc.inside.domusdigitalis.dev" \
    ttl="8760h" > /tmp/win-cert.json

jq -r '.data.certificate' /tmp/win-cert.json > /tmp/cert.pem
jq -r '.data.private_key' /tmp/win-cert.json > /tmp/key.pem
jq -r '.data.issuing_ca' /tmp/win-cert.json > /tmp/ca.pem

openssl pkcs12 -export \
    -in /tmp/cert.pem \
    -inkey /tmp/key.pem \
    -certfile /tmp/ca.pem \
    -out /tmp/winpc-eaptls.p12 \
    -name "EAP-TLS Certificate"

# Transfer to Windows, import with:
# certutil -importpfx -f winpc-eaptls.p12

Infrastructure Certificate Operations

# CHECK ALL INFRASTRUCTURE CERTS
for host in vault-01 ise-01 grafana prometheus; do
    echo "=== $host ==="
    echo | openssl s_client -connect "${host}.inside.domusdigitalis.dev:443" 2>/dev/null | \
        openssl x509 -noout -subject -dates 2>/dev/null || echo "  Connection failed"
done

# CERTIFICATE EXPIRY MONITORING
check_expiry() {
    local host=$1
    local port=${2:-443}
    local warn_days=${3:-30}

    EXPIRY=$(echo | openssl s_client -connect "$host:$port" 2>/dev/null | \
        openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)

    if [ -z "$EXPIRY" ]; then
        echo "$host: UNREACHABLE"
        return 1
    fi

    EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
    NOW_EPOCH=$(date +%s)
    DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

    if [ $DAYS_LEFT -lt 0 ]; then
        echo "$host: EXPIRED!"
    elif [ $DAYS_LEFT -lt $warn_days ]; then
        echo "$host: WARNING - $DAYS_LEFT days left"
    else
        echo "$host: OK - $DAYS_LEFT days left"
    fi
}

check_expiry "vault-01.inside.domusdigitalis.dev" 8200
check_expiry "ise-01.inside.domusdigitalis.dev" 443
check_expiry "grafana.inside.domusdigitalis.dev" 443

# VERIFY EAP-TLS CERTIFICATE CHAIN
openssl verify \
    -CAfile ~/.secrets/certs/d000/DOMUS-CA-CHAIN.pem \
    /etc/ssl/certs/modestus-razer-eaptls.pem

# UPDATE SYSTEM CA TRUST
# Debian/Ubuntu
sudo cp DOMUS-CA-CHAIN.pem /usr/local/share/ca-certificates/domus-ca.crt
sudo update-ca-certificates

# RHEL/Rocky/Fedora
sudo cp DOMUS-CA-CHAIN.pem /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

# Arch Linux
sudo cp DOMUS-CA-CHAIN.pem /etc/ca-certificates/trust-source/anchors/
sudo trust extract-compat

# CERTIFICATE RENEWAL WORKFLOW

# 1. Generate new cert from Vault
vault write -format=json pki_int/issue/domus-client \
    common_name="hostname.inside.domusdigitalis.dev" \
    ttl="8760h" > /tmp/new-cert.json

# 2. Verify new cert
jq -r '.data.certificate' /tmp/new-cert.json | \
    openssl x509 -noout -subject -dates

# 3. Backup old cert
cp /etc/ssl/certs/hostname-eaptls.pem /etc/ssl/certs/hostname-eaptls.pem.bak

# 4. Install new cert
jq -r '.data.certificate' /tmp/new-cert.json > /etc/ssl/certs/hostname-eaptls.pem
jq -r '.data.private_key' /tmp/new-cert.json > /etc/ssl/private/hostname-eaptls.key
chmod 600 /etc/ssl/private/hostname-eaptls.key

# 5. Restart services
sudo systemctl restart wpa_supplicant
# Or for NetworkManager:
nmcli connection down "Wired-802.1X-EAP-TLS"
nmcli connection up "Wired-802.1X-EAP-TLS"

# 6. Verify authentication
netapi ise mnt sessions | grep hostname

Certificate Gotchas

# WRONG: Missing newline in echo for s_client
echo "Q" | openssl s_client -connect host:443
# May hang or behave unexpectedly

# CORRECT: Use empty echo
echo | openssl s_client -connect host:443

# WRONG: Trusting self-signed without verification
curl -k https://untrusted-host/
# -k skips ALL verification!

# CORRECT: Provide CA certificate
curl --cacert ca.pem https://host/

# WRONG: Certificate but no SAN
openssl req -x509 -subj "/CN=myhost"
# Modern browsers require SAN, not just CN

# CORRECT: Always include SAN
openssl req -x509 -subj "/CN=myhost" -addext "subjectAltName=DNS:myhost"

# WRONG: Chain in wrong order
cat root.pem intermediate.pem leaf.pem > chain.pem
# Should be: leaf -> intermediate -> root

# CORRECT: Leaf first
cat leaf.pem intermediate.pem root.pem > chain.pem

# WRONG: Assuming cert file contains key
# PEM can contain cert, key, or both!

# CORRECT: Check what's in file
grep -E "BEGIN (CERTIFICATE|PRIVATE KEY|RSA PRIVATE KEY)" file.pem

# WRONG: Key permissions too open
chmod 644 private-key.pem
# Anyone can read!

# CORRECT: Restrict key permissions
chmod 600 private-key.pem
chown root:root private-key.pem

# WRONG: Expired intermediate CA
# Leaf cert valid, but intermediate expired = chain invalid

# CORRECT: Check entire chain expiry
for cert in $(cat chain.pem | awk '/BEGIN/,/END/' RS= ORS='\n\n'); do
    echo "$cert" | openssl x509 -noout -subject -enddate
done

# WRONG: Missing CA in verification
openssl verify cert.pem
# Uses system CAs, might miss custom CA

# CORRECT: Specify CA explicitly
openssl verify -CAfile my-ca.pem cert.pem

# WRONG: SSH cert with wrong principals
vault write ssh/sign/domus-client public_key=@key.pub
# No principals = can't authenticate

# CORRECT: Specify all needed principals
vault write ssh/sign/domus-client \
    public_key=@key.pub \
    valid_principals="user1,user2,admin"

# WRONG: PKCS#12 without chain
openssl pkcs12 -export -in cert.pem -inkey key.pem -out cert.p12
# Missing intermediate = validation fails on import

# CORRECT: Include chain
openssl pkcs12 -export -in cert.pem -inkey key.pem -certfile chain.pem -out cert.p12

Quick Reference

# VIEW CERTIFICATE
openssl x509 -in cert.pem -noout -text       # Full details
openssl x509 -in cert.pem -noout -subject -dates  # Key info

# REMOTE CERTIFICATE
echo | openssl s_client -connect host:443 2>/dev/null | \
    openssl x509 -noout -subject -dates

# VERIFY CHAIN
openssl verify -CAfile ca.pem cert.pem
openssl verify -CAfile root.pem -untrusted intermediate.pem cert.pem

# KEY/CERT MATCH
openssl x509 -in cert.pem -noout -modulus | sha256sum
openssl rsa -in key.pem -noout -modulus | sha256sum
# Should match!

# GENERATE SELF-SIGNED
openssl req -x509 -nodes -days 365 \
    -newkey rsa:2048 -keyout key.pem -out cert.pem \
    -subj "/CN=hostname" -addext "subjectAltName=DNS:hostname"

# VAULT PKI
vault write pki_int/issue/role common_name="host.domain" ttl="8760h"

# SSH CERTIFICATES
ssh-keygen -Lf cert.pub                  # View
vault write ssh/sign/role public_key=@key.pub valid_principals="user"

# FORMAT CONVERSION
openssl x509 -in cert.pem -outform DER -out cert.der  # PEM to DER
openssl pkcs12 -export -in cert.pem -inkey key.pem -out cert.p12  # To PKCS#12
openssl pkcs12 -in cert.p12 -out all.pem -nodes  # From PKCS#12

# EXPIRY CHECK
echo | openssl s_client -connect host:443 2>/dev/null | \
    openssl x509 -noout -enddate | cut -d= -f2