/[hydra]/hydra/src/ssl.c
ViewVC logotype

Contents of /hydra/src/ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations)
Sun Sep 22 15:10:36 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: BOAS_WITH_RANGES_AND_CGI, hydra_0_0_2
Changes since 1.1: +50 -27 lines
File MIME type: text/plain
reentracy fixes in regeneration of TLS parameters.

1 /*
2 * Copyright (C) 2002 Nikos Mavroyanopoulos
3 *
4 * This file is part of BOA webserver.
5 *
6 * GNUTLS-EXTRA is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * GNUTLS-EXTRA is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "boa.h"
24
25 #ifdef ENABLE_SSL
26
27 #include <gnutls/gnutls.h>
28 #include <gcrypt.h>
29
30 extern int ssl_session_cache;
31 extern int ssl_session_timeout;
32
33 extern char* ssl_ciphers;
34 extern char* ssl_kx;
35 extern char* ssl_mac;
36 extern char* ssl_comp;
37 extern char* ssl_protocol;
38
39 static void wrap_db_init(void);
40 static int wrap_db_store(void *dbf, gnutls_datum key, gnutls_datum data);
41 static gnutls_datum wrap_db_fetch(void *dbf, gnutls_datum key);
42 static int wrap_db_delete(void *dbf, gnutls_datum key);
43
44 static int cur = 0; /* points to the credentials structure used */
45 static gnutls_certificate_credentials credentials[2];
46
47 static int need_dh_params = 0; /* whether we need to generate DHE
48 * parameters. Depend on the chosen ciphersuites.
49 */
50 static int need_rsa_params = 0;
51
52
53 /* we use primes up to 1024 in this server.
54 * otherwise we should add them here.
55 */
56 extern int ssl_dh_bits;
57
58 gnutls_dh_params _dh_params[2];
59 gnutls_rsa_params _rsa_params[2];
60
61 static int generate_dh_primes( gnutls_dh_params* dh_params)
62 {
63 gnutls_datum prime, generator;
64
65 if (gnutls_dh_params_init( dh_params) < 0) {
66 log_error_time();
67 fprintf(stderr, "Error in dh parameter initialization\n");
68 exit(1);
69 }
70
71 /* Generate Diffie Hellman parameters - for use with DHE
72 * kx algorithms. These should be discarded and regenerated
73 * once a day, once a week or once a month. Depends on the
74 * security requirements.
75 */
76
77 if (gnutls_dh_params_generate(&prime, &generator, ssl_dh_bits) <
78 0) {
79 log_error_time();
80 fprintf(stderr, "Error in prime generation\n");
81 exit(1);
82 }
83
84 if (gnutls_dh_params_set
85 (*dh_params, prime, generator, ssl_dh_bits) < 0) {
86 log_error_time();
87 fprintf(stderr, "Error in prime replacement\n");
88 exit(1);
89 }
90
91 log_error_time();
92 fprintf
93 (stderr,
94 "tls: Generated Diffie Hellman parameters [%d bits].\n",
95 ssl_dh_bits);
96
97 free(prime.data);
98 free(generator.data);
99
100 return 0;
101 }
102
103 static int generate_rsa_params( gnutls_rsa_params* rsa_params)
104 {
105 gnutls_datum m, e, d, p, q, u;
106
107 if (gnutls_rsa_params_init( rsa_params) < 0) {
108 log_error_time();
109 fprintf(stderr, "Error in rsa parameter initialization\n");
110 exit(1);
111 }
112
113 /* Generate RSA parameters - for use with RSA-export
114 * cipher suites. These should be discarded and regenerated
115 * once a day, once every 500 transactions etc. Depends on the
116 * security requirements.
117 */
118
119 if (gnutls_rsa_params_generate(&m, &e, &d, &p, &q, &u, 512) < 0) {
120 log_error_time();
121 fprintf(stderr, "Error in rsa parameter generation\n");
122 exit(1);
123 }
124
125 if (gnutls_rsa_params_set( *rsa_params, m, e, d, p, q, u, 512) < 0) {
126 log_error_time();
127 fprintf(stderr, "Error in rsa parameter setting\n");
128 exit(1);
129 }
130
131 free(m.data);
132 free(e.data);
133 free(d.data);
134 free(p.data);
135 free(q.data);
136 free(u.data);
137
138 log_error_time();
139 fprintf
140 (stderr, "tls: Generated temporary RSA parameters.\n");
141
142 return 0;
143 }
144
145 static int protocol_priority[16];
146 static int kx_priority[16];
147 static int cipher_priority[16];
148 static int mac_priority[16];
149 static int comp_priority[16];
150
151 /* Parses a string in the form:
152 * CIPHER1, CIPHER2, ...
153 * and tries to find the given algorithm.
154 * Returns true or false.
155 */
156 static int parse_cs_string( const char* string, const char* algo)
157 {
158 if (string == NULL || algo == NULL) return 0;
159
160 if (strstr( string, algo) != NULL)
161 return 1;
162
163 return 0;
164
165 }
166
167 gnutls_session initialize_ssl_session(void)
168 {
169 GNUTLS_STATE state;
170
171 gnutls_init(&state, GNUTLS_SERVER);
172
173 gnutls_cipher_set_priority(state, cipher_priority);
174 gnutls_compression_set_priority(state, comp_priority);
175 gnutls_kx_set_priority(state, kx_priority);
176 gnutls_protocol_set_priority(state, protocol_priority);
177 gnutls_mac_set_priority(state, mac_priority);
178
179 gnutls_cred_set(state, GNUTLS_CRD_CERTIFICATE, credentials[ cur]);
180
181 gnutls_certificate_server_set_request(state, GNUTLS_CERT_IGNORE);
182
183 if (ssl_session_cache != 0) {
184 gnutls_db_set_retrieve_function(state, wrap_db_fetch);
185 gnutls_db_set_remove_function(state, wrap_db_delete);
186 gnutls_db_set_store_function(state, wrap_db_store);
187 gnutls_db_set_ptr(state, NULL);
188 }
189 gnutls_db_set_cache_expiration( state, ssl_session_timeout);
190
191 gnutls_handshake_set_private_extensions( state, 1);
192
193 return state;
194 }
195
196 extern char *server_cert;
197 extern char *server_key;
198
199 /* Initialization of gnutls' global state
200 */
201 int initialize_ssl(void)
202 {
203 int i;
204
205 gnutls_global_init();
206 /* gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING, NULL, 0); */
207
208 if (gnutls_certificate_allocate_credentials( &credentials[0]) < 0) {
209 log_error_time();
210 fprintf(stderr, "certificate allocation error\n");
211 exit(1);
212 }
213
214 if (gnutls_certificate_set_x509_key_file
215 ( credentials[0], server_cert, server_key, GNUTLS_X509_FMT_PEM) < 0) {
216 log_error_time();
217 fprintf(stderr, "could not find %s or %s", server_cert,
218 server_key);
219 exit(1);
220 }
221
222 if (ssl_session_cache != 0)
223 wrap_db_init();
224
225 /* Add ciphers
226 */
227 i = 0;
228 if ( parse_cs_string( ssl_ciphers, "AES") != 0)
229 cipher_priority[i++] = GNUTLS_CIPHER_RIJNDAEL_128_CBC;
230 if ( parse_cs_string( ssl_ciphers, "ARCFOUR-128") != 0)
231 cipher_priority[i++] = GNUTLS_CIPHER_ARCFOUR_128;
232 if ( parse_cs_string( ssl_ciphers, "3DES") != 0)
233 cipher_priority[i++] = GNUTLS_CIPHER_3DES_CBC;
234 if ( parse_cs_string( ssl_ciphers, "ARCFOUR-40") != 0)
235 cipher_priority[i++] = GNUTLS_CIPHER_ARCFOUR_40;
236 cipher_priority[i] = 0;
237
238 /* Add key exchange methods
239 */
240 i = 0;
241 if ( parse_cs_string( ssl_kx, "RSA") != 0)
242 kx_priority[i++] = GNUTLS_KX_RSA;
243 if ( parse_cs_string( ssl_kx, "RSA-EXPORT") != 0) {
244 kx_priority[i++] = GNUTLS_KX_RSA_EXPORT;
245 need_rsa_params = 1;
246 }
247 if ( parse_cs_string( ssl_kx, "DHE-RSA") != 0) {
248 kx_priority[i++] = GNUTLS_KX_DHE_RSA;
249 need_dh_params = 1; /* generate DH parameters */
250 }
251 if ( parse_cs_string( ssl_kx, "DHE-DSS") != 0) {
252 kx_priority[i++] = GNUTLS_KX_DHE_DSS;
253 need_dh_params = 1;
254 }
255 kx_priority[i] = 0;
256
257 /* Add MAC Algorithms
258 */
259 i = 0;
260 if ( parse_cs_string( ssl_mac, "MD5") != 0)
261 mac_priority[i++] = GNUTLS_MAC_MD5;
262 if ( parse_cs_string( ssl_mac, "SHA") != 0)
263 mac_priority[i++] = GNUTLS_MAC_SHA;
264 mac_priority[i] = 0;
265
266 /* Add Compression algorithms
267 */
268 i = 0;
269 if ( parse_cs_string( ssl_comp, "NULL") != 0)
270 comp_priority[i++] = GNUTLS_COMP_NULL;
271 if ( parse_cs_string( ssl_comp, "ZLIB") != 0)
272 comp_priority[i++] = GNUTLS_COMP_ZLIB;
273 if ( parse_cs_string( ssl_comp, "LZO") != 0)
274 comp_priority[i++] = GNUTLS_COMP_LZO;
275 comp_priority[i] = 0;
276
277 /* Add protocols
278 */
279 i = 0;
280 if ( parse_cs_string( ssl_protocol, "TLS") != 0)
281 protocol_priority[i++] = GNUTLS_TLS1;
282 if ( parse_cs_string( ssl_protocol, "SSL") != 0)
283 protocol_priority[i++] = GNUTLS_SSL3;
284 protocol_priority[i] = 0;
285
286 /* Generate temporary parameters -- if needed.
287 */
288 if (need_rsa_params) {
289 generate_rsa_params( &_rsa_params[0]);
290 gnutls_certificate_set_rsa_params(credentials[0], _rsa_params[0]);
291 }
292
293 if (need_dh_params) {
294 generate_dh_primes( &_dh_params[0]);
295 gnutls_certificate_set_dh_params(credentials[0], _dh_params[0]);
296 }
297
298 return 0;
299 }
300
301 /* This function will regenerate the SSL parameters (RSA and DH) without
302 * any need for downtime.
303 */
304 void ssl_regenerate_params(void)
305 {
306 int _cur = (cur + 1) % 2;
307
308 /* The hint here, is that we keep a copy of 2 certificate credentials.
309 * When we come here, we free the unused copy and allocate new
310 * parameters to it. Then we make the current copy to be this copy.
311 *
312 * We don't free the previous copy because we don't know if anyone
313 * is using it. (this has to be fixed)
314 */
315
316 time(&current_time);
317
318 if ( !credentials[_cur]) {
319 if (gnutls_certificate_allocate_credentials( &credentials[ _cur]) < 0) {
320 log_error_time();
321 fprintf(stderr, "certificate allocation error\n");
322 exit(1);
323 }
324
325 if (gnutls_certificate_set_x509_key_file
326 ( credentials[_cur], server_cert, server_key, GNUTLS_X509_FMT_PEM) < 0) {
327 log_error_time();
328 fprintf(stderr, "could not find %s or %s", server_cert,
329 server_key);
330 exit(1);
331 }
332 }
333
334 if (need_rsa_params) {
335 gnutls_rsa_params_deinit( _rsa_params[ _cur]);
336 generate_rsa_params( &_rsa_params[ _cur]);
337 gnutls_certificate_set_rsa_params(credentials[_cur], _rsa_params[ _cur]);
338 }
339
340 if (need_dh_params) {
341 gnutls_dh_params_deinit( _dh_params[ _cur]);
342 generate_dh_primes( &_dh_params[ _cur]);
343 gnutls_certificate_set_dh_params(credentials[_cur], _dh_params[ _cur]);
344 }
345
346 cur = _cur;
347
348 return;
349 }
350
351
352 /* Session resuming:
353 */
354
355 #define SESSION_ID_SIZE 32
356 #define SESSION_DATA_SIZE 512
357
358 typedef struct {
359 char session_id[SESSION_ID_SIZE];
360 int session_id_size;
361
362 char session_data[SESSION_DATA_SIZE];
363 int session_data_size;
364 } CACHE;
365
366 static CACHE *cache_db;
367 int cache_db_ptr = 0;
368
369 static void wrap_db_init(void)
370 {
371
372 /* allocate cache_db */
373 cache_db = calloc(1, ssl_session_cache * sizeof(CACHE));
374 }
375
376 static int wrap_db_store(void *dbf, gnutls_datum key, gnutls_datum data)
377 {
378
379 if (cache_db == NULL)
380 return -1;
381
382 if (key.size > SESSION_ID_SIZE)
383 return -1;
384 if (data.size > SESSION_DATA_SIZE)
385 return -1;
386
387 memcpy(cache_db[cache_db_ptr].session_id, key.data, key.size);
388 cache_db[cache_db_ptr].session_id_size = key.size;
389
390 memcpy(cache_db[cache_db_ptr].session_data, data.data, data.size);
391 cache_db[cache_db_ptr].session_data_size = data.size;
392
393 cache_db_ptr++;
394 cache_db_ptr %= ssl_session_cache;
395
396 return 0;
397 }
398
399 static gnutls_datum wrap_db_fetch(void *dbf, gnutls_datum key)
400 {
401 gnutls_datum res = { NULL, 0 };
402 int i;
403
404 if (cache_db == NULL)
405 return res;
406
407 for (i = 0; i < ssl_session_cache; i++) {
408 if (key.size == cache_db[i].session_id_size &&
409 memcmp(key.data, cache_db[i].session_id, key.size) == 0) {
410
411
412 res.size = cache_db[i].session_data_size;
413
414 res.data = malloc(res.size);
415 if (res.data == NULL)
416 return res;
417
418 memcpy(res.data, cache_db[i].session_data, res.size);
419
420 return res;
421 }
422 }
423 return res;
424 }
425
426 static int wrap_db_delete(void *dbf, gnutls_datum key)
427 {
428 int i;
429
430 if (cache_db == NULL)
431 return -1;
432
433 for (i = 0; i < ssl_session_cache; i++) {
434 if (key.size == cache_db[i].session_id_size &&
435 memcmp(key.data, cache_db[i].session_id, key.size) == 0) {
436
437 cache_db[i].session_id_size = 0;
438 cache_db[i].session_data_size = 0;
439
440 return 0;
441 }
442 }
443
444 return -1;
445
446 }
447
448 void check_ssl_alert( request* req, int ret)
449 {
450 int last_alert;
451
452 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
453 {
454 last_alert = gnutls_alert_get(req->ssl_state);
455 log_error_doc(req);
456 fprintf(stderr, "Received alert \"%s\".\n", gnutls_alert_get_name(ret));
457 }
458 }
459
460 int finish_handshake(request * current)
461 {
462 int retval;
463
464 retval = gnutls_handshake(current->ssl_state);
465
466 if (retval == GNUTLS_E_AGAIN)
467 retval = -1;
468 else if (retval == GNUTLS_E_INTERRUPTED)
469 retval = 1;
470 else if (retval < 0) {
471 if (gnutls_error_is_fatal(retval) != 0) {
472 log_error_doc(current);
473 fprintf(stderr, "TLS handshake error \"%s\"\n", gnutls_strerror(retval));
474 check_ssl_alert( current, retval);
475
476 /* we ignore the level of the alert, since we always
477 * send fatal alerts.
478 */
479 current->alert_to_send = gnutls_error_to_alert( retval, NULL);
480 if (current->alert_to_send >= 0) {
481 current->status = SEND_ALERT;
482 }
483 retval = 1;
484 } else {
485 check_ssl_alert( current, retval);
486 retval = 1;
487 }
488 } else if (retval == 0) {
489 retval = 1;
490 current->status = READ_HEADER;
491 }
492
493 return retval;
494 }
495
496 int send_alert(request * current)
497 {
498 int retval;
499
500 retval = gnutls_alert_send( current->ssl_state,
501 GNUTLS_AL_FATAL, current->alert_to_send);
502
503 if (retval == GNUTLS_E_AGAIN)
504 retval = -1;
505 else if (retval == GNUTLS_E_INTERRUPTED)
506 retval = 1;
507 else if (retval <= 0) {
508 retval = 0;
509 current->status = DEAD;
510 }
511
512 return retval;
513 }
514
515 #else /* a stub for initialize_ssl */
516
517 int initialize_ssl(void)
518 {
519 log_error_time();
520 fprintf(stderr, "SSL is not available in this build\n");
521 exit(1);
522 }
523
524 #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26