Connecting to HTTPS with OpenSSL

OpenBSD uses LibreSSL, a fork of OpenSSL begun in 2014, which modernizes the codebase and improves security.

Connecting to HTTPS websites

To test a website's TLS:

$ openssl s_client -connect example.com:443

Replace example.com with your actual hostname.

You should see the correct SSL subject and issuer:

$ openssl s_client -connect example.org:443
CONNECTED(00000003)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R11
verify return:1
depth=0 CN = example.com
verify return:1
---
Certificate chain
 0 s:/CN=example.com
   i:/C=US/O=Let's Encrypt/CN=R11
 1 s:/C=US/O=Let's Encrypt/CN=R11
   i:/C=US/O=Internet Security Research Group/CN=ISRG Root X1
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIF+jCCBOKgAwIBAgISBBiSmYI1JcgnGriQsYnjgYNaMA0GCSqGSIb3DQEBCwUA
MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD
EwNSMTEwHhcNMjQxMTE0MDAzNjU3WhcNMjUwMjEyMDAzNjU2WjAfMR0wGwYDVQQD
ExRqcm11Lmhvc3QuaXJjbm93Lm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
AgoCggIBANuLaDDkipvSVq4lPmSymFhbnqt7Exv3LRmzq6YvqzWpLOd1wkHNXFHg
yxCE6AbVdz3jqZT00sVO1uF/A3YdN63qlziWJFP1GaCZzcyuJ7a2NAVX/igggxO3
guwzlfFh844AoudJ3+KPBCGfCmI8qWftjOTIz4/huCr3CRsPwuABySWKGh/p9n+3
wJE5EU425hkiTGGDNhF65aU8B/cT3clhdkFKwcNGEX4vkrQwlZeF43Mj9cQf3G3v
uAOdP0DEGqhxyYQUrsGP/ml9S99VnQ91hxta1J4EYwTqCnG4UwyZ/unFJ3vRpajQ
/8LKkVPBQxKaREJNafB0cv29sEqE2RTBWzot8RT6mSFN59b07O7m4pxqHs+OenkW
ltH3lM9pwrFBc0RLipAXkkgauVSohBH7SbVuMDIwCMYFdOHCBRqgW6eDTk+hhklh
nXWR0JJ2lRF1IUQQjduJWadEUDK9O/iUfLfnZr1a5ZfjXs4dlFqVU8NUQWQd3G5J
9d4iCX7VkEigXlJrxTgbohFLkPzeDiSPqdwKqx1GMEWLxrW65a71UR81AJEYTJJE
ixOwGEb1kXtGEqKhM4CYywBLKiDNOEoMPsRg3UsOfHS1eaSDF6io42brmhKILAJL
SP5CTPZw5LYKaqc+aO13keucLBTne5+aWhaQBD0ihqsssYPlxFehAgMBAAGjggIa
MIICFjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAVeGed5J7eod57c69KSUDiVDq7m
MB8GA1UdIwQYMBaAFMXPRqTq9MPAemyVxC2wXpIvJuO5MFcGCCsGAQUFBwEBBEsw
STAiBggrBgEFBQcwAYYWaHR0cDovL3IxMS5vLmxlbmNyLm9yZzAjBggrBgEFBQcw
AoYXaHR0cDovL3IxMS5pLmxlbmNyLm9yZy8wHwYDVR0RBBgwFoIUanJtdS5ob3N0
LmlyY25vdy5vcmcwEwYDVR0gBAwwCjAIBgZngQwBAgEwggEGBgorBgEEAdZ5AgQC
BIH3BIH0APIAdwDPEVbu1S58r/OHW9lpLpvpGnFnSrAX7KwB0lt3zsw7CAAAAZMo
T6OZAAAEAwBIMEYCIQD+t4oiZ3lkJeY+nH1glYZjlktnSc31rKjJlBbJwnPTfwIh
ALwVTA0TNEa2jo5zmOq7nypo7awprI48XnDofYsb7GK+AHcAE0rfGrWYQgl4DG/v
THqRpBa3I0nOWFdq367ap8Kr4CIAAAGTKE+kEwAABAMASDBGAiEA5nosfBa3GTMC
Rw9xjef4RVpwdvaaRsC8xDZy95CW86ECIQCLSXo2BqI9coah2trzV3gxq0LnEn9r
XcciSxO0ZH4mCzANBgkqhkiG9w0BAQsFAAOCAQEApjLhmAFD1bEgI5lxzIcGQrdM
3CSgDn7OZEqQS6pbmTGdjk3aiWAUNsNlwBdatdWra171lytEd2wufDf/iN7RWkcK
6BK3RZeTsKK8KNdKiV7oXL9Kd/1NpYSHizVN1obqF3Knh1JM+Kes6YXTxod7L1Av
ozkhle3d61jrUhUz4VEp053pNxi8ylDRd6jeDnIAQbAJlGJapD1P3Sfy0VL+Kprs
ZoEucBa3ZaSh+JNNS0fxSnl/qKfWlwOSsiMNL8yj7sy6hcVEgWqhMkviGGYpNikY
harUihdi26bReT1MXM9nFsYZa20+B1BUGk7Y/0TQ7zo1JtjhSXVIP4pB1zpuwg==
-----END CERTIFICATE-----
subject=/CN=example.com
issuer=/C=US/O=Let's Encrypt/CN=R11
---
No client certificate CA names sent
Server Temp Key: ECDH, X25519, 253 bits
---
SSL handshake has read 3645 bytes and written 386 bytes
---
New, TLSv1/SSLv3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 4096 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Start Time: 1731552214
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

At this point, you can make normal HTTP GET requests like with netcat or telnet.

Expired Certificates

If your certificate has expired, you will see the following error message:

    Verify return code: 10 (certificate has expired)

Make sure to renew your certificate using acme-client. Consider automating the renewal using cron.

Missing full certificate chain

If the web server is missing the full certificate chain, you will see the following return code:

    Verify return code: 20 (unable to get local issuer certificate)

Double check that the web server is serving the full certificate chain. If using acme-client, make sure you are using the certificate that is specified in acme-client.conf(5)'s domain full chain certificate.

Self-Signed Certificates

If you are using a self-signed certificate, you will see the following return code:

    Verify return code: 18 (self signed certificate)

It's recommended to use a properly signed certificate from a trusted Certificate Authority to avoid issues with users trying to connect. Such certificates can be requested using acme-client. Self-signed certificates will often trigger validation errors from end-user clients.

Wrong Ports

Obtaining TLS certificate

To get the certificate from a website, type the command below, replacing example.com:

$ openssl s_client -connect example.com:443 2>&1 | sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > example.com.pem

See Also:

  1. Applied Cryptography: Protocols, Algorithms, and Source Code in C by Bruce Schneier
  2. SSL and TLS Essentials: Securing the Web by Stephen A. Thomas