client.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * A "simple" SSLeay 0.8.0 demo program
  3. *
  4. * This program implements a simple SSL v2 or v3 client
  5. * which connects to a web server and issues a "HEAD / HTTP/1.0"
  6. * command and prints the output.
  7. *
  8. * Written by Emil Sit <sit@mit.edu>
  9. */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <fcntl.h>
  14. #include <netdb.h>
  15. #include <netinet/in.h>
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <unistd.h>
  19. #include <openssl/ssl.h>
  20. #include <openssl/err.h>
  21. #include "slitheen.h"
  22. int my_connect( char *, int );
  23. void apps_ssl_info_callback( SSL *s, int where, int ret );
  24. int my_dumb_callback( int ok, X509_STORE_CTX *ctx ) {
  25. return 1;
  26. }
  27. int main( int argc, char **argv ) {
  28. SSL_CTX *ctx = NULL;
  29. SSL *session = NULL;
  30. char *command = "HEAD / HTTP/1.0\r\n\r\n";
  31. int s;
  32. int status;
  33. /* We first need to establish what sort of
  34. * connection we know how to make. We can use one of
  35. * SSLv23_client_method(), SSLv2_client_method() and
  36. * SSLv3_client_method().
  37. */
  38. const SSL_METHOD *meth = TLSv1_2_client_method();
  39. if (meth == NULL) {
  40. fprintf( stderr, "no method. :(\n" ); exit(1);
  41. }
  42. /* This enables all ciphers in SSLeay, these include:
  43. * DES, RC4, IDEA, RC2, Blowfish,
  44. * MD2, SHA, DSA.
  45. * See crypto/c_all.c
  46. */
  47. SSL_load_error_strings();
  48. OpenSSL_add_ssl_algorithms();
  49. /* Initialize the context. This is shared between SSL sessions
  50. * and can do FH caching.
  51. */
  52. ctx = SSL_CTX_new( meth );
  53. if ( ctx == NULL ) { fprintf( stderr, "no context. :(\n" ); exit(1);
  54. ERR_print_errors_fp(stderr);
  55. }
  56. SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384");
  57. /* Set slitheen callbacks */
  58. slitheen_init();
  59. SSL_CTX_set_client_hello_callback(ctx, slitheen_tag_hello);
  60. SSL_CTX_set_generate_ec_key_callback(ctx, slitheen_ec_seed_from_tag);
  61. SSL_CTX_set_generate_key_callback(ctx, slitheen_seed_from_tag);
  62. SSL_CTX_set_finished_mac_callback(ctx, slitheen_finished_mac);
  63. /* Set up a callback for each state change so we can see what's
  64. * going on */
  65. SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
  66. /* Set it up so tha we will connect to *any* site, regardless
  67. * of their certificate. */
  68. SSL_CTX_set_verify( ctx, SSL_VERIFY_NONE, my_dumb_callback );
  69. /* MACRO. Set's CTX options. Not sure. I think this enables bug
  70. * support hacks. */
  71. SSL_CTX_set_options(ctx,SSL_OP_ALL);
  72. /* Finally, we're all set so we can set up the session holder */
  73. session = SSL_new( ctx );
  74. if ( session == NULL ) { fprintf( stderr, "no session. :(\n" ); exit(1);}
  75. /* Make connection s.t. s is the appropriate fd */
  76. s = my_connect( (argc == 2) ? argv[1] : "scspc430.cs.uwaterloo.ca" , 8888 );
  77. /* Set up the SSL side of the connection */
  78. SSL_set_fd( session, s );
  79. status = SSL_connect( session );
  80. /* Check the results. */
  81. switch (SSL_get_error(session,status)) {
  82. case SSL_ERROR_NONE:
  83. /* Everything worked :-) */
  84. break;
  85. case SSL_ERROR_SSL:
  86. fprintf( stderr, "ssl handshake failure\n" );
  87. ERR_print_errors_fp(stderr);
  88. goto byebye;
  89. break;
  90. /* These are for NON-BLOCKING I/O only! */
  91. case SSL_ERROR_WANT_READ:
  92. case SSL_ERROR_WANT_WRITE:
  93. fprintf( stderr, "want read/write. Use blocking?\n" );
  94. goto byebye; break;
  95. case SSL_ERROR_WANT_CONNECT:
  96. fprintf( stderr, "want connect. sleep a while, try again." );
  97. goto byebye; break;
  98. case SSL_ERROR_SYSCALL:
  99. perror("SSL_connect");
  100. goto byebye; break;
  101. case SSL_ERROR_WANT_X509_LOOKUP:
  102. /* not used! */
  103. fprintf( stderr, "shouldn't be getting this.\n" );
  104. break;
  105. case SSL_ERROR_ZERO_RETURN:
  106. fprintf( stderr, "connection closed.\n" );
  107. goto byebye;
  108. }
  109. /*Resume session*/
  110. printf("Resuming session\n");
  111. SSL_SESSION *sess = SSL_get1_session(session);
  112. SSL_shutdown(session);
  113. SSL_free(session);
  114. close(s);
  115. s = my_connect( (argc == 2) ? argv[1] : "scspc430.cs.uwaterloo.ca" , 8888 );
  116. session = SSL_new(ctx);
  117. SSL_set_fd( session, s );
  118. SSL_set_session(session, sess);
  119. status = SSL_connect( session );
  120. switch (SSL_get_error(session,status)) {
  121. case SSL_ERROR_NONE:
  122. /* Everything worked :-) */
  123. break;
  124. case SSL_ERROR_SSL:
  125. fprintf( stderr, "ssl handshake failure\n" );
  126. ERR_print_errors_fp(stderr);
  127. goto byebye;
  128. break;
  129. /* These are for NON-BLOCKING I/O only! */
  130. case SSL_ERROR_WANT_READ:
  131. case SSL_ERROR_WANT_WRITE:
  132. fprintf( stderr, "want read/write. Use blocking?\n" );
  133. goto byebye; break;
  134. case SSL_ERROR_WANT_CONNECT:
  135. fprintf( stderr, "want connect. sleep a while, try again." );
  136. goto byebye; break;
  137. case SSL_ERROR_SYSCALL:
  138. perror("SSL_connect");
  139. goto byebye; break;
  140. case SSL_ERROR_WANT_X509_LOOKUP:
  141. /* not used! */
  142. fprintf( stderr, "shouldn't be getting this.\n" );
  143. break;
  144. case SSL_ERROR_ZERO_RETURN:
  145. fprintf( stderr, "connection closed.\n" );
  146. goto byebye;
  147. }
  148. byebye:
  149. /* close everything down */
  150. SSL_shutdown(session);
  151. close(s);
  152. SSL_free( session ); session = NULL;
  153. SSL_CTX_free(ctx);
  154. return 0;
  155. }
  156. /* returns a socket connected to host on port port */
  157. int my_connect( char *hostname, int port ) {
  158. struct hostent *remote_host;
  159. char local_hostname[256];
  160. struct sockaddr_in address;
  161. int s;
  162. /* Get a socket to work with. This socket will be in the Internet domain, and */
  163. /* will be a stream socket. */
  164. if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  165. perror( "connect: cannot create socket" );
  166. exit(1);
  167. }
  168. /* If hostname is NULL or of zero length, look up the local hostname */
  169. if ((hostname==NULL)||(hostname[0]=='\0'))
  170. {
  171. /* Get the local hostname */
  172. if (gethostname(local_hostname, sizeof(local_hostname))==-1)
  173. {
  174. perror("connect");
  175. exit(1);
  176. }
  177. /* Look up the remote host (local host) to get its network number */
  178. if ((remote_host=gethostbyname(local_hostname)) == NULL)
  179. {
  180. perror("connect");
  181. exit(1);
  182. }
  183. }
  184. else
  185. /* Look up the remote host to get its network number. */
  186. if ((remote_host=gethostbyname(hostname)) == NULL)
  187. {
  188. perror("connect");
  189. exit(1);
  190. }
  191. /* Initialize the address varaible, which specifies where
  192. connect() should attempt to connect. */
  193. bcopy(remote_host->h_addr, &address.sin_addr, remote_host->h_length);
  194. address.sin_family = AF_INET;
  195. address.sin_port = htons(port);
  196. if (!(connect(s, (struct sockaddr *)(&address), sizeof(address)) >= 0))
  197. {
  198. perror("connect");
  199. exit(1);
  200. }
  201. /* Set the socket to non-blocking mode */
  202. /* fcntl(s, F_SETFL, O_NONBLOCK); */
  203. return(s);
  204. }
  205. void apps_ssl_info_callback( SSL *s, int where, int ret )
  206. {
  207. char *str;
  208. int w;
  209. w=where& ~SSL_ST_MASK;
  210. if (w & SSL_ST_CONNECT) str="SSL_connect";
  211. else if (w & SSL_ST_ACCEPT) str="SSL_accept";
  212. else str="undefined";
  213. if (where & SSL_CB_LOOP)
  214. {
  215. fprintf(stderr,"%s: %s\n",str,SSL_state_string_long(s));
  216. }
  217. else if (where & SSL_CB_ALERT)
  218. {
  219. str=(where & SSL_CB_READ)?"read":"write";
  220. fprintf(stderr,"SSL3 alert %s:%s:%s\n",
  221. str,
  222. SSL_alert_type_string_long(ret),
  223. SSL_alert_desc_string_long(ret));
  224. }
  225. else if (where & SSL_CB_EXIT)
  226. {
  227. if (ret == 0)
  228. fprintf(stderr,"%s:failed in %s\n",
  229. str,SSL_state_string_long(s));
  230. else if (ret < 0)
  231. {
  232. fprintf(stderr,"%s:error in %s\n",
  233. str,SSL_state_string_long(s));
  234. }
  235. }
  236. }