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