TLS Certificates, Hostnames and Trust¶
An encrypted connection is not enough if you have connected to the wrong server. Use the previous C++ client to separate two questions: who issued this certificate, and is it for the server you intended?
Course examples on GitHub
Reuse the standalone TLS client, certificate fixture and negative tests. There is no second implementation to keep in sync.
Before you start¶
Complete Your First Verified TLS Connection, including a successful echo. Run commands on your Pi from the examples repository's network/ directory. This lesson does not install a CA into the OS or browser.
Outcome: explain and reproduce separate trust-chain and hostname failures, and confirm that the C++ client sends no application message when either check fails.
Two checks before application data¶
This separates the decisions conceptually, not OpenSSL's internal validation order. Chain validation includes more than checking a signature: certificate validity periods, CA constraints and allowed usage matter too. The handshake also proves possession of the server's private key. Merely copying another server's public certificate is not sufficient.
In this exercise the chain is short: a practice CA signs a server certificate. Real deployments can include intermediate CAs. The local ca.pem is our explicitly selected trust anchor, not something the server gets to declare trustworthy.
TLS identity: address, expected name and SNI¶
| Value | In this client | What it does not establish |
|---|---|---|
| Destination address | 127.0.0.1 in sockaddr_in |
Which DNS identity a certificate should contain. |
| Expected name | localhost, passed to SSL_set1_host |
Whether the issuer is trusted. |
| SNI | localhost, sent with SSL_set_tlsext_host_name |
Whether the returned certificate is valid. |
| Trust file | Your selected ca.pem |
Whether a trusted certificate belongs to this hostname. |
SNI helps a server hosting multiple names select a certificate. It is not the hostname check. The fixture serves just one certificate, so changing SNI cannot make it produce a certificate for another name.
Our certificate contains DNS:localhost, not IP:127.0.0.1. The client connects to the loopback IP but deliberately verifies the DNS identity. A general IP-identity client should use OpenSSL's IP-address verification API and require an IP Subject Alternative Name; do not replace DNS verification with a string comparison against the certificate's printed subject.
Inspect your practice certificate¶
If the previous terminal has closed, create a fresh, private practice directory:
Inspect the public server certificate, not its secret key:
Look for the practice CA issuer, the two-day validity window and DNS:localhost. A readable certificate is not evidence that verification passed.
Now check it explicitly for the right name:
Expected: the certificate path followed by OK, with exit status zero. This is an offline certificate check, not a network handshake or proof that a live peer possesses the private key.
Change only the required identity:
Expected: hostname mismatch and a nonzero exit status. The issuer is still trusted, but this is not a certificate for wrong.example. Exact diagnostic formatting can vary with OpenSSL.
Reproduce failures through the C++ client¶
Start a fresh fixture in terminal A before each attempt:
Terminal B needs the same printed certificate-directory path, just as in the previous lesson. First, keep the right CA but request the wrong name:
Expected: exit status 1, a TLS error on stderr and no successful echo on stdout. The fixture can also report the client's fatal TLS alert and exit with an error; this is an intentional failed handshake, not a reason to disable checking.
For an issuer failure, create an independent practice CA in terminal B:
Restart terminal A first, still using the original $certs server certificate. The independent CA cannot authenticate that server. The two practice CAs happen to share a display name, but have different keys; matching issuer text is not a valid trust check.
Do not replace the trust file with a certificate supplied by an unknown peer merely to get a successful result. Decide trust through an authenticated channel outside the connection being checked.
Prove that failure stops the application¶
Run the independent peer checks:
The harness records application bytes seen by the Python TLS peer. It requires the exact message on the good path and no application request for the wrong-CA and wrong-host paths. This provides stronger evidence than checking only whether the C++ process printed an error.
In the existing C++ source, locate these four responsibilities:
SSL_CTX_load_verify_locationsloads the selected CA file.SSL_CTX_set_verify(..., SSL_VERIFY_PEER, ...)makes peer verification mandatory.SSL_set1_hostsets the required identity before the handshake.- The
SSL_write_exloop is reached only afterSSL_connectsucceeds and verification is checked.
Keep the formatted full source in the previous lesson open while tracing that path. There is no insecure fallback or reconnect-without-verification branch.
What this exercise does not cover¶
This fixture authenticates the server, not the client. A server that also requires client certificates needs a separate mutual-TLS policy and client credentials. Application login and permissions are separate again.
The fixture does not demonstrate revocation checking, public certificate issuance, rotation or browser trust management. OpenSSL verification with this CA file does not automatically configure an application-specific revocation policy. A production client needs a maintained trust store and an explicit operational policy, not the two-day practice CA.
TLS protects application content in transit between its endpoints. It does not hide all network metadata, make the endpoints trustworthy, or prove the truth of a sensor reading.
Check your understanding¶
- Can a certificate from a trusted CA still be wrong for your connection?
- Does sending SNI enable certificate verification?
- Why do two CA certificates with identical subject text not necessarily establish the same trust?
- Does an offline
openssl verifysuccess prove that a network server holds the private key?
Answers
Yes: its identity, validity or permitted usage can be unsuitable. SNI requests a server name but does not validate the returned certificate. Trust depends on keys and validated signatures, not display-name equality. Offline verification checks certificate material; the live handshake provides proof of private-key possession.
Continue the course¶
Previous: Your First Verified TLS Connection · Next: Your First HTTPS Request
References: OpenSSL certificate verification, server identity checking, TLS 1.3 authentication.