bignum: make mpi_init() and mpi_free() accept a single argument
[tropicssl.git] / programs / ssl / ssl_server.c
blobdd997fbfc4893950ce2a5165816dcd0e3b156715
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 = -1;
177 int client_fd = -1;
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(&ssl, 0, sizeof(ssl_context));
193 memset(&ssn, 0, sizeof(ssl_session));
194 memset(&srvcert, 0, sizeof(x509_cert));
195 memset(&rsa, 0, sizeof(rsa_context));
198 * This demonstration program uses embedded test certificates.
199 * Instead, you may want to use x509parse_crtfile() to read the
200 * server and CA certificates, as well as x509parse_keyfile().
202 ret = x509parse_crt(&srvcert, (const unsigned char *)test_srv_crt,
203 strlen(test_srv_crt));
204 if (ret != 0) {
205 printf(" failed\n ! x509parse_crt returned %d\n\n", ret);
206 goto exit;
209 ret = x509parse_crt(&srvcert, (const unsigned char *)test_ca_crt,
210 strlen(test_ca_crt));
211 if (ret != 0) {
212 printf(" failed\n ! x509parse_crt returned %d\n\n", ret);
213 goto exit;
216 ret = x509parse_key(&rsa, (const unsigned char *)test_srv_key,
217 strlen(test_srv_key), NULL, 0);
218 if (ret != 0) {
219 printf(" failed\n ! x509parse_key returned %d\n\n", ret);
220 goto exit;
223 printf(" ok\n");
226 * 2. Setup the listening TCP socket
228 printf(" . Bind on https://localhost:4433/ ...");
229 fflush(stdout);
231 if ((ret = net_bind(&listen_fd, NULL, 4433)) != 0) {
232 printf(" failed\n ! net_bind returned %d\n\n", ret);
233 goto exit;
236 printf(" ok\n");
239 * 3. Wait until a client connects
241 #ifdef WIN32
242 ShellExecute(NULL, "open", "https://localhost:4433/",
243 NULL, NULL, SW_SHOWNORMAL);
244 #endif
246 client_fd = -1;
247 memset(&ssl, 0, sizeof(ssl));
249 accept:
251 net_close(client_fd);
252 ssl_free(&ssl);
254 printf(" . Waiting for a remote connection ...");
255 fflush(stdout);
257 if ((ret = net_accept(listen_fd, &client_fd, NULL)) != 0) {
258 printf(" failed\n ! net_accept returned %d\n\n", ret);
259 goto exit;
262 printf(" ok\n");
265 * 4. Setup stuff
267 printf(" . Setting up the RNG and SSL data....");
268 fflush(stdout);
270 havege_init(&hs);
272 if ((ret = ssl_init(&ssl)) != 0) {
273 printf(" failed\n ! ssl_init returned %d\n\n", ret);
274 goto accept;
277 printf(" ok\n");
279 ssl_set_endpoint(&ssl, SSL_IS_SERVER);
280 ssl_set_authmode(&ssl, SSL_VERIFY_NONE);
282 ssl_set_rng(&ssl, havege_rand, &hs);
283 ssl_set_dbg(&ssl, my_debug, stdout);
284 ssl_set_bio(&ssl, net_recv, &client_fd, net_send, &client_fd);
285 ssl_set_scb(&ssl, my_get_session, my_set_session);
287 ssl_set_ciphers(&ssl, my_ciphers);
288 ssl_set_session(&ssl, 1, 0, &ssn);
290 ssl_set_ca_chain(&ssl, srvcert.next, NULL);
291 ssl_set_own_cert(&ssl, &srvcert, &rsa);
292 ssl_set_dh_param(&ssl, my_dhm_P, my_dhm_G);
295 * 5. Handshake
297 printf(" . Performing the SSL/TLS handshake...");
298 fflush(stdout);
300 while ((ret = ssl_handshake(&ssl)) != 0) {
301 if (ret != TROPICSSL_ERR_NET_TRY_AGAIN) {
302 printf(" failed\n ! ssl_handshake returned %d\n\n",
303 ret);
304 goto accept;
308 printf(" ok\n");
311 * 6. Read the HTTP Request
313 printf(" < Read from client:");
314 fflush(stdout);
316 do {
317 len = sizeof(buf) - 1;
318 memset(buf, 0, sizeof(buf));
319 ret = ssl_read(&ssl, buf, len);
321 if (ret == TROPICSSL_ERR_NET_TRY_AGAIN)
322 continue;
324 if (ret <= 0) {
325 switch (ret) {
326 case TROPICSSL_ERR_SSL_PEER_CLOSE_NOTIFY:
327 printf(" connection was closed gracefully\n");
328 break;
330 case TROPICSSL_ERR_NET_CONN_RESET:
331 printf(" connection was reset by peer\n");
332 break;
334 default:
335 printf(" ssl_read returned %d\n", ret);
336 break;
339 break;
342 len = ret;
343 printf(" %d bytes read\n\n%s", len, (char *)buf);
345 while (0);
348 * 7. Write the 200 Response
350 printf(" > Write to client:");
351 fflush(stdout);
353 len = sprintf((char *)buf, HTTP_RESPONSE, ssl_get_cipher(&ssl));
355 while ((ret = ssl_write(&ssl, buf, len)) <= 0) {
356 if (ret == TROPICSSL_ERR_NET_CONN_RESET) {
357 printf(" failed\n ! peer closed the connection\n\n");
358 goto accept;
361 if (ret != TROPICSSL_ERR_NET_TRY_AGAIN) {
362 printf(" failed\n ! ssl_write returned %d\n\n", ret);
363 goto exit;
367 len = ret;
368 printf(" %d bytes written\n\n%s\n", len, (char *)buf);
370 ssl_close_notify(&ssl);
371 goto accept;
373 exit:
375 net_close(client_fd);
376 x509_free(&srvcert);
377 rsa_free(&rsa);
378 ssl_free(&ssl);
380 cur = s_list_1st;
381 while (cur != NULL) {
382 prv = cur;
383 cur = cur->next;
384 memset(prv, 0, sizeof(ssl_session));
385 free(prv);
388 memset(&ssl, 0, sizeof(ssl_context));
390 #ifdef WIN32
391 printf(" Press Enter to exit this program.\n");
392 fflush(stdout);
393 getchar();
394 #endif
396 return (ret);