Communication Samples

Some C code examples

Classes | Macros | Functions
myssl.c File Reference

SSL Client HTTP Connection example getting information and verifying certificates. These are just some SSL notes. More...

#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/select.h>
#include <sys/time.h>

Go to the source code of this file.

Classes

struct  Sslc
 

Macros

#define CAPATH   "/etc/ssl/certs"
 
#define BUFFERSIZE   16384
 
#define STRBUFFERSIZE   256
 
#define USERAGENT   "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0"
 
#define CRLF   "\r\n"
 

Functions

int ASN1_TIME_to_time_t (ASN1_TIME *time, time_t *tmt)
 
char * join (char *buffer, const char *origin, size_t *from, size_t size)
 
long int check_certificate_validity (X509 *certificate)
 
int TCP_Connection (Sslc *h, char *server, int port)
 
int TCP_select (Sslc *h, double timeout)
 
int SSL_Connection (Sslc *h)
 
int SSL_send (Sslc *h, char *msg)
 
int SSL_recv (Sslc *h, char **data)
 
void SSL_print_info (Sslc *h)
 
void SSL_print_certificate_info (X509 *cert)
 
char * SSL_cipher_description (SSL_CIPHER *cipher)
 
char * time_t_to_str (char *buffer, size_t bufsize, const char *format, time_t *tim)
 
void print_time (ASN1_TIME *asn1time, char *pre_string, char *dateformat)
 
void print_usage (char *executable)
 
void panic (char *msg)
 
int main (int argc, char *argv[])
 

Detailed Description

SSL Client HTTP Connection example getting information and verifying certificates. These are just some SSL notes.

Author
Gaspar Fernández blake.nosp@m.yed@.nosp@m.totak.nosp@m.i.co.nosp@m.m
Version
Date
17 abr 2015

To compile: $ gcc -o myssl myssl.c -lcrypto -lssl

Definition in file myssl.c.

Macro Definition Documentation

#define BUFFERSIZE   16384

16Kb SSL_read block size

Definition at line 36 of file myssl.c.

Referenced by SSL_recv().

#define CAPATH   "/etc/ssl/certs"

Where to look for the Certificate Authorities

Definition at line 34 of file myssl.c.

Referenced by check_certificate_validity(), and SSL_Connection().

#define CRLF   "\r\n"

CRLF

Definition at line 42 of file myssl.c.

#define STRBUFFERSIZE   256

For temporary strings

Definition at line 38 of file myssl.c.

Referenced by print_time(), SSL_cipher_description(), and SSL_print_certificate_info().

#define USERAGENT   "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0"

User agent string

Definition at line 40 of file myssl.c.

Function Documentation

int ASN1_TIME_to_time_t ( ASN1_TIME *  time,
time_t *  tmt 
)

Transforms ASN1 time sring to time_t (except milliseconds and time zone) Ideas from: http://stackoverflow.com/questions/10975542/asn1-time-conversion

Parameters
timeSSL ASN1_TIME pointer
tmttime_t pointer to write to
Returns
int 0 if OK, <0 if anything goes wrong

Definition at line 279 of file myssl.c.

References join().

Referenced by print_time().

280 {
281  const char* data = (char*)time->data;
282  size_t p = 0;
283  char buf[5];
284  struct tm t;
285 
286  memset(&t, 0, sizeof(t));
287  size_t datalen = strlen(data);
288 
289  if (time->type == V_ASN1_UTCTIME) {/* two digit year */
290  /* error checking YYMMDDHH at least */
291  if (datalen<8)
292  return -1;
293  t.tm_year = atoi (join(buf, data, &p, 2));
294  if (t.tm_year<70)
295  t.tm_year += 100;
296  datalen = strlen(data+2);
297  } else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
298  /* error checking YYYYMMDDHH at least*/
299  if (datalen<10)
300  return -1;
301 
302  t.tm_year = atoi (join(buf, data, &p, 4));
303  t.tm_year -= 1900;
304  datalen = strlen(data+4);
305  }
306 
307  /* the year is out of datalen. Now datalen is fixed */
308 
309  t.tm_mon = atoi (join(buf, data, &p, 2))-1; /* January is 0 for time_t */
310  t.tm_mday= atoi (join(buf, data, &p, 2));
311  t.tm_hour= atoi (join(buf, data, &p, 2));
312 
313  if (datalen<8)
314  return !(*tmt = mktime(&t));
315  t.tm_min = atoi (join(buf, data, &p, 2));
316 
317  if (datalen<10)
318  return !(*tmt = mktime(&t));
319  t.tm_sec = atoi (join(buf, data, &p, 2));
320 
321  /* Ignore millisecnds and time zone */
322  return !(*tmt = mktime(&t));
323 }
char * join(char *buffer, const char *origin, size_t *from, size_t size)
Definition: myssl.c:268
long int check_certificate_validity ( X509 *  certificate)

