ssl/tls: add proper const attributes to functions, context members
[tropicssl.git] / programs / ssl / ssl_server.c
blob278f1dd4ebe75febe785602d5eb74fb770024772
1 /*
2 * SSL server demonstration program
4 * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
6 * Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * * Neither the names of PolarSSL or XySSL nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #ifndef _CRT_SECURE_NO_DEPRECATE
37 #define _CRT_SECURE_NO_DEPRECATE 1
38 #endif
40 #ifdef WIN32
41 #include <windows.h>
42 #endif
44 #include <string.h>
45 #include <stdlib.h>
46 #include <stdio.h>
48 #include "tropicssl/havege.h"
49 #include "tropicssl/certs.h"
50 #include "tropicssl/x509.h"
51 #include "tropicssl/ssl.h"
52 #include "tropicssl/net.h"
54 #define HTTP_RESPONSE \
55 "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
56 "<h2><p><center>Successful connection using: %s\r\n"
59 * Computing a "safe" DH-1024 prime can take a very
60 * long time, so a precomputed value is provided below.
61 * You may run dh_genprime to generate a new value.
63 static const char *my_dhm_P =
64 "E4004C1F94182000103D883A448B3F80"
65 "2CE4B44A83301270002C20D0321CFD00"
66 "11CCEF784C26A400F43DFB901BCA7538"
67 "F2C6B176001CF5A0FD16D2C48B1D0C1C"
68 "F6AC8E1DA6BCC3B4E1F96B0564965300"
69 "FFA1D0B601EB2800F489AA512C4B248C"
70 "01F76949A60BB7F00A40B1EAB64BDD48" "E8A700D60B7F1200FA8E77B0A979DABF";
72 static const char *my_dhm_G = "4";
75 * Sorted by order of preference
77 static const int my_ciphers[] = {
78 SSL_EDH_RSA_AES_256_SHA,
79 SSL_EDH_RSA_CAMELLIA_256_SHA,
80 SSL_EDH_RSA_DES_168_SHA,
81 SSL_RSA_AES_256_SHA,
82 SSL_RSA_CAMELLIA_256_SHA,
83 SSL_RSA_AES_128_SHA,
84 SSL_RSA_CAMELLIA_128_SHA,
85 SSL_RSA_DES_168_SHA,
86 SSL_RSA_RC4_128_SHA,
87 SSL_RSA_RC4_128_MD5,
91 #define DEBUG_LEVEL 0
93 static void my_debug(void *ctx, int level, const char *str)
95 if (level < DEBUG_LEVEL) {
96 fprintf((FILE *) ctx, "%s", str);
97 fflush((FILE *) ctx);
102 * These session callbacks use a simple chained list
103 * to store and retrieve the session information.
105 ssl_session *s_list_1st = NULL;
106 ssl_session *cur, *prv;
108 static int my_get_session(ssl_context * ssl)
110 time_t t = time(NULL);
112 if (ssl->resume == 0)
113 return (1);
115 cur = s_list_1st;
116 prv = NULL;
118 while (cur != NULL) {
119 prv = cur;
120 cur = cur->next;
122 if (ssl->timeout != 0 && t - prv->start > ssl->timeout)
123 continue;
125 if (ssl->session->cipher != prv->cipher ||
126 ssl->session->length != prv->length)
127 continue;
129 if (memcmp(ssl->session->id, prv->id, prv->length) != 0)
130 continue;
132 memcpy(ssl->session->master, prv->master, 48);
133 return (0);
136 return (1);
139 static int my_set_session(ssl_context * ssl)
141 time_t t = time(NULL);
143 cur = s_list_1st;
144 prv = NULL;
146 while (cur != NULL) {
147 if (ssl->timeout != 0 && t - cur->start > ssl->timeout)
148 break; /* expired, reuse this slot */
150 if (memcmp(ssl->session->id, cur->id, cur->length) == 0)
151 break; /* client reconnected */
153 prv = cur;
154 cur = cur->next;
157 if (cur == NULL) {
158 cur = (ssl_session *) malloc(sizeof(ssl_session));
159 if (cur == NULL)
160 return (1);
162 if (prv == NULL)
163 s_list_1st = cur;
164 else
165 prv->next = cur;
168 memcpy(cur, ssl->session, sizeof(ssl_session));
170 return (0);
173 int main(void)
175 int ret, len;
176 int listen_fd;
177 int client_fd;
178 unsigned char buf[1024];
180 havege_state hs;
181 ssl_context ssl;
182 ssl_session ssn;
183 x509_cert srvcert;
184 rsa_context rsa;
187 * 1. Load the certificates and private RSA key
189 printf("\n . Loading the server cert. and key...");
190 fflush(stdout);
192 memset(&srvcert, 0, sizeof(x509_cert));
195 * This demonstration program uses embedded test certificates.
196 * Instead, you may want to use x509parse_crtfile() to read the
197 * server and CA certificates, as well as x509parse_keyfile().
199 ret = x509parse_crt(&srvcert, (unsigned char *)test_srv_crt,
200 strlen(test_srv_crt));
201 if (ret != 0) {
202 printf(" failed\n ! x509parse_crt returned %d\n\n", ret);
203 goto exit;
206 ret = x509parse_crt(&srvcert, (unsigned char *)test_ca_crt,
207 strlen(test_ca_crt));
208 if (ret != 0) {
209 printf(" failed\n ! x509parse_crt returned %d\n\n", ret);
210 goto exit;
213 ret = x509parse_key(&rsa, (unsigned char *)test_srv_key,
214 strlen(test_srv_key), NULL, 0);
215 if (ret != 0) {
216 printf(" failed\n ! x509parse_key returned %d\n\n", ret);
217 goto exit;
220 printf(" ok\n");
223 * 2. Setup the listening TCP socket
225 printf(" . Bind on https://localhost:4433/ ...");
226 fflush(stdout);
228 if ((ret = net_bind(&listen_fd, NULL, 4433)) != 0) {
229 printf(" failed\n ! net_bind returned %d\n\n", ret);
230 goto exit;
233 printf(" ok\n");
236 * 3. Wait until a client connects
238 #ifdef WIN32
239 ShellExecute(NULL, "open", "https://localhost:4433/",
240 NULL, NULL, SW_SHOWNORMAL);
241 #endif
243 client_fd = -1;
244 memset(&ssl, 0, sizeof(ssl));
246 accept:
248 net_close(client_fd);
249 ssl_free(&ssl);
251 printf(" . Waiting for a remote connection ...");
252 fflush(stdout);
254 if ((ret = net_accept(listen_fd, &client_fd, NULL)) != 0) {
255 printf(" failed\n ! net_accept returned %d\n\n", ret);
256 goto exit;
259 printf(" ok\n");
262 * 4. Setup stuff
264 printf(" . Setting up the RNG and SSL data....");
265 fflush(stdout);
267 havege_init(&hs);
269 if ((ret = ssl_init(&ssl)) != 0) {
270 printf(" failed\n ! ssl_init returned %d\n\n", ret);
271 goto accept;
274 printf(" ok\n");
276 ssl_set_endpoint(&ssl, SSL_IS_SERVER);
277 ssl_set_authmode(&ssl, SSL_VERIFY_NONE);
279 ssl_set_rng(&ssl, havege_rand, &hs);
280 ssl_set_dbg(&ssl, my_debug, stdout);
281 ssl_set_bio(&ssl, net_recv, &client_fd, net_send, &client_fd);
282 ssl_set_scb(&ssl, my_get_session, my_set_session);
284 ssl_set_ciphers(&ssl, my_ciphers);
285 ssl_set_session(&ssl, 1, 0, &ssn);
287 memset(&ssn, 0, sizeof(ssl_session));
289 ssl_set_ca_chain(&ssl, srvcert.next, NULL);
290 ssl_set_own_cert(&ssl, &srvcert, &rsa);
291 ssl_set_dh_param(&ssl, my_dhm_P, my_dhm_G);
294 * 5. Handshake
296 printf(" . Performing the SSL/TLS handshake...");
297 fflush(stdout);
299 while ((ret = ssl_handshake(&ssl)) != 0) {
300 if (ret != TROPICSSL_ERR_NET_TRY_AGAIN) {
301 printf(" failed\n ! ssl_handshake returned %d\n\n",
302 ret);
303 goto accept;
307 printf(" ok\n");
310 * 6. Read the HTTP Request
312 printf(" < Read from client:");
313 fflush(stdout);
315 do {
316 len = sizeof(buf) - 1;
317 memset(buf, 0, sizeof(buf));
318 ret = ssl_read(&ssl, buf, len);
320 if (ret == TROPICSSL_ERR_NET_TRY_AGAIN)
321 continue;
323 if (ret <= 0) {
324 switch (ret) {
325 case TROPICSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
326 printf(" connection was closed gracefully\n");
327 break;
329 case TROPICSSL_ERR_NET_CONN_RESET:
330 printf(" connection was reset by peer\n");
331 break;
333 default:
334 printf(" ssl_read returned %d\n", ret);
335 break;
338 break;
341 len = ret;
342 printf(" %d bytes read\n\n%s", len, (char *)buf);
344 while (0);
347 * 7. Write the 200 Response
349 printf(" > Write to client:");
350 fflush(stdout);
352 len = sprintf((char *)buf, HTTP_RESPONSE, ssl_get_cipher(&ssl));
354 while ((ret = ssl_write(&ssl, buf, len)) <= 0) {
355 if (ret == TROPICSSL_ERR_NET_CONN_RESET) {
356 printf(" failed\n ! peer closed the connection\n\n");
357 goto accept;
360 if (ret != TROPICSSL_ERR_NET_TRY_AGAIN) {
361 printf(" failed\n ! ssl_write returned %d\n\n", ret);
362 goto exit;
366 len = ret;
367 printf(" %d bytes written\n\n%s\n", len, (char *)buf);
369 ssl_close_notify(&ssl);
370 goto accept;
372 exit:
374 net_close(client_fd);
375 x509_free(&srvcert);
376 rsa_free(&rsa);
377 ssl_free(&ssl);
379 cur = s_list_1st;
380 while (cur != NULL) {
381 prv = cur;
382 cur = cur->next;
383 memset(prv, 0, sizeof(ssl_session));
384 free(prv);
387 memset(&ssl, 0, sizeof(ssl_context));
389 #ifdef WIN32
390 printf(" Press Enter to exit this program.\n");
391 fflush(stdout);
392 getchar();
393 #endif
395 return (ret);