Communication Samples

Some C code examples

serverssl.c
Go to the documentation of this file.
1 /**
2 *************************************************************
3 * @file serverssl.c
4 * @brief Example web server using SSL connection.
5 * It will always send the same web. It's just a test
6 * to stablish a secure connection and send some data
7 * This server cannot attend simultaneous connections
8 *
9 * @author Gaspar Fernández <blakeyed@totaki.com>
10 * @version 0.1
11 * @date 18 apr 2015
12 *
13 * Changelog:
14 * 20150422 - Some more doc.
15 *
16 * To compile
17 * $ gcc -o serverssl serverssl.c -lcrypto -lssl
18 *
19 *************************************************************/
20 
21 #include <fcntl.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <netinet/in.h>
27 #include <resolv.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <arpa/inet.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <openssl/rand.h>
35 #include <openssl/ssl.h>
36 #include <openssl/err.h>
37 
38 /** Port */
39 #define PORT 1430
40 
41 /** Buffer Size to use */
42 #define BUFFERSIZE 16384
43 
44 /** CRLF */
45 #define CRLF "\r\n"
46 
47 /** The only response of this server */
48 #define RESPONSE "HTTP/1.1 200 OK" CRLF \
49  "Content-Type: text/html charset=utf-8" CRLF \
50  "Server: ServerTest" CRLF \
51  CRLF \
52  "<html><head><title>Server Test</title></head><body>This is just a test</body></html>" CRLF
53 
54 /** Certificate file, or certificate chain file */
55 #define CERTFILE "sslserverchain.pem"
56 /** Key file */
57 #define KEYFILE "sslserver.key"
58 
59 /** sslc handles SSL and SSL_CTX and socket.
60  The same as myssl.c */
61 typedef struct
62 {
63  /** socket handler */
64  int skt;
65  /** client socket handler */
67  /** error, if any */
68  int err;
69  /** SSL handler */
70  SSL* ssl;
71  /** SSL Context */
72  SSL_CTX* ctx;
73 } Sslc;
74 
75 /**
76  *
77  * @param h Our struct
78  * @param port Por to listen to
79  *
80  * @return (0 if OK, else fail)
81  */
82 int TCP_Server(Sslc* h, int port);
83 
84 /**
85  * Uses select to test if there is anything waiting to be read.
86  * The same function as myssl.c
87  *
88  * @param h Our structure. Only the socket will be used
89  * @param timeout Timeout before giving up
90  *
91  * @return (0 timeout, 1 data waiting, <0 fail)
92  */
93 int TCP_select(Sslc* h, double timeout);
94 
95 /**
96  * Initializes SSL connection and creates the SSL Context
97  *
98  * @param h Our struct to store everything
99  *
100  * @return 0 if OK
101  */
102 int SSL_init(Sslc* h);
103 
104 /**
105  * Loads certificates in the context.
106  *
107  * @param h Our struct to store everything
108  * @param cert PEM certificate file or chain (we can store several
109  * certificates in one file, just concatenating them.
110  * @param key Encryption key
111  *
112  * @return 0 if OK
113  */
114 int SSL_load_certificates(Sslc* h, char* cert, char* key);
115 
116 /**
117  * Accepts client and start dialog
118  *
119  * @param h Our struct
120  *
121  * @return 0 if OK
122  */
123 int TCP_acceptClient(Sslc* h);
124 
125 /**
126  * Just a test, replace SSL_clientDialog() in acceptClient() by
127  * TCP_clientDialog() to create an insecure web server.
128  *
129  * @param h Our struct
130  *
131  * @return 0 if OK
132  */
133 int TCP_clientDialog(Sslc* h);
134 
135 /**
136  * It's everything we're here for. SSL dialog with the clients
137  *
138  * @param h Our struct
139  *
140  * @return 0 if OK
141  */
142 int SSL_clientDialog(Sslc* h);
143 
144 /**
145  * Prints a tragic error and exit
146  *
147  * @param msg Error text
148  *
149  * @return void
150  */
151 void panic(char* msg);
152 
153 /**
154  * ASCII clock to wait for clients
155  *
156  * @param loop Just a number, when it changes, it draws a new character.
157  * If loop == 0, restarts
158  *
159  * @return void
160  */
161 void aclock(int loop);
162 
163 int main(int argv, char** argc){
164 
165  Sslc sslc;
166  int activated=1;
167  int loop=0;
168  int sel_res;
169 
170  if (SSL_init(&sslc)<0)
171  panic ("Couldn't initialize SSL");
172 
174  panic ("Couln't load certificates");
175 
176  if (TCP_Server(&sslc, PORT)<0)
177  panic ("Couldn't make a TCP Connection");
178 
179  while(activated)
180  {
181  aclock(loop);
182  sel_res =TCP_select(&sslc, 1);
183  if (sel_res<0)
184  panic("Failed on selec()");
185  else if (sel_res==1)
186  {
187  if (TCP_acceptClient(&sslc)<0)
188  panic ("Tragic error accepting client");
189  loop = -1; /* Reset clock */
190  }
191 
192  loop++;
193  }
194 
195  /* Wont' reach this point as the server never ends... */
196  close(sslc.skt);
197 
198  return 0;
199 }
200 
201 int TCP_Server(Sslc* h, int port)
202 {
203  struct sockaddr_in my_addr;
204 
205  h->skt = socket(AF_INET, SOCK_STREAM, 0);
206  if(h->skt < 0)
207  return -1;
208 
209  my_addr.sin_family = AF_INET ;
210  my_addr.sin_port = htons(port);
211  my_addr.sin_addr.s_addr = INADDR_ANY ;
212 
213  if( bind( h->skt, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 )
214  return -2;
215 
216  if(listen( h->skt, 10) == -1 )
217  return -3;
218 
219  return 0;
220 }
221 
222 int TCP_select(Sslc* h, double timeout)
223 {
224  fd_set fds;
225  FD_ZERO(&fds);
226  FD_SET(h->skt, &fds);
227  fd_set *rset=&fds;
228  fd_set *wset=NULL;
229 
230  struct timeval tv;
231  tv.tv_sec = (int)(timeout);
232  tv.tv_usec = (int)((timeout - (int)(timeout)) * 1000000.0);
233 
234  int ret = select(h->skt+1, rset, wset, NULL, &tv);
235  return ret;
236 }
237 
239 {
240  struct sockaddr_in client_addr;
241  socklen_t size_addr = sizeof(struct sockaddr_in);
242 
243  if ((h->client_skt = accept( h->skt, (struct sockaddr*)&client_addr, &size_addr))!= -1)
244  {
245  printf("\nNew client connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
246  int r = SSL_clientDialog(h);
247  if (r<0)
248  {
249  printf ("There was a problem with this client connection\n");
250  ERR_print_errors_fp(stderr);
251  }
252  close(h->client_skt);
253  }
254 
255  /* Returns 0 to avoid tragic fails, just display on screen*/
256  return -6;
257 }
258 
260 {
261  char buffer[BUFFERSIZE];
262  int bytecount;
263 
264  memset(buffer, 0, BUFFERSIZE);
265  if((bytecount = recv(h->client_skt, buffer, BUFFERSIZE, 0))== -1)
266  return -7;
267 
268  if (send(h->client_skt, RESPONSE, strlen(RESPONSE), 0)<0)
269  return -8;
270 
271  return 0;
272 }
273 
275 {
276  char buffer[BUFFERSIZE];
277  int bytecount;
278 
279  h->ssl = SSL_new(h->ctx);
280  if (h->ssl == NULL)
281  return -11;
282  /* SSL_set_options(h->ssl, SSL_OP_ALL ); */
283 
284  if (SSL_set_fd(h->ssl, h->client_skt) == 0)
285  return -12;
286 
287  /* Accept SSL connection and handshake */
288  if (SSL_accept(h->ssl) < 1)
289  return -13;
290 
291  memset(buffer, 0, BUFFERSIZE);
292  if((bytecount = SSL_read(h->ssl, buffer, BUFFERSIZE)) < 1)
293  return -7;
294 
295  if (SSL_write(h->ssl, RESPONSE, strlen(RESPONSE))< 1)
296  return -8;
297 
298  SSL_free(h->ssl); /* free mem */
299 
300  return 0;
301 }
302 
303 int SSL_init(Sslc* h)
304 {
305  SSL_library_init(); /* not reentrant! */
306 
307  SSL_load_error_strings();
308 
309  OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
310 
311  /* We can try SSLv23_server_method() to try several
312  methods, starting from the more secure*/
313  h->ctx = SSL_CTX_new(TLSv1_2_server_method());
314  if (h->ctx == NULL)
315  return -4;
316 
317  return 0;
318 }
319 
320 int SSL_load_certificates(Sslc* h, char* cert, char* key)
321 {
322  if ( SSL_CTX_use_certificate_chain_file(h->ctx, cert) < 1 )
323  return -8;
324 
325  /* set the private key */
326  if ( SSL_CTX_use_PrivateKey_file(h->ctx, key, SSL_FILETYPE_PEM) <= 0 )
327  return -9;
328 
329  /* verify private key */
330  if ( !SSL_CTX_check_private_key(h->ctx) )
331  {
332  printf("Private key doesn't match the public certificate\n");
333  return -10;
334  }
335 
336  return 0;
337 }
338 
339 void aclock(int loop)
340 {
341  if (loop==0)
342  printf("[SERVER] Waiting for connections ");
343 
344  printf("\033[1D"); /* ANSI code to go back 2 characters */
345  switch (loop%4)
346  {
347  case 0: printf("|"); break;
348  case 1: printf("/"); break;
349  case 2: printf("-"); break;
350  case 3: printf("\\"); break;
351  default: /* Nothing here */
352  break;
353  }
354 
355  fflush(stdout); /* Update screen */
356 }
357 
358 
359 void panic(char *msg)
360 {
361  fprintf (stderr, "Error: %s (errno %d, %s)\n", msg, errno, strerror(errno));
362  /* Print SSL errors */
363  ERR_print_errors_fp(stderr);
364  exit(2);
365 }
int TCP_clientDialog(Sslc *h)
Definition: serverssl.c:259
void panic(char *msg)
Definition: serverssl.c:359
int client_skt
Definition: serverssl.c:66
#define BUFFERSIZE
Definition: serverssl.c:42
int TCP_acceptClient(Sslc *h)
Definition: serverssl.c:238
int skt
Definition: myssl.c:51
int SSL_clientDialog(Sslc *h)
Definition: serverssl.c:274
int TCP_select(Sslc *h, double timeout)
Definition: serverssl.c:222
#define CERTFILE
Definition: serverssl.c:55
Definition: myssl.c:48
SSL_CTX * ctx
Definition: myssl.c:57
void aclock(int loop)
Definition: serverssl.c:339
#define KEYFILE
Definition: serverssl.c:57
#define RESPONSE
Definition: serverssl.c:48
int SSL_load_certificates(Sslc *h, char *cert, char *key)
Definition: serverssl.c:320
int TCP_Server(Sslc *h, int port)
Definition: serverssl.c:201
int SSL_init(Sslc *h)
Definition: serverssl.c:303
SSL * ssl
Definition: myssl.c:55
#define PORT
Definition: serverssl.c:39