Check certificate validity

Parameters
certificateCertificate to check
Returns
error code (0 is OK. See x509_vfy.h for constants (X509_V_ERR_UNABLE_*). You can also use X509_verify_cert_error_string(long int) to see the error string

Definition at line 325 of file myssl.c.

References CAPATH.

Referenced by SSL_print_certificate_info().

326 {
327  int status;
328  X509_STORE_CTX *ctx;
329  ctx = X509_STORE_CTX_new();
330  X509_STORE *store = X509_STORE_new();
331  X509_STORE_load_locations(store, NULL, CAPATH);
332  X509_STORE_add_cert(store, certificate);
333 
334  X509_STORE_CTX_init(ctx, store, certificate, NULL);
335 
336  status = X509_verify_cert(ctx);
337 
338  return ctx->error;
339 }
#define CAPATH
Definition: myssl.c:34
char * join ( char *  buffer,
const char *  origin,
size_t *  from,
size_t  size 
)

Extract a substring from origin into buffer, updating starting value to call in chain. Used by ASN1_TIME_to_time_t to extract substrings easyly

Parameters
bufferWhere to write to
originOriginal string
fromWhere to start from. Updated to the last position after end.
sizeCharacters to extract.
Returns
char* reference to buffer

Definition at line 268 of file myssl.c.

Referenced by ASN1_TIME_to_time_t().

269 {
270  size_t i=0;
271  while (i<size)
272  {
273  buffer[i++] = origin[(*from)++];
274  }
275  buffer[i] = '\0';
276  return buffer;
277 }
void panic ( char *  msg)

Prints a tragic error and exit

Parameters
msgError text
Returns
void

Definition at line 586 of file myssl.c.

587 {
588  fprintf (stderr, "Error: %s (errno %d, %s)\n", msg, errno, strerror(errno));
589  /* Print SSL errors */
590  ERR_print_errors_fp(stderr);
591  exit(2);
592 }
void print_time ( ASN1_TIME *  asn1time,
char *  pre_string,
char *  dateformat 
)

Prints ASN1_TIME on screen

Parameters
asn1timeTime to write
pre_stringString to write before the date
dateformatDate format (
See Also
strftime())
Returns
void

Definition at line 557 of file myssl.c.

References ASN1_TIME_to_time_t(), STRBUFFERSIZE, and time_t_to_str().

Referenced by SSL_print_certificate_info().

558 {
559  time_t tim;
560  char buffer[STRBUFFERSIZE];
561 
562  if (ASN1_TIME_to_time_t(asn1time, &tim)==0)
563  printf ("%s: %s\n", pre_string, time_t_to_str(buffer, STRBUFFERSIZE, dateformat, &tim));
564  else
565  printf ("%s: (error)\n", pre_string);
566 }
int ASN1_TIME_to_time_t(ASN1_TIME *time, time_t *tmt)
Definition: myssl.c:279
#define STRBUFFERSIZE
Definition: myssl.c:38
char * time_t_to_str(char *buffer, size_t bufsize, const char *format, time_t *tim)
Definition: myssl.c:549
void print_usage ( char *  executable)

Prints program usage

Parameters
executableProgram executable (argv[0])
Returns
void

Definition at line 578 of file myssl.c.

579 {
580  fprintf(stderr, "You must specify a web server to connect through HTTPS and additionally a port:\n");
581  fprintf(stderr, " %s server [port]\n", executable);
582  fprintf(stderr, "------------\n\n");
583  exit(-1);
584 }
char * SSL_cipher_description ( SSL_CIPHER *  cipher)

Gets cipher description in a string Please free the resulting string, don't do it like me ;)

Parameters
cipherCipher
Returns
String with the description

Definition at line 568 of file myssl.c.

References STRBUFFERSIZE.

Referenced by SSL_print_info().

569 {
570  char *tmp = malloc(sizeof(char)*STRBUFFERSIZE);
571  tmp[0] = '\0';
572  if (cipher)
573  SSL_CIPHER_description(cipher, tmp, STRBUFFERSIZE);
574 
575  return tmp;
576 }
#define STRBUFFERSIZE
Definition: myssl.c:38
int SSL_Connection ( Sslc h)

SSL initialization and handshake

Parameters
hOur structure.
Returns
(0 if OK, else fail)

Definition at line 373 of file myssl.c.

References CAPATH, Sslc::ctx, Sslc::skt, and Sslc::ssl.

374 {
375  SSL_library_init(); /* not reentrant! */
376  SSL_load_error_strings();
377 
378  /* try SSL methods (TLSv1.2 ... SSLv3 and SSLv2 (caution! SSLv2 and SSLv3 are deprecated!) */
379  /* you could use TLSv1_client_method(), TLSv1_2_client_method()... */
380  h->ctx = SSL_CTX_new(SSLv23_client_method());
381  if (h->ctx == NULL)
382  return -3; /* Context not created */
383 
384  /* SSL will fail if cerificate can't be validated */
385  /* h->ctx->verify_mode = 1; */
386 
387  h->ssl = SSL_new (h->ctx);
388  if (h->ssl == NULL)
389  return -4; /* SSL struct not created */
390 
391  if (SSL_set_fd(h->ssl, h->skt) == 0)
392  return -5; /* Couldn't bind SSL with our connection */
393 
394  if (SSL_CTX_load_verify_locations(h->ctx, NULL, CAPATH) == 0)
395  return -6; /* Couldn't load verify locations */
396 
397  /* Verify depth. How many certs from the chain to verify */
398  /* -1 to verify all certificates. */
399  printf ("VDepth: %d\n", SSL_get_verify_depth(h->ssl));
400 
401  if (SSL_connect (h->ssl) < 1)
402  return -7; /* Couldn't finish SSL handshake */
403 
404  /* Get certificate information */
405  return 0;
406 }
#define CAPATH
Definition: myssl.c:34
int skt
Definition: myssl.c:51
SSL_CTX * ctx
Definition: myssl.c:57
SSL * ssl
Definition: myssl.c:55
void SSL_print_certificate_info ( X509 *  cert)

Prints out certificate information. Run throught the entries, print the not before and not after information and verify the certificate.

Parameters
certThe certificate to check
Returns
void

Definition at line 516 of file myssl.c.

References check_certificate_validity(), print_time(), and STRBUFFERSIZE.

Referenced by SSL_print_info().

517 {
518  X509_NAME *certname;
519  X509_NAME_ENTRY* entry;
520  char *s;
521  char buffer[STRBUFFERSIZE];
522  int i;
523 
524  certname = X509_get_subject_name(cert);
525  for (i=0; i< X509_NAME_entry_count(certname); i++)
526  {
527  entry = X509_NAME_get_entry(certname, i);
528  if (entry == NULL) /* error test. May exit the loop */
529  continue;
530 
531  /* extracted from X509_NAME_print_ex() */
532  int n = OBJ_obj2nid(entry->object);
533  if ((n == NID_undef) || ((s = (char*)OBJ_nid2sn(n)) == NULL))
534  {
535  i2t_ASN1_OBJECT(buffer, sizeof(buffer), entry->object);
536  s = buffer;
537  }
538  printf ("%s = %s\n", s, entry->value->data);
539  /* We must NOT free entries (they are internal pointers) */
540  }
541  print_time(X509_get_notBefore(cert), "Not Before", "%d/%m/%Y %H:%M:%S");
542  print_time(X509_get_notAfter(cert), "Not After", "%d/%m/%Y %H:%M:%S");
543  printf ("Valid certificate?: %s\n", X509_verify_cert_error_string(check_certificate_validity(cert)));
544 
545  /* We must NOT free X509_get_subject_name() objects */
546  /* X509_NAME_free(certname); */
547 }
#define STRBUFFERSIZE
Definition: myssl.c:38
void print_time(ASN1_TIME *asn1time, char *pre_string, char *dateformat)
Definition: myssl.c:557
long int check_certificate_validity(X509 *certificate)
Definition: myssl.c:325
void SSL_print_info ( Sslc h)

Prints out SSL information: SSL Version, cipher used and certificate information.

Parameters
hOur structure.
Returns
void

Definition at line 469 of file myssl.c.

References Sslc::ssl, SSL_cipher_description(), and SSL_print_certificate_info().

470 {
471  long vresult = SSL_get_verify_result (h->ssl);
472  X509* cert;
473  STACK_OF(X509) *chain;
474  int i;
475 
476  printf ("Verify result: %ld (%s)\n", vresult, X509_verify_cert_error_string(vresult));
477  printf ("Verify mode: %d\n", SSL_get_verify_mode(h->ssl)); /* If it's 1 SSL will fail if not verified */
478  printf ("SSL version: %s\n", SSL_get_version(h->ssl));
479  printf ("Cipher name : %s\n", SSL_get_cipher_name(h->ssl));
480  printf ("Cipher version: %s\n", SSL_get_cipher_version(h->ssl));
481  printf ("Cipher description: %s\n", SSL_cipher_description((SSL_CIPHER*)SSL_get_current_cipher(h->ssl)));
482  printf ("--------------------------------------------\n");
483  printf ("Certificate:\n");
484  cert = SSL_get_peer_certificate(h->ssl);
485  if (cert)
486  {
488  /* X509_free(cert); */
489  }
490  else
491  fprintf(stderr, "------ ERROR: Peer certificate not present!!\n");
492 
493  printf ("--------------------------------------------\n");
494  printf ("The entire certificate chain: \n");
495  chain = SSL_get_peer_cert_chain(h->ssl);
496  if (chain)
497  {
498  printf ("Certificates on chain: %d\n", sk_X509_num(chain));
499  for (i=0; i<sk_X509_num(chain); i++)
500  {
501  cert = sk_X509_value(chain, i);
502  if (cert)
503  {
505  /* Not a good idea to free, it's an internal pointer and may
506  break something*/
507  /* X509_free(cert); */
508  printf (" ·················\n");
509  }
510  }
511  }
512  else
513  fprintf (stderr, "------- ERROR: Couldn't get certificate chain!!\n");
514 }
char * SSL_cipher_description(SSL_CIPHER *cipher)
Definition: myssl.c:568
void SSL_print_certificate_info(X509 *cert)
Definition: myssl.c:516
SSL * ssl
Definition: myssl.c:55
int SSL_recv ( Sslc h,
char **  data 
)

SSL recv. To be called instead of recs. It will read the socket and decode information, or even perform a handshake if needed

Parameters
hOur structure.
dataData to be read (caution a pointer by reference that must be freed manually
Returns
(0 if OK, else fail)

Definition at line 433 of file myssl.c.

References BUFFERSIZE, Sslc::ssl, and TCP_select().

434 {
435  size_t bytes, totalbytes = 0;
436  char buffer[BUFFERSIZE];
437  int sel;
438  size_t allocated = BUFFERSIZE;
439  *data = malloc (sizeof(char) * BUFFERSIZE);
440  *data[0] = '\0';
441 
442  while (1)
443  {
444  sel = TCP_select(h, 1);
445  if (sel<0)
446  return -6; /* select fail */
447  else if (sel==0)
448  {
449  return totalbytes;
450  }
451  /* We must include terminator after reading */
452  bytes = SSL_read (h->ssl, buffer, BUFFERSIZE -1);
453  buffer[bytes] = '\0';
454 
455  if (bytes<1)
456  return -7;
457 
458  if (totalbytes + bytes > allocated)
459  {
460  allocated+=BUFFERSIZE;
461  *data = realloc(*data, allocated * sizeof(char));
462  }
463  strcat(*data, buffer);
464  totalbytes+=bytes;
465  }
466  return totalbytes;
467 }
int TCP_select(Sslc *h, double timeout)
Definition: myssl.c:417
#define BUFFERSIZE
Definition: myssl.c:36
SSL * ssl
Definition: myssl.c:55
int SSL_send ( Sslc h,
char *  msg 
)

SSL send. To be called instead of send. It will send data through the socket and decode information, or even perform a handshake if needed.

Parameters
hOur structure.
msgMessage to send
Returns
(0 if OK, else fail)

Definition at line 408 of file myssl.c.

References Sslc::err, and Sslc::ssl.

409 {
410  int bytes = SSL_write(h->ssl, msg, strlen(msg));
411  if (bytes<1)
412  h->err = bytes;
413 
414  return bytes;
415 }
int err
Definition: myssl.c:53
SSL * ssl
Definition: myssl.c:55
int TCP_Connection ( Sslc h,
char *  server,
int  port 
)

Creates a basic TCP client connection to a server on a port. Uses simple sockets

Parameters
hOur structure. Only the socket will be used
serverWhere to connect
portThe port to use (443 for HTTPS)
Returns
int (0 if OK, else fail)

Definition at line 341 of file myssl.c.

References Sslc::err, and Sslc::skt.

342 {
343  h->err = 0;
344  struct hostent *host = gethostbyname (server);
345  struct sockaddr_in addr;
346 
347  if (host == NULL)
348  return -1; /* Couldn't get host */
349 
350  h->skt = socket (AF_INET, SOCK_STREAM, 0);
351  if (h->skt < 0)
352  {
353  return -2;
354  }
355  else
356  {
357  /* fill in address data */
358  addr.sin_family = AF_INET;
359  addr.sin_port = htons (port);
360  addr.sin_addr = *((struct in_addr *) host->h_addr);
361  bzero (&(addr.sin_zero), 8);
362 
363  /* connect */
364  h->err = connect (h->skt, (struct sockaddr *) &addr, sizeof (struct sockaddr));
365  if (h->err == -1)
366  {
367  return -3;
368  }
369  }
370  return 0;
371 }
int err
Definition: myssl.c:53
int skt
Definition: myssl.c:51
int TCP_select ( Sslc h,
double  timeout 
)

Uses select to test if there is anything waiting to be read.

Parameters
hOur structure. Only the socket will be used
timeoutTimeout before giving up
Returns
(0 timeout, 1 data waiting, <0 fail)

Definition at line 417 of file myssl.c.

References Sslc::skt.

Referenced by SSL_recv().

418 {
419  fd_set fds;
420  FD_ZERO(&fds);
421  FD_SET(h->skt, &fds);
422  fd_set *rset=&fds;
423  fd_set *wset=NULL;
424 
425  struct timeval tv;
426  tv.tv_sec = (int)(timeout);
427  tv.tv_usec = (int)((timeout - (int)(timeout)) * 1000000.0);
428 
429  int ret = select(h->skt+1, rset, wset, NULL, &tv);
430  return ret;
431 }
int skt
Definition: myssl.c:51
char * time_t_to_str ( char *  buffer,
size_t  bufsize,
const char *  format,
time_t *  tim 
)

Gets a string with the time_t into a string

Parameters
bufferBuffer to write to
bufsizeTotal buffer size
formatDate/Time format (
See Also
strftime())
Parameters
timTime
Returns
buffer

Definition at line 549 of file myssl.c.

Referenced by print_time().

550 {
551  struct tm _tm;
552  gmtime_r(tim, &_tm);
553  strftime(buffer, bufsize, format, &_tm);
554  return buffer;
555 }