Skip to content

Instantly share code, notes, and snippets.

@jay
Last active February 14, 2019 07:41
Show Gist options
  • Save jay/982b70e50bdd8a86415c to your computer and use it in GitHub Desktop.
Save jay/982b70e50bdd8a86415c to your computer and use it in GitHub Desktop.
Use libcurl and OpenSSL to show SSL negotiated cipher and version.
/* Use libcurl and OpenSSL to show SSL negotiated cipher and version.
Usage: ShowSSLInfo
curl-library mailing list thread:
'CURLINFO_TLS_SESSION with OPENSSL returns SSL_CTX instead of SSL'
http://curl.haxx.se/mail/lib-2015-09/0127.html
Copyright (C) 2015 Jay Satiro <raysatiro@yahoo.com>
http://curl.haxx.se/docs/copyright.html
https://gist.github.com/jay/982b70e50bdd8a86415c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* http://curl.haxx.se/download.html */
#include <curl/curl.h>
/* https://www.openssl.org/source/ */
#include <openssl/ssl.h>
#undef FALSE
#define FALSE 0
#undef TRUE
#define TRUE 1
void ssl_info_callback(const SSL *s, int where, int ret)
{
(void) ret;
if(where & SSL_CB_HANDSHAKE_DONE) {
const char *ver, *cipher;
fprintf(stderr, "Received SSL_CB_HANDSHAKE_DONE\n");
switch(SSL_version(s)) {
case TLS1_2_VERSION:
ver = "TLSv1.2";
break;
case TLS1_1_VERSION:
ver = "TLSv1.1";
break;
case TLS1_VERSION:
ver = "TLSv1.0";
break;
case SSL3_VERSION:
ver = "SSLv3";
break;
case SSL2_VERSION:
ver = "SSLv2";
break;
default:
ver = "unknown";
break;
}
fprintf(stderr, "Version: %s\n", ver);
cipher = SSL_get_cipher(s);
if(!cipher)
cipher = "unknown";
fprintf(stderr, "Cipher: %s\n\n", cipher);
}
return;
}
CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *userptr)
{
(void)curl;
(void)userptr;
SSL_CTX_set_info_callback((SSL_CTX *)ssl_ctx, ssl_info_callback);
return CURLE_OK;
}
/* Retrieve url, show the SSL cipher and version. */
int ShowSSLInfo(const char *url)
{
int retcode = FALSE;
CURL *curl = NULL;
CURLcode res = CURLE_FAILED_INIT;
char errbuf[CURL_ERROR_SIZE] = { 0, };
curl = curl_easy_init();
if(!curl) {
fprintf(stderr, "Error: curl_easy_init failed.\n");
goto cleanup;
}
/* CURLOPT_CAINFO
To verify SSL sites you may need to load a bundle of certificates.
You can download the default bundle here:
https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt
However your SSL backend might use a database in addition to or instead of
the bundle.
http://curl.haxx.se/docs/ssl-compared.html
*/
curl_easy_setopt(curl, CURLOPT_CAINFO, "curl-ca-bundle.crt");
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback);
/* curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); */
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); /* HEAD request */
curl_easy_setopt(curl, CURLOPT_HEADER, 1L); /* show headers */
curl_easy_setopt(curl, CURLOPT_URL, url);
res = curl_easy_perform(curl);
if(res != CURLE_OK) {
size_t len = strlen(errbuf);
fprintf(stderr, "\nlibcurl: (%d) ", res);
if(len)
fprintf(stderr, "%s%s", errbuf, ((errbuf[len - 1] != '\n') ? "\n" : ""));
fprintf(stderr, "%s\n\n", curl_easy_strerror(res));
goto cleanup;
}
retcode = TRUE;
cleanup:
curl_easy_cleanup(curl);
return retcode;
}
int main(int argc, char *argv[])
{
curl_version_info_data *curlver = NULL;
if(argc != 2) {
fprintf(stderr, "Usage: ShowSSLInfo <url>\n");
return EXIT_FAILURE;
}
if(curl_global_init(CURL_GLOBAL_ALL)) {
fprintf(stderr, "Fatal: The initialization of libcurl has failed.\n");
return EXIT_FAILURE;
}
if(atexit(curl_global_cleanup)) {
fprintf(stderr, "Fatal: atexit failed to register curl_global_cleanup.\n");
curl_global_cleanup();
return EXIT_FAILURE;
}
curlver = curl_version_info(CURLVERSION_NOW);
if(!(curlver->features & CURL_VERSION_SSL) || !curlver->ssl_version ||
strncmp("OpenSSL", curlver->ssl_version, 7)) {
fprintf(stderr, "Fatal: libcurl is not using OpenSSL.\n");
return EXIT_FAILURE;
}
if(!ShowSSLInfo(argv[1])) {
fprintf(stderr, "Fatal: ShowSSLInfo failed.\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment