]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added program to estimate the timings in different record paddings.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 20 Jan 2013 19:39:07 +0000 (20:39 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 20 Jan 2013 19:39:07 +0000 (20:39 +0100)
.gitignore
tests/suite/Makefile.am
tests/suite/mini-record-timing.c [new file with mode: 0644]

index f95b182293182cfd3705795e2c348969b3e7ff4e..147c4629f5cd600417afbc0aabd744829bb552f2 100644 (file)
@@ -524,6 +524,7 @@ tests/mini-loss
 tests/mini-loss-time
 tests/mini-loss2
 tests/mini-record
+tests/suite/mini-record-timing
 tests/mini-rehandshake
 tests/mini-tdb
 tests/mini-termination
@@ -627,3 +628,5 @@ gl/tests/test-u8-uctomb
 tmp-compare-makefile
 tests/mini-dtls-record
 tests/mini-x509-rehandshake
+tests/mini-sbuf
+tests/suite/mini-record-timing
index 36d379bf43496c9fc401c27b0eba6043db5e61b6..1ba8d5bf3523f1ce33e365798c873c793b11851d 100644 (file)
@@ -92,7 +92,7 @@ noinst_LTLIBRARIES = libecore.la
 eagain_cli_LDADD = libecore.la -lrt -lm -ldl -lpthread $(LDADD)
 nodist_eagain_cli_SOURCES = mini-eagain2.c
 
-noinst_PROGRAMS = eagain-cli
+noinst_PROGRAMS = eagain-cli mini-record-timing
 
 TESTS += eagain
 endif
diff --git a/tests/suite/mini-record-timing.c b/tests/suite/mini-record-timing.c
new file mode 100644 (file)
index 0000000..6363ff2
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GnuTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(_WIN32)
+
+int main()
+{
+  exit(77);
+}
+
+#else
+
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <time.h>
+#include <timespec.h>
+#include <sys/time.h>
+
+#ifdef DEBUG
+static void
+server_log_func (int level, const char *str)
+{
+  fprintf (stderr, "server|<%d>| %s", level, str);
+}
+
+static void
+client_log_func (int level, const char *str)
+{
+  fprintf (stderr, "client|<%d>| %s", level, str);
+}
+#endif
+
+static void terminate(void);
+
+/* This program tests the robustness of record
+ * decoding.
+ */
+
+static unsigned char server_cert_pem[] =
+"-----BEGIN CERTIFICATE-----\n"
+"MIIBeTCCASWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDEwROb25l\n"
+"MCIYDzIwMTMwMTE5MTA0MDAwWhgPMjA0MDA2MDUxMDQwMDBaMA8xDTALBgNVBAMT\n"
+"BE5vbmUwWTANBgkqhkiG9w0BAQEFAANIADBFAj4Bh52/b3FNXDdICg1Obqu9ivW+\n"
+"PGJ89mNsX3O9S/aclnx5Ozw9MC1UJuZ2UEHl27YVmm4xG/y3nKUNevZjKwIDAQAB\n"
+"o2swaTAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDATBgNVHSUE\n"
+"DDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB6AAMB0GA1UdDgQWBBRhEgmVCi6c\n"
+"hhRQvMzfEXqLKTRxcTANBgkqhkiG9w0BAQsFAAM/AADMi31wr0Tp2SJUCuQjFVCb\n"
+"JDleomTayOWVS/afCyAUxYjqFfUFSZ8sYN3zAgnXt5DYO3VclIlax4n6iXOg\n"
+"-----END CERTIFICATE-----\n";
+
+const gnutls_datum_t server_cert = { server_cert_pem,
+  sizeof (server_cert_pem)
+};
+
+static unsigned char server_key_pem[] =
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIBLAIBAAI+AYedv29xTVw3SAoNTm6rvYr1vjxifPZjbF9zvUv2nJZ8eTs8PTAt\n"
+"VCbmdlBB5du2FZpuMRv8t5ylDXr2YysCAwEAAQI9EPt8Q77sFeWn0BfHoPD9pTsG\n"
+"5uN2e9DP8Eu6l8K4AcOuEsEkqZzvxgqZPA68pw8BZ5xKINMFdRPHmrX/cQIfHsdq\n"
+"aMDYR/moqgj8MbupqOr/48iorTk/D//2lgAMnwIfDLk3UWGvPiv6fNTlEnTgVn6o\n"
+"TdL0mvpkixebQ5RR9QIfHDjkRGtXph+xXUBh50RZXE8nFfl/WV7diVE+DOq8pwIf\n"
+"BxdOwjdsAH1oLBxG0sN6qBoM2NrCYoE8edydNsu55QIfEWsrlJnO/t0GzHy7qWdV\n"
+"zi9JMPu9MTDhOGmqPQO7Xw==\n"
+"-----END RSA PRIVATE KEY-----\n";
+
+
+const gnutls_datum_t server_key = { server_key_pem,
+  sizeof (server_key_pem)
+};
+
+
+/* A very basic TLS client, with anonymous authentication.
+ */
+
+#define MAX_BUF 1024
+
+#define MAX_PER_POINT (16*1024)
+#define MAX_MEASUREMENTS (MAX_PER_POINT*(sizeof(points)/sizeof(points[0])))
+
+struct point_st {
+  unsigned char byte1;
+  unsigned char byte2;
+  unsigned midx;
+  unsigned long measurements[MAX_PER_POINT];
+};
+
+static struct point_st points[] = {
+  { 0, 0, 0 },
+//  { 1, 1, 0 },
+//  { 14, 14, 0 },
+  { 253, 253, 0 },
+};
+
+struct point_st *prev_point_ptr = &points[0];
+unsigned int point_idx = 0;
+
+
+static ssize_t
+push(gnutls_transport_ptr_t tr, const void *_data, size_t len)
+{
+int fd = (long int)tr;
+    
+  return send(fd, _data, len, 0);
+}
+
+static ssize_t
+push_crippled (gnutls_transport_ptr_t tr, const void *_data, size_t len)
+{
+int fd = (long int)tr;
+unsigned char* data = (void*)_data;
+struct point_st * p = &points[point_idx];
+
+  memcpy(&data[len-32], data+5, 32);
+
+//fprintf(stderr, "sending: %d.%d: %d\n", (unsigned)p->byte1, (unsigned)p->byte2, (int)len);
+  data[len-17] ^= p->byte1;
+  data[len-18] ^= p->byte2;
+
+  prev_point_ptr = p;
+  point_idx++;
+  if (point_idx >= (sizeof(points)/sizeof(points[0])))
+    point_idx = 0;
+    
+  return send(fd, data, len, 0);
+}
+
+
+static unsigned long timespec_sub_us(struct timespec *a, struct timespec *b)
+{
+  return (a->tv_sec*1000*1000 + a->tv_nsec/1000 - (b->tv_sec *1000*1000 + 
+          b->tv_nsec/1000));
+}
+
+static
+double calc_avg(unsigned long *diffs, unsigned int diffs_size)
+{
+double avg = 0;
+unsigned int i;
+
+  for(i=0;i<diffs_size;i++)
+    avg += diffs[i];
+    
+  avg /= diffs_size;
+
+  return avg;
+}
+
+static int compar(const void* _a, const void* _b)
+{
+  unsigned long a, b;
+  
+  a = *((unsigned long*)_a);
+  b = *((unsigned long*)_b);
+  
+  if (a < b)
+    return -1;
+  else if (a==b)
+    return 0;
+  else
+    return 1;
+}
+
+static
+double calc_median(unsigned long *diffs, unsigned int diffs_size)
+{
+double med;
+
+  qsort(diffs, diffs_size, sizeof(diffs[0]), compar);
+    
+  med = diffs[diffs_size/2];
+
+  return med;
+}
+
+static
+double calc_var(unsigned long *diffs, unsigned int diffs_size, double avg)
+{
+double sum = 0, d;
+unsigned int i;
+
+  for (i=0;i<diffs_size;i++) {
+    d = ((double)diffs[i] - avg);
+    d *= d;
+    
+    sum += d;
+  }
+  sum /= diffs_size - 1;
+  
+  return sum;
+}
+
+
+static void
+client (int fd, const char* prio, unsigned int text_size)
+{
+  int ret;
+  char buffer[MAX_BUF + 1];
+  char text[text_size];
+  gnutls_certificate_credentials_t x509_cred;
+  gnutls_session_t session;
+  struct timespec start, stop;
+  static unsigned int taken = 0;
+  static unsigned long *measurements;
+  static unsigned long min = 0, max = 0;
+  const char* err;
+
+  measurements = malloc(sizeof(measurements[0])*MAX_MEASUREMENTS);
+  if (measurements == NULL)
+    exit(1);
+
+  gnutls_global_init ();
+  
+  setpriority(PRIO_PROCESS, getpid(), -15);
+  
+  memset(text, 0, text_size);
+
+#ifdef DEBUG
+  gnutls_global_set_log_function (client_log_func);
+  gnutls_global_set_log_level (6);
+#endif
+
+  gnutls_certificate_allocate_credentials (&x509_cred);
+
+  /* Initialize TLS session
+   */
+restart:
+  gnutls_init (&session, GNUTLS_CLIENT);
+
+  /* Use default priorities */
+  if (gnutls_priority_set_direct (session, prio, &err) < 0) {
+    fprintf(stderr, "Error in %s\n", err);
+    exit(1);
+  }
+
+  /* put the anonymous credentials to the current session
+   */
+  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd);
+
+  /* Perform the TLS handshake
+   */
+  do 
+    {
+      ret = gnutls_handshake (session);
+    }
+  while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
+
+  if (ret < 0)
+    {
+      fprintf (stderr, "client: Handshake failed\n");
+      gnutls_perror (ret);
+      exit(1);
+    }
+    
+  if (gnutls_protocol_get_version(session) != GNUTLS_TLS1_1)
+    {
+      fprintf (stderr, "client: Handshake didn't negotiate TLS 1.1\n");
+      exit(1);
+    }
+
+  gnutls_transport_set_push_function (session, push_crippled);
+  do {
+    ret = gnutls_record_send (session, text, sizeof(text));
+  } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+  /* measure peer's processing time */
+  gettime(&start);
+
+#define TLS_RECV
+#ifdef TLS_RECV
+  do {
+    ret = gnutls_record_recv(session, buffer, sizeof(buffer));
+  } while(ret < 0 && (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED));
+#else
+  do {
+    ret = recv(fd, buffer, sizeof(buffer), 0);
+  } while(ret == -1 && errno == EAGAIN);
+#endif
+
+  if (taken < MAX_MEASUREMENTS)
+    {
+      gettime(&stop);
+      measurements[taken] = timespec_sub_us(&stop, &start);
+
+      if (min > measurements[taken] || min == 0)
+        min = measurements[taken];
+      if (max < measurements[taken])
+        max = measurements[taken];
+
+//fprintf(stderr, "(%u,%u): %lu\n", (unsigned) prev_point_ptr->byte1,
+// (unsigned) prev_point_ptr->byte2, measurements[taken]);
+      prev_point_ptr->measurements[prev_point_ptr->midx++] = measurements[taken];
+      taken++;
+      
+      gnutls_deinit(session);
+      
+      goto restart;
+    }
+#ifndef TLS_RECV
+  else if (ret < 0)
+    {
+      fprintf(stderr, "Error in recv()\n");
+      exit(1);
+    }
+#endif
+
+  gnutls_transport_set_push_function (session, push);
+    
+  gnutls_bye (session, GNUTLS_SHUT_WR);
+  
+  {
+    double avg1, avg2, var, med;
+    unsigned i;
+    
+    printf("Taken %u measurements\n", taken);
+    avg1 = calc_avg(measurements, taken);
+    med = calc_median(measurements, taken);
+    
+    var = calc_var(measurements, taken, avg1);
+    
+    printf("Average processing time: %.3f microsec, Median: %.3f Variance: %.3f\n", avg1, med, var);
+    printf("(Min,Max)=(%lu,%lu)\n\n", min, max);
+
+    for (i=0;i<sizeof(points)/sizeof(points[0]);i++)
+      {
+        avg2 = calc_avg( points[i].measurements, points[i].midx);
+        var = calc_var(points[i].measurements, points[i].midx, avg2);
+        med = calc_median(points[i].measurements, points[i].midx);
+        printf("(%u,%u) Avg: %.3f microsec, Median: %.3f, Variance: %.3f\n", (unsigned)points[i].byte2, (unsigned)points[i].byte1, 
+               avg2, med, var);
+        if (i > 0)
+          {
+            printf("Avg diff (%u,%u)-(%u,%u)=%.3f\n", 
+                   (unsigned)points[0].byte2, (unsigned)points[0].byte1,
+                   (unsigned)points[i].byte2, (unsigned)points[i].byte1,
+                   avg1-avg2);
+          
+          }
+        else
+          avg1 = avg2;
+      }
+  }
+
+  close (fd);
+
+  gnutls_deinit (session);
+
+  gnutls_certificate_free_credentials (x509_cred);
+
+  gnutls_global_deinit ();
+}
+
+
+/* These are global */
+pid_t child;
+
+static void terminate(void)
+{
+  kill(child, SIGTERM);
+  exit(1);
+}
+
+static void
+server (int fd, const char* prio)
+{
+int ret;
+char buffer[MAX_BUF + 1];
+gnutls_session_t session;
+gnutls_certificate_credentials_t x509_cred;
+const char* err;
+
+  setpriority(PRIO_PROCESS, getpid(), -15);
+
+  /* this must be called once in the program
+   */
+  gnutls_global_init ();
+  memset(buffer, 0, sizeof(buffer));
+
+#ifdef DEBUG
+  gnutls_global_set_log_function (server_log_func);
+  gnutls_global_set_log_level (6);
+#endif
+
+  gnutls_certificate_allocate_credentials (&x509_cred);
+  ret = gnutls_certificate_set_x509_key_mem (x509_cred, &server_cert, &server_key,
+                                       GNUTLS_X509_FMT_PEM);
+  if (ret < 0)
+    {
+      fprintf(stderr, "Could not set certificate\n");
+      terminate();
+    }
+
+restart:
+  gnutls_init (&session, GNUTLS_SERVER);
+
+  /* avoid calling all the priority functions, since the defaults
+   * are adequate.
+   */
+  if (gnutls_priority_set_direct (session, prio, &err) < 0) {
+    fprintf(stderr, "Error in %s\n", err);
+    terminate();
+  }
+
+  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd);
+
+  do 
+    {
+      ret = gnutls_handshake (session);
+    }
+  while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
+  if (ret < 0)
+    {
+#ifdef GNUTLS_E_PREMATURE_TERMINATION
+      if (ret != GNUTLS_E_PREMATURE_TERMINATION && ret != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+#else
+      if (ret != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+#endif
+        {
+          close (fd);
+          gnutls_deinit (session);
+          fprintf( stderr, "server: Handshake has failed (%s)\n\n", gnutls_strerror (ret));
+          terminate();
+        }
+      goto finish;
+    }
+
+  do {
+    ret = gnutls_record_recv (session, buffer, sizeof (buffer));
+  } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+
+  if (ret < 0)
+    {
+      do {
+        ret = gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_BAD_RECORD_MAC);
+      } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+      gnutls_deinit(session);
+      goto restart;
+    }
+
+  /* do not wait for the peer to close the connection.
+   */
+  gnutls_bye (session, GNUTLS_SHUT_WR);
+
+finish:
+  close (fd);
+  gnutls_deinit (session);
+
+  gnutls_certificate_free_credentials (x509_cred);
+
+  gnutls_global_deinit ();
+
+}
+
+static void start (const char* prio, unsigned int text_size)
+{
+  int fd[2];
+  int ret;
+  
+  ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
+  if (ret < 0)
+    {
+      perror("socketpair");
+      exit(1);
+    }
+
+  child = fork ();
+  if (child < 0)
+    {
+      perror ("fork");
+      fprintf( stderr, "fork");
+      exit(1);
+    }
+
+  if (child)
+    {
+      /* parent */
+      close(fd[1]);
+      server (fd[0], prio);
+      kill(child, SIGTERM);
+    }
+  else 
+    {
+      close(fd[0]);
+      client (fd[1], prio, text_size);
+      exit(0);
+    }
+}
+
+static void ch_handler(int sig)
+{
+int status;
+  wait(&status);
+  if (WEXITSTATUS(status) != 0 ||
+      (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV))
+    {
+      if (WIFSIGNALED(status))
+        fprintf(stderr, "Child died with sigsegv\n");
+      else
+        fprintf(stderr, "Child died with status %d\n", WEXITSTATUS(status));
+      terminate();
+    }
+  return;
+}
+
+int main(int argc, char** argv)
+{
+  signal(SIGCHLD, ch_handler);
+
+  printf("\nAES-SHA1 (GnuTLS attack)\n");
+  start("NONE:+COMP-NULL:+AES-128-CBC:+SHA1:+RSA:%COMPAT:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0", 18*16);
+//  start("PERFORMANCE:-CIPHER-ALL:+AES-128-CBC:-MAC-ALL:+SHA1:%COMPAT", 18*16);
+
+//  printf("\nAES-SHA1 (full plaintext recovery)\n");
+//  start("PERFORMANCE:-CIPHER-ALL:+AES-128-CBC:-MAC-ALL:+SHA1:%COMPAT", 2*16);
+
+//  printf("\nAES-SHA256\n");
+//  start("PERFORMANCE:-CIPHER-ALL:+AES-128-CBC:-MAC-ALL:+SHA256:%COMPAT");
+}
+
+#endif /* _WIN32 */
+