Once the TLS connection is established, we can use the SSL_get_peer_certificate() function to get the server's certificate. It's also easy to print the certificate subject and issuer, as shown in the following code:
X509 *cert = SSL_get_peer_certificate(ssl);
if (!cert) {
fprintf(stderr, "SSL_get_peer_certificate() failed.\n");
return 1;
}
char *tmp;
if (tmp = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) {
printf("subject: %s\n", tmp);
OPENSSL_free(tmp);
}
if (tmp = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) {
printf("issuer: %s\n", tmp);
OPENSSL_free(tmp);
}
X509_free(cert);
OpenSSL automatically verifies the certificate during the TLS/SSL handshake. You can get the verification results using the SSL_get_verify_result() function. Its usage is shown in the following code:
long vp = SSL_get_verify_result(ssl);
if (vp == X509_V_OK) {
printf("Certificates verified successfully.\n");
} else {
printf("Could not verify certificates: %ld\n", vp);
}
If SSL_get_verify_result() returns X509_V_OK, then the certificate chain was verified by OpenSSL and the connection can be trusted. If SSL_get_verify_result() does not return X509_V_OK, then HTTPS authentication has failed, and the connection should be abandoned.
In order for OpenSSL to successfully verify the certificate, we must tell it which certificate authorities we trust. This can be done by using the SSL_CTX_load_verify_locations() function. It must be passed the filename that stores all of the trusted root certificates. Assuming your trusted certificates are in trusted.pem, the following code sets this up:
if (!SSL_CTX_load_verify_locations(ctx, "trusted.pem", 0)) {
fprintf(stderr, "SSL_CTX_load_verify_locations() failed.\n");
ERR_print_errors_fp(stderr);
return 1;
}
Deciding which root certificates to trust isn't easy. Each operating system provides a list of trusted certificates, but there is no general, easy way to import these lists. Using the operating system's default list is also not always appropriate for every application. For these reasons, certificate verification has been omitted from the examples in this chapter. However, it is absolutely critical that it be implemented appropriately in order for your HTTPS connections to be secure.
In addition to validating the certificate's signatures, it is also important to validate that the certificate is actually valid for the particular server you're connected with! Newer versions of OpenSSL provide functions to help with this, but with older versions of OpenSSL, you're on your own. Consult the OpenSSL documentation for more information.
We've now covered enough background information about TLS and OpenSSL that we're ready to tackle a concrete example program.