#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
int
verify(int ok, X509_STORE_CTX *store)
{
// Always abort verification with an error.
return 0;
}
int
main(int argc, char *argv[])
{
// Initialize OpenSSL
SSL_library_init();
SSL_load_error_strings();
// Create a context
SSL_CTX *ctx = SSL_CTX_new(TLSv1_client_method());
if (ctx == NULL) {
ERR_print_errors_fp(stderr);
abort();
}
// Load trusted CAs from default paths.
SSL_CTX_set_default_verify_paths(ctx);
// Set verify function
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify);
// Resolve
struct addrinfo hints, *ai;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int ai_error = getaddrinfo("www.apple.com", "https", &hints, &ai) ;
if(ai_error != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ai_error));
abort();
}
// Connect
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(connect(sock, ai->ai_addr, ai->ai_addrlen) != 0) {
close(sock);
perror("connect");
abort();
}
// Wrap connection with TLS
SSL *ssl = SSL_new(ctx);
if (ssl == NULL) {
ERR_print_errors_fp(stderr);
abort();
}
SSL_set_fd(ssl, sock);
if (SSL_connect(ssl) == -1) {
ERR_print_errors_fp(stderr);
} else {
// Should NOT be reached with the verify function from above!
printf("Connected with cipher %s\n", SSL_get_cipher(ssl));
SSL_shutdown(ssl);
}
SSL_free(ssl);
close(sock);
SSL_CTX_free(ctx);
return 0;
}
Compile it using
$ cc ssl_client.c -lssl -lcrypto -o ssl_client
and run without arguments.
This program succeeds only when linked against Apple’s patched OpenSSL. Any other fails with an error message like:
SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed:s3_clnt.c:1166:
I have double-checked this back to a vintage 0.9.8e-fips-rhel5 on CentOS 5. It is definitely an Apple-only problem.