1/*
2 * Remember to turn off CPU frequency scaling before testing.
3 */
4
5
6#include <polarssl/ctr_drbg.h>
7#include <polarssl/error.h>
8#include <polarssl/entropy.h>
9#include <polarssl/ssl.h>
10
11#include <polarssl/certs.h>
12
13#include <muduo/base/Thread.h>
14
15#include <boost/bind.hpp>
16
17#include <stdio.h>
18#include <sys/socket.h>
19#include <sys/time.h>
20
21bool useRSA = false;
22bool useECDHE = false;
23const int N = 500;
24
25double now()
26{
27  struct timeval tv;
28  gettimeofday(&tv, NULL);
29  return tv.tv_sec + tv.tv_usec / 1000000.0;
30}
31
32// FIXME: net_recv with buffer
33
34void clientThread(entropy_context* entropy, int* clientFd)
35{
36  ctr_drbg_context ctr_drbg;
37  ctr_drbg_init(&ctr_drbg, entropy_func, entropy, NULL, 0);
38
39  ssl_context ssl;
40  bzero(&ssl, sizeof ssl);
41  ssl_init(&ssl);
42  ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg);
43  ssl_set_bio(&ssl, &net_recv, clientFd, &net_send, clientFd);
44  ssl_set_endpoint(&ssl, SSL_IS_CLIENT);
45  ssl_set_authmode(&ssl, SSL_VERIFY_NONE);
46
47  for (int i = 0; i < N; ++i)
48  {
49    ssl_session_reset( &ssl );
50    int ret = 0;
51    while ( (ret = ssl_handshake(&ssl)) != 0)
52    {
53      if (ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE)
54      {
55        printf("client handshake failed %d\n", ret);
56        break;
57      }
58    }
59    if (i == 0)
60      printf("client done %s %s\n", ssl_get_version(&ssl), ssl_get_ciphersuite(&ssl));
61  }
62
63  ssl_free(&ssl);
64}
65
66void serverThread(entropy_context* entropy, int* serverFd)
67{
68  const char* srv_cert = test_srv_crt_ec;
69  const char* srv_key = test_srv_key_ec;
70  if (useRSA)
71  {
72    srv_cert = test_srv_crt;
73    srv_key = test_srv_key;
74  }
75  x509_crt cert;
76  x509_crt_init(&cert);
77  x509_crt_parse(&cert, reinterpret_cast<const unsigned char*>(srv_cert), strlen(srv_cert));
78  x509_crt_parse(&cert, reinterpret_cast<const unsigned char*>(test_ca_list), strlen(test_ca_list));
79
80  pk_context pkey;
81  pk_init(&pkey);
82  pk_parse_key(&pkey, reinterpret_cast<const unsigned char*>(srv_key), strlen(srv_key), NULL, 0);
83
84  ctr_drbg_context ctr_drbg;
85  ctr_drbg_init(&ctr_drbg, entropy_func, entropy, NULL, 0);
86
87  ssl_context ssl_server;
88  bzero(&ssl_server, sizeof ssl_server);
89  ssl_init(&ssl_server);
90  ssl_set_rng(&ssl_server, ctr_drbg_random, &ctr_drbg);
91  ssl_set_bio(&ssl_server, &net_recv, serverFd, &net_send, serverFd);
92  ssl_set_endpoint(&ssl_server, SSL_IS_SERVER);
93  ssl_set_authmode(&ssl_server, SSL_VERIFY_NONE);
94  ssl_set_ca_chain(&ssl_server, cert.next, NULL, NULL);
95  ssl_set_own_cert(&ssl_server, &cert, &pkey);
96  // ssl_set_dbg(&ssl_server, my_debug, (void*)"server");
97  ecp_group_id curves[] = { POLARSSL_ECP_DP_SECP256R1, POLARSSL_ECP_DP_NONE };
98  ssl_set_curves(&ssl_server, curves);
99  int ciphersuites[] = { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, 0 };
100  if (!useECDHE)
101    ssl_set_ciphersuites(&ssl_server, ciphersuites);
102
103  for (int i = 0; i < N; ++i)
104  {
105    ssl_session_reset(&ssl_server);
106    int ret = 0;
107    while ( (ret = ssl_handshake(&ssl_server)) != 0)
108    {
109      if (ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE)
110      {
111        printf("server handshake failed %d\n", ret);
112        break;
113      }
114    }
115    if (i == 0)
116      printf("server done %s %s\n", ssl_get_version(&ssl_server), ssl_get_ciphersuite(&ssl_server));
117  }
118
119  ssl_free(&ssl_server);
120  pk_free(&pkey);
121  x509_crt_free(&cert);
122}
123
124int main(int argc, char* argv[])
125{
126  unsigned char buf[16384] = { 0 };
127  entropy_context entropy;
128  entropy_init(&entropy);
129
130  if (argc > 1)
131    useRSA = true;
132
133  useECDHE = argc > 2;
134
135  int fds[2];
136  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
137    abort();
138
139  double start = now();
140  muduo::Thread client(boost::bind(&clientThread, &entropy, &fds[0]), "ssl client");
141  muduo::Thread server(boost::bind(&serverThread, &entropy, &fds[1]), "ssl server");
142  client.start();
143  server.start();
144
145  client.join();
146  server.join();
147  double elapsed = now() - start;
148  printf("%.2fs %.1f handshakes/s\n", elapsed, N / elapsed);
149  entropy_free(&entropy);
150}
151