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

Contents of /hydra/src/ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show 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 /*
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