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

Annotation of /hydra/src/ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (hide 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 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     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 nmav 1.2 static int cur = 0; /* points to the credentials structure used */
45     static gnutls_certificate_credentials credentials[2];
46 nmav 1.1
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 nmav 1.2 gnutls_dh_params _dh_params[2];
59     gnutls_rsa_params _rsa_params[2];
60 nmav 1.1
61 nmav 1.2 static int generate_dh_primes( gnutls_dh_params* dh_params)
62 nmav 1.1 {
63     gnutls_datum prime, generator;
64    
65 nmav 1.2 if (gnutls_dh_params_init( dh_params) < 0) {
66 nmav 1.1 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 nmav 1.2 (*dh_params, prime, generator, ssl_dh_bits) < 0) {
86 nmav 1.1 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 nmav 1.2 static int generate_rsa_params( gnutls_rsa_params* rsa_params)
104 nmav 1.1 {
105     gnutls_datum m, e, d, p, q, u;
106    
107 nmav 1.2 if (gnutls_rsa_params_init( rsa_params) < 0) {
108 nmav 1.1 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 nmav 1.2 if (gnutls_rsa_params_set( *rsa_params, m, e, d, p, q, u, 512) < 0) {
126 nmav 1.1 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 nmav 1.2 gnutls_cred_set(state, GNUTLS_CRD_CERTIFICATE, credentials[ cur]);
180 nmav 1.1
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 nmav 1.2 if (gnutls_certificate_allocate_credentials( &credentials[0]) < 0) {
209 nmav 1.1 log_error_time();
210     fprintf(stderr, "certificate allocation error\n");
211     exit(1);
212     }
213    
214     if (gnutls_certificate_set_x509_key_file
215 nmav 1.2 ( credentials[0], server_cert, server_key, GNUTLS_X509_FMT_PEM) < 0) {
216 nmav 1.1 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 nmav 1.2 generate_rsa_params( &_rsa_params[0]);
290     gnutls_certificate_set_rsa_params(credentials[0], _rsa_params[0]);
291 nmav 1.1 }
292    
293     if (need_dh_params) {
294 nmav 1.2 generate_dh_primes( &_dh_params[0]);
295     gnutls_certificate_set_dh_params(credentials[0], _dh_params[0]);
296 nmav 1.1 }
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 nmav 1.2 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 nmav 1.1
316     time(&current_time);
317    
318 nmav 1.2 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 nmav 1.1 if (need_rsa_params) {
335 nmav 1.2 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 nmav 1.1 }
339    
340     if (need_dh_params) {
341 nmav 1.2 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 nmav 1.1 }
345 nmav 1.2
346     cur = _cur;
347 nmav 1.1
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