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

Contents of /hydra/src/ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (show annotations)
Sat Oct 5 09:39:36 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.7: +19 -10 lines
File MIME type: text/plain
More SSL additions.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26