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

Annotation of /hydra/src/ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations)
Fri Sep 27 07:09:15 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.3: +2 -1 lines
File MIME type: text/plain
*** empty log message ***

1 nmav 1.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 nmav 1.3 #ifdef ENABLE_SMP
31     pthread_mutex_t ssl_session_cache_lock = PTHREAD_MUTEX_INITIALIZER;
32     #endif
33    
34 nmav 1.1 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 nmav 1.2 static int cur = 0; /* points to the credentials structure used */
49     static gnutls_certificate_credentials credentials[2];
50 nmav 1.1
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 nmav 1.2 gnutls_dh_params _dh_params[2];
63     gnutls_rsa_params _rsa_params[2];
64 nmav 1.1
65 nmav 1.2 static int generate_dh_primes( gnutls_dh_params* dh_params)
66 nmav 1.1 {
67     gnutls_datum prime, generator;
68    
69 nmav 1.2 if (gnutls_dh_params_init( dh_params) < 0) {
70 nmav 1.1 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 nmav 1.2 (*dh_params, prime, generator, ssl_dh_bits) < 0) {
90 nmav 1.1 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 nmav 1.2 static int generate_rsa_params( gnutls_rsa_params* rsa_params)
108 nmav 1.1 {
109     gnutls_datum m, e, d, p, q, u;
110    
111 nmav 1.2 if (gnutls_rsa_params_init( rsa_params) < 0) {
112 nmav 1.1 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 nmav 1.2 if (gnutls_rsa_params_set( *rsa_params, m, e, d, p, q, u, 512) < 0) {
130 nmav 1.1 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 nmav 1.2 gnutls_cred_set(state, GNUTLS_CRD_CERTIFICATE, credentials[ cur]);
184 nmav 1.1
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 nmav 1.2 if (gnutls_certificate_allocate_credentials( &credentials[0]) < 0) {
213 nmav 1.1 log_error_time();
214     fprintf(stderr, "certificate allocation error\n");
215     exit(1);
216     }
217    
218     if (gnutls_certificate_set_x509_key_file
219 nmav 1.2 ( credentials[0], server_cert, server_key, GNUTLS_X509_FMT_PEM) < 0) {
220 nmav 1.1 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 nmav 1.2 generate_rsa_params( &_rsa_params[0]);
294     gnutls_certificate_set_rsa_params(credentials[0], _rsa_params[0]);
295 nmav 1.1 }
296    
297     if (need_dh_params) {
298 nmav 1.2 generate_dh_primes( &_dh_params[0]);
299     gnutls_certificate_set_dh_params(credentials[0], _dh_params[0]);
300 nmav 1.1 }
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 nmav 1.2 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 nmav 1.1
320     time(&current_time);
321    
322 nmav 1.2 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 nmav 1.1 if (need_rsa_params) {
339 nmav 1.2 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 nmav 1.1 }
343    
344     if (need_dh_params) {
345 nmav 1.2 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 nmav 1.1 }
349 nmav 1.2
350     cur = _cur;
351 nmav 1.1
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 nmav 1.3 static int cache_db_ptr;
372 nmav 1.1
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 nmav 1.3 #ifdef ENABLE_SMP
392     pthread_mutex_lock( &ssl_session_cache_lock);
393     #endif
394    
395 nmav 1.1 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 nmav 1.4 cache_db_ptr++;
402     cache_db_ptr %= ssl_session_cache;
403 nmav 1.3
404     #ifdef ENABLE_SMP
405     pthread_mutex_unlock( &ssl_session_cache_lock);
406     #endif
407 nmav 1.1
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 nmav 1.3 #ifdef ENABLE_SMP
420     pthread_mutex_lock( &ssl_session_cache_lock);
421     #endif
422    
423 nmav 1.1 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 nmav 1.3 if (res.data == NULL) {
431     #ifdef ENABLE_SMP
432     pthread_mutex_unlock( &ssl_session_cache_lock);
433     #endif
434 nmav 1.1 return res;
435 nmav 1.3 }
436 nmav 1.1
437     memcpy(res.data, cache_db[i].session_data, res.size);
438    
439 nmav 1.3 #ifdef ENABLE_SMP
440     pthread_mutex_unlock( &ssl_session_cache_lock);
441     #endif
442 nmav 1.1 return res;
443     }
444     }
445 nmav 1.3
446     #ifdef ENABLE_SMP
447     pthread_mutex_unlock( &ssl_session_cache_lock);
448     #endif
449    
450 nmav 1.1 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 nmav 1.3 #ifdef ENABLE_SMP
461     pthread_mutex_lock( &ssl_session_cache_lock);
462     #endif
463    
464 nmav 1.1 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 nmav 1.3 #ifdef ENABLE_SMP
472     pthread_mutex_unlock( &ssl_session_cache_lock);
473     #endif
474    
475 nmav 1.1 return 0;
476     }
477     }
478 nmav 1.3
479     #ifdef ENABLE_SMP
480     pthread_mutex_unlock( &ssl_session_cache_lock);
481     #endif
482 nmav 1.1 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