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

Contents of /hydra/src/ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (show annotations)
Sat Sep 28 16:32:37 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_3, hydra_0_0_6, hydra_0_0_4, hydra_0_0_5
Changes since 1.4: +3 -3 lines
File MIME type: text/plain
In sighup and sigterm, the HIC thread is terminated as well.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26