Skip to content
ecdsa.com

Self-signed certificate · OpenSSL

How to create a self-signed EC P-256 certificate with SANs with OpenSSL

openssl req -x509 creates a key and a self-signed certificate in one command: -newkey ec with the P-256 curve generates the key, -subj and -days set the name and the validity, and four -addext options write the SANs and the extensions that make it a TLS server certificate rather than a CA. The run decodes the certificate with OpenSSL and verifies it for localhost and 127.0.0.1.

Tested with OpenSSL 3.5.7 (Debian 13).

cert.sh — P-256 key and self-signed server certificate, valid 365 days
# P-256 key and a self-signed TLS server certificate, valid 365 days
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
-keyout key.pem -out cert.pem -days 365 \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
-addext "basicConstraints=critical,CA:FALSE" \
-addext "keyUsage=critical,digitalSignature" \
-addext "extendedKeyUsage=serverAuth"
inspect.sh — print the subject, the validity and the SANs
openssl x509 -in cert.pem -noout -subject -dates -ext subjectAltName

How it works

  1. req -x509 makes a self-signed certificate instead of a CSR; -newkey ec -pkeyopt ec_paramgen_curve:P-256 generates the key, and -noenc writes key.pem unencrypted.
  2. -subj "/CN=localhost" becomes both the subject and the issuer; -days 365 counts from the current time, which is the notBefore.
  3. subjectAltName=DNS:localhost,IP:127.0.0.1 lists the names clients match: DNS: entries for host names, IP: entries for addresses.
  4. basicConstraints=critical,CA:FALSE, keyUsage=critical,digitalSignature and extendedKeyUsage=serverAuth make it a leaf certificate for TLS servers; inspect.sh prints single fields with -dates and -ext subjectAltName.

Gotchas

  • Without -addext "basicConstraints=…", req -x509 applies the v3_ca section of the default openssl.cnf, and the certificate comes out as a CA — basicConstraints: critical, CA:TRUE — with no key usage at all.
  • Without -days, the certificate is valid for 30 days only.
  • DNS:127.0.0.1 is not an IP SAN: clients that connect by address reject it, and openssl verify -verify_ip 127.0.0.1 fails with error 64 at 0 depth lookup: IP address mismatch. Write IP:127.0.0.1.
  • Clients still have to be told to trust the file: openssl verify cert.pem fails with error 18 at 0 depth lookup: self-signed certificate and curl with curl: (60) SSL certificate problem: self-signed certificate until you pass -CAfile cert.pem or --cacert cert.pem.

Related recipes