Fun with certs
--#--
Defining a verify callback routine helps to grant exceptions
to OpenSSL's default verification algorithm (which looks for
self-signed certs, certs whose signatures don't match,
unknown CA's and expired certs).
But the opposite situation may occur -- when you want to go
OpenSSL one further in making absolutely sure this is the cert
you're looking for. Consider this scenario -- Someone has
taken a cert issued for one server and used it to start up
an SSL daemon somewhere else. You may well have encountered this
on the Net. Netscape will warn you in this circumstance,
with a dialog box cautioning you that the cert name and server
request name don't match.
We obtained the chain (which, incidentally, is likely to contain
only one cert, making it a "chain" in concept only) by calling
SSL_get_peer_cert_chain(ssl). We can also get just the
server cert by calling SSL_get_peer_certificate(ssl).
Using these two functions, we can get almost any information about
the cert and the chain.
-###X509 *server_cert, *next_cert;
int i;###-
...
-###server_cert = SSL_get_peer_certificate(ssl);###-
chain = SSL_get_peer_cert_chain(ssl);
result = ssl_verify_cert_chain(ssl, chain);
-###printf("Server cert: %s\n", X509_NAME_oneline(
X509_get_subject_name(server_cert), 0, 0));
printf("Server cert issuer: %s\n", X509_NAME_oneline(
X509_get_issuer_name(server_cert), 0, 0));
printf("%d certs in chain\n", chain->stack.num;
for (i = 0; i < chain->stack.num; i++) {
next_cert = (X509 *)chain->stack.data[0];
printf("\t%d: %s\n", i, X509_NAME_oneline(
X509_get_subject_name(next_cert), 0, 0));
printf("\t%d: %s\n", i, X509_NAME_oneline(
X509_get_issuer_name(next_cert), 0, 0));
}###-
Using code like this you can examine the whole chain. But, most importantly,
you could examine the "subject_name" of the server cert to see if it's the
one you expect. Another way to do this is to get the hash of the
subject name and compare it to a stored hash.
/* I'll assume you've got the hash stored in a file or */
/* embedded in the code somewhere and use a function to */
/* retrieve it. */
unsigned long cert_hash = 0;
unsigned long stored_hash = getHash();
cert_hash = X509_subject_name_hash(server_cert);
if (cert_hash != stored_hash) {
/* Decide here whether this is fatal or not */
There are a number of things you can examine in a cert. Check out x509_cmp.c
and X509_vfy.c in the source distribution to see what some of them are. Also,
play around with the openssl command line tool some, using the x509 command
and its options. For instructions use:
openssl x509 -h