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

Annotation of /hydra/src/ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Sat Sep 21 13:53:23 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Branch point for: boas
File MIME type: text/plain
Initial revision

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     static gnutls_certificate_credentials credentials;
45    
46     static int need_dh_params = 0; /* whether we need to generate DHE
47     * parameters. Depend on the chosen ciphersuites.
48     */
49     static int need_rsa_params = 0;
50    
51    
52     /* we use primes up to 1024 in this server.
53     * otherwise we should add them here.
54     */
55     extern int ssl_dh_bits;
56    
57     gnutls_dh_params dh_params;
58     gnutls_rsa_params rsa_params;
59    
60     static int generate_dh_primes()
61     {
62     gnutls_datum prime, generator;
63    
64     if (gnutls_dh_params_init( &dh_params) < 0) {
65     log_error_time();
66     fprintf(stderr, "Error in dh parameter initialization\n");
67     exit(1);
68     }
69    
70     /* Generate Diffie Hellman parameters - for use with DHE
71     * kx algorithms. These should be discarded and regenerated
72     * once a day, once a week or once a month. Depends on the
73     * security requirements.
74     */
75    
76     if (gnutls_dh_params_generate(&prime, &generator, ssl_dh_bits) <
77     0) {
78     log_error_time();
79     fprintf(stderr, "Error in prime generation\n");
80     exit(1);
81     }
82    
83     if (gnutls_dh_params_set
84     (dh_params, prime, generator, ssl_dh_bits) < 0) {
85     log_error_time();
86     fprintf(stderr, "Error in prime replacement\n");
87     exit(1);
88     }
89    
90     log_error_time();
91     fprintf
92     (stderr,
93     "tls: Generated Diffie Hellman parameters [%d bits].\n",
94     ssl_dh_bits);
95    
96     free(prime.data);
97     free(generator.data);
98    
99     return 0;
100     }
101    
102     static int generate_rsa_params()
103     {
104     gnutls_datum m, e, d, p, q, u;
105    
106     if (gnutls_rsa_params_init(&rsa_params) < 0) {
107     log_error_time();
108     fprintf(stderr, "Error in rsa parameter initialization\n");
109     exit(1);
110     }
111    
112     /* Generate RSA parameters - for use with RSA-export
113     * cipher suites. These should be discarded and regenerated
114     * once a day, once every 500 transactions etc. Depends on the
115     * security requirements.
116     */
117    
118     if (gnutls_rsa_params_generate(&m, &e, &d, &p, &q, &u, 512) < 0) {
119     log_error_time();
120     fprintf(stderr, "Error in rsa parameter generation\n");
121     exit(1);
122     }
123    
124     if (gnutls_rsa_params_set(rsa_params, m, e, d, p, q, u, 512) < 0) {
125     log_error_time();
126     fprintf(stderr, "Error in rsa parameter setting\n");
127     exit(1);
128     }
129    
130     free(m.data);
131     free(e.data);
132     free(d.data);
133     free(p.data);
134     free(q.data);
135     free(u.data);
136    
137     log_error_time();
138     fprintf
139     (stderr, "tls: Generated temporary RSA parameters.\n");
140    
141     return 0;
142     }
143    
144     static int protocol_priority[16];
145     static int kx_priority[16];
146     static int cipher_priority[16];
147     static int mac_priority[16];
148     static int comp_priority[16];
149    
150     /* Parses a string in the form:
151     * CIPHER1, CIPHER2, ...
152     * and tries to find the given algorithm.
153     * Returns true or false.
154     */
155     static int parse_cs_string( const char* string, const char* algo)
156     {
157     if (string == NULL || algo == NULL) return 0;
158    
159     if (strstr( string, algo) != NULL)
160     return 1;
161    
162     return 0;
163    
164     }
165    
166     gnutls_session initialize_ssl_session(void)
167     {
168     GNUTLS_STATE state;
169    
170     gnutls_init(&state, GNUTLS_SERVER);
171    
172     gnutls_cipher_set_priority(state, cipher_priority);
173     gnutls_compression_set_priority(state, comp_priority);
174     gnutls_kx_set_priority(state, kx_priority);
175     gnutls_protocol_set_priority(state, protocol_priority);
176     gnutls_mac_set_priority(state, mac_priority);
177    
178     gnutls_cred_set(state, GNUTLS_CRD_CERTIFICATE, credentials);
179    
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) {
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, 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();
290     gnutls_certificate_set_rsa_params(credentials, rsa_params);
291     }
292    
293     if (need_dh_params) {
294     generate_dh_primes();
295     gnutls_certificate_set_dh_params(credentials, dh_params);
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     /* This is tricky, and should not be used in any kind of
307     * servers (ie threaded ones). This works just because no
308     * tls session works in parallel with this function.
309     */
310    
311     time(&current_time);
312    
313     if (need_rsa_params) {
314     gnutls_rsa_params_deinit( rsa_params);
315     generate_rsa_params();
316     gnutls_certificate_set_rsa_params(credentials, rsa_params);
317     }
318    
319     if (need_dh_params) {
320     gnutls_dh_params_deinit( dh_params);
321     generate_dh_primes();
322     gnutls_certificate_set_dh_params(credentials, dh_params);
323     }
324    
325     return;
326     }
327    
328    
329     /* Session resuming:
330     */
331    
332     #define SESSION_ID_SIZE 32
333     #define SESSION_DATA_SIZE 512
334    
335     typedef struct {
336     char session_id[SESSION_ID_SIZE];
337     int session_id_size;
338    
339     char session_data[SESSION_DATA_SIZE];
340     int session_data_size;
341     } CACHE;
342    
343     static CACHE *cache_db;
344     int cache_db_ptr = 0;
345    
346     static void wrap_db_init(void)
347     {
348    
349     /* allocate cache_db */
350     cache_db = calloc(1, ssl_session_cache * sizeof(CACHE));
351     }
352    
353     static int wrap_db_store(void *dbf, gnutls_datum key, gnutls_datum data)
354     {
355    
356     if (cache_db == NULL)
357     return -1;
358    
359     if (key.size > SESSION_ID_SIZE)
360     return -1;
361     if (data.size > SESSION_DATA_SIZE)
362     return -1;
363    
364     memcpy(cache_db[cache_db_ptr].session_id, key.data, key.size);
365     cache_db[cache_db_ptr].session_id_size = key.size;
366    
367     memcpy(cache_db[cache_db_ptr].session_data, data.data, data.size);
368     cache_db[cache_db_ptr].session_data_size = data.size;
369    
370     cache_db_ptr++;
371     cache_db_ptr %= ssl_session_cache;
372    
373     return 0;
374     }
375    
376     static gnutls_datum wrap_db_fetch(void *dbf, gnutls_datum key)
377     {
378     gnutls_datum res = { NULL, 0 };
379     int i;
380    
381     if (cache_db == NULL)
382     return res;
383    
384     for (i = 0; i < ssl_session_cache; i++) {
385     if (key.size == cache_db[i].session_id_size &&
386     memcmp(key.data, cache_db[i].session_id, key.size) == 0) {
387    
388    
389     res.size = cache_db[i].session_data_size;
390    
391     res.data = malloc(res.size);
392     if (res.data == NULL)
393     return res;
394    
395     memcpy(res.data, cache_db[i].session_data, res.size);
396    
397     return res;
398     }
399     }
400     return res;
401     }
402    
403     static int wrap_db_delete(void *dbf, gnutls_datum key)
404     {
405     int i;
406    
407     if (cache_db == NULL)
408     return -1;
409    
410     for (i = 0; i < ssl_session_cache; i++) {
411     if (key.size == cache_db[i].session_id_size &&
412     memcmp(key.data, cache_db[i].session_id, key.size) == 0) {
413    
414     cache_db[i].session_id_size = 0;
415     cache_db[i].session_data_size = 0;
416    
417     return 0;
418     }
419     }
420    
421     return -1;
422    
423     }
424    
425     void check_ssl_alert( request* req, int ret)
426     {
427     int last_alert;
428    
429     if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
430     {
431     last_alert = gnutls_alert_get(req->ssl_state);
432     log_error_doc(req);
433     fprintf(stderr, "Received alert \"%s\".\n", gnutls_alert_get_name(ret));
434     }
435     }
436    
437     int finish_handshake(request * current)
438     {
439     int retval;
440    
441     retval = gnutls_handshake(current->ssl_state);
442    
443     if (retval == GNUTLS_E_AGAIN)
444     retval = -1;
445     else if (retval == GNUTLS_E_INTERRUPTED)
446     retval = 1;
447     else if (retval < 0) {
448     if (gnutls_error_is_fatal(retval) != 0) {
449     log_error_doc(current);
450     fprintf(stderr, "TLS handshake error \"%s\"\n", gnutls_strerror(retval));
451     check_ssl_alert( current, retval);
452    
453     /* we ignore the level of the alert, since we always
454     * send fatal alerts.
455     */
456     current->alert_to_send = gnutls_error_to_alert( retval, NULL);
457     if (current->alert_to_send >= 0) {
458     current->status = SEND_ALERT;
459     }
460     retval = 1;
461     } else {
462     check_ssl_alert( current, retval);
463     retval = 1;
464     }
465     } else if (retval == 0) {
466     retval = 1;
467     current->status = READ_HEADER;
468     }
469    
470     return retval;
471     }
472    
473     int send_alert(request * current)
474     {
475     int retval;
476    
477     retval = gnutls_alert_send( current->ssl_state,
478     GNUTLS_AL_FATAL, current->alert_to_send);
479    
480     if (retval == GNUTLS_E_AGAIN)
481     retval = -1;
482     else if (retval == GNUTLS_E_INTERRUPTED)
483     retval = 1;
484     else if (retval <= 0) {
485     retval = 0;
486     current->status = DEAD;
487     }
488    
489     return retval;
490     }
491    
492     #else /* a stub for initialize_ssl */
493    
494     int initialize_ssl(void)
495     {
496     log_error_time();
497     fprintf(stderr, "SSL is not available in this build\n");
498     exit(1);
499     }
500    
501     #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26