Skip to content

Instantly share code, notes, and snippets.

@maurorappa
Created December 2, 2016 16:02
Show Gist options
  • Save maurorappa/7fa11f27a08680af9f56880b859df60f to your computer and use it in GitHub Desktop.
Save maurorappa/7fa11f27a08680af9f56880b859df60f to your computer and use it in GitHub Desktop.
TCP / SSL connection times measurements
/* ------------------------------------------------------------ *
* file: sslconnect.c *
* ------------------------------------------------------------ *
* file: sslconnect.c *
* purpose: utility to time an SSL connection and *
* to compile: *
* gcc -lssl -lcrypto -o sslconnect sslconnect.c *
* ------------------------------------------------------------ */
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
/* ---------------------------------------------------------- *
* First we need to make a standard TCP socket connection. *
* create_socket() creates a socket & TCP-connects to server. *
* ---------------------------------------------------------- */
int create_socket(char[], BIO *);
int main (int argc, char *argv[]) {
int verbose = 0;
char *dest_url = "empty";
int opt;
int index;
BIO *certbio = NULL;
BIO *outbio = NULL;
X509 *cert = NULL;
X509_NAME *certname = NULL;
const SSL_METHOD *method;
SSL_CTX *ctx;
SSL *ssl;
int math = 0;
int i,server,start,tcp,epoch_tcp,tls = 0;
while ((opt = getopt (argc, argv, "hmvu:")) != -1)
{
switch (opt)
{
case 'm':
math = 1;
break;
case 'v':
verbose = 1;
break;
case 'u':
dest_url = optarg;
break;
case 'h':
printf("Usage: sslconnect [options] -u <url>\nOptions:\n\t-v\tverbose\n\t-m\tdo the math for you (results in microseconds)\n");
return 1;
break;
}
}
if(dest_url == "empty")
{
printf("Please specify an url!\n");
return 1;
}
/* ---------------------------------------------------------- *
* These function calls initialize openssl for correct work. *
* ---------------------------------------------------------- */
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
/* ---------------------------------------------------------- *
* Create the Input/Output BIO's. *
* ---------------------------------------------------------- */
certbio = BIO_new(BIO_s_file());
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
/* ---------------------------------------------------------- *
* initialize SSL library and register algorithms *
* ---------------------------------------------------------- */
if(SSL_library_init() < 0)
BIO_printf(outbio, "Could not initialize the OpenSSL library !\n");
/* ---------------------------------------------------------- *
* Set SSLv2 client hello, also announce SSLv3 and TLSv1 *
* ---------------------------------------------------------- */
method = SSLv23_client_method();
/* ---------------------------------------------------------- *
* Try to create a new SSL context *
* ---------------------------------------------------------- */
if ( (ctx = SSL_CTX_new(method)) == NULL)
BIO_printf(outbio, "Unable to create a new SSL context structure.\n");
/* ---------------------------------------------------------- *
* Disabling SSLv2 will leave v3 and TSLv1 for negotiation *
* ---------------------------------------------------------- */
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
/* ---------------------------------------------------------- *
* Create new SSL connection state object *
* ---------------------------------------------------------- */
ssl = SSL_new(ctx);
/* setting the start time*/
struct timespec start_time;
clock_gettime(CLOCK_REALTIME, &start_time);
start = start_time.tv_nsec;
if (math==0 ) { printf("Start time: %ld.%d\n",start_time.tv_sec,start);}
/* ---------------------------------------------------------- *
* Make the underlying TCP socket connection *
* ---------------------------------------------------------- */
server = create_socket(dest_url, outbio);
if(server != 0)
if(verbose==1){BIO_printf(outbio, "Successfully made the TCP connection to: %s.\n", dest_url);}
/* setting the tcp connection time*/
clock_gettime(CLOCK_REALTIME, &start_time);
tcp = start_time.tv_nsec;
epoch_tcp = start_time.tv_sec;
if (math==1)
{
if (tcp > start) {printf("TCP time: %6d\n",(tcp - start)/1000);}
else {printf("TCP time: %6d\n", (tcp+(1000000000-start))/1000);}
}
else { printf("TCP time: %ld.%d\n",start_time.tv_sec,tcp);}
/* ---------------------------------------------------------- *
* Attach the SSL session to the socket descriptor *
* ---------------------------------------------------------- */
SSL_set_fd(ssl, server);
/* ---------------------------------------------------------- *
* Try to SSL-connect here, returns 1 for success *
* ---------------------------------------------------------- */
if ( SSL_connect(ssl) != 1 )
BIO_printf(outbio, "Error: Could not build a SSL session to: %s.\n", dest_url);
else
if(verbose==1){BIO_printf(outbio, "Successfully enabled SSL/TLS session to: %s.\n", dest_url);}
/* setting the SSL time*/
clock_gettime(CLOCK_REALTIME, &start_time);
tls = start_time.tv_nsec;
if (start_time.tv_sec-1 > epoch_tcp)
{ printf("TLS took more than 2 seconds\n");}
if (math==1)
{
if (tls > tcp) {printf("SSL time: %6d\n",(tls - tcp)/1000);}
else {printf("SSL time: %6d\n", (tls+(1000000000-tcp))/1000);}
}
else { printf("SSL time: %ld.%d\n",start_time.tv_sec,tls);}
/* ---------------------------------------------------------- *
* Get the remote certificate into the X509 structure *
* ---------------------------------------------------------- */
cert = SSL_get_peer_certificate(ssl);
if (cert == NULL)
BIO_printf(outbio, "Error: Could not get a certificate from: %s.\n", dest_url);
else
if(verbose==1){BIO_printf(outbio, "Retrieved the server's certificate from: %s.\n", dest_url);}
/* ---------------------------------------------------------- *
* extract various certificate information *
* -----------------------------------------------------------*/
certname = X509_NAME_new();
certname = X509_get_subject_name(cert);
/* ---------------------------------------------------------- *
* display the cert subject here *
* -----------------------------------------------------------*/
if(verbose==1)
{
BIO_printf(outbio, "Displaying the certificate subject data:\n");
X509_NAME_print_ex(outbio, certname, 0, 0);
BIO_printf(outbio, "\n");
}
/* ---------------------------------------------------------- *
* Free the structures we don't need anymore *
* -----------------------------------------------------------*/
SSL_free(ssl);
close(server);
X509_free(cert);
SSL_CTX_free(ctx);
if(verbose==1){BIO_printf(outbio, "Finished SSL/TLS connection with server: %s.\n", dest_url);}
return(0);
}
/* ---------------------------------------------------------- *
* create_socket() creates the socket & TCP-connect to server *
* ---------------------------------------------------------- */
int create_socket(char url_str[], BIO *out) {
int sockfd;
char hostname[256] = "";
char portnum[6] = "443";
char proto[6] = "";
char *tmp_ptr = NULL;
int port;
struct hostent *host;
struct sockaddr_in dest_addr;
/* ---------------------------------------------------------- *
* Remove the final / from url_str, if there is one *
* ---------------------------------------------------------- */
if(url_str[strlen(url_str)] == '/')
url_str[strlen(url_str)] = '\0';
/* ---------------------------------------------------------- *
* the first : ends the protocol string, i.e. http *
* ---------------------------------------------------------- */
strncpy(proto, url_str, (strchr(url_str, ':')-url_str));
/* ---------------------------------------------------------- *
* the hostname starts after the "://" part *
* ---------------------------------------------------------- */
strncpy(hostname, strstr(url_str, "://")+3, sizeof(hostname));
/* ---------------------------------------------------------- *
* if the hostname contains a colon :, we got a port number *
* ---------------------------------------------------------- */
if(strchr(hostname, ':')) {
tmp_ptr = strchr(hostname, ':');
/* the last : starts the port number, if avail, i.e. 8443 */
strncpy(portnum, tmp_ptr+1, sizeof(portnum));
*tmp_ptr = '\0';
}
port = atoi(portnum);
if ( (host = gethostbyname(hostname)) == NULL ) {
BIO_printf(out, "Error: Cannot resolve hostname %s.\n", hostname);
abort();
}
/* ---------------------------------------------------------- *
* create the basic TCP socket *
* ---------------------------------------------------------- */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons(port);
dest_addr.sin_addr.s_addr = *(long*)(host->h_addr);
/* ---------------------------------------------------------- *
* Zeroing the rest of the struct *
* ---------------------------------------------------------- */
memset(&(dest_addr.sin_zero), '\0', 8);
tmp_ptr = inet_ntoa(dest_addr.sin_addr);
/* ---------------------------------------------------------- *
* Try to make the host connect here *
* ---------------------------------------------------------- */
if ( connect(sockfd, (struct sockaddr *) &dest_addr,
sizeof(struct sockaddr)) == -1 ) {
BIO_printf(out, "Error: Cannot connect to host %s [%s] on port %d.\n",
hostname, tmp_ptr, port);
}
return sockfd;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment