added openpgp authentication test, and unknown cipher suites test
[gnutls.git] / src / serv.c
blobbe2f1fece484034ef8e89422a3979fb6b882ef61
1 /*
2 * Copyright (C) 2000,2001,2002 Nikos Mavroyanopoulos
4 * This file is part of GNUTLS.
6 * GNUTLS 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.
11 * GNUTLS 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.
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
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include "../lib/gnutls.h"
31 #include <common.h>
32 #include <signal.h>
33 #include <serv-gaa.h>
35 #define KEYFILE1 "x509/key.pem"
36 #define CERTFILE1 "x509/cert.pem"
38 #define KEYFILE2 "x509/key-dsa.pem"
39 #define CERTFILE2 "x509/cert-dsa.pem"
41 #define PGP_KEYFILE "openpgp/sec.asc"
42 #define PGP_CERTFILE "openpgp/pub.asc"
44 #define CAFILE "x509/ca.pem"
45 #define CRLFILE NULL
47 #define SRP_PASSWD "srp/tpasswd"
48 #define SRP_PASSWD_CONF "srp/tpasswd.conf"
50 /* konqueror cannot handle sending the page in multiple
51 * pieces.
53 /* global stuff */
54 static char http_buffer[16 * 1024];
55 static int generate = 0;
56 static int http = 0;
57 static int port = 0;
59 /* end of globals */
61 /* This is a sample TCP echo server.
62 * This will behave as an http server if any argument in the
63 * command line is present
67 #define SA struct sockaddr
68 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
69 #define MAX_BUF 1024
71 #define HTTP_BEGIN "HTTP/1.0 200 OK\n" \
72 "Content-Type: text/html\n" \
73 "\n" \
74 "<HTML><BODY>\n" \
75 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
76 "GNUTLS</a></H1>\n\n"
78 #define HTTP_END "</BODY></HTML>\n\n"
80 #define RENEGOTIATE
82 /* These are global */
83 GNUTLS_SRP_SERVER_CREDENTIALS srp_cred;
84 GNUTLS_ANON_SERVER_CREDENTIALS dh_cred;
85 GNUTLS_CERTIFICATE_SERVER_CREDENTIALS cert_cred;
88 #define DEFAULT_PRIME_BITS 1024
90 /* we use primes up to 1024 in this server.
91 * otherwise we should add them here.
93 static int prime_nums[] = { 768, 1024, 0 };
95 GNUTLS_DH_PARAMS dh_params;
97 static int generate_dh_primes(void)
99 gnutls_datum prime, generator;
100 int i = 0;
102 if (gnutls_dh_params_init( &dh_params) < 0) {
103 fprintf(stderr, "Error in dh parameter initialization\n");
104 exit(1);
107 do {
108 /* Generate Diffie Hellman parameters - for use with DHE
109 * kx algorithms. These should be discarded and regenerated
110 * once a day, once a week or once a month. Depends on the
111 * security requirements.
113 printf
114 ("Generating Diffie Hellman parameters [%d]. Please wait...",
115 prime_nums[i]);
116 fflush(stdout);
118 if (gnutls_dh_params_generate
119 (&prime, &generator, prime_nums[i]) < 0) {
120 fprintf(stderr, "Error in prime generation\n");
121 exit(1);
124 if (gnutls_dh_params_set
125 (dh_params, prime, generator, prime_nums[i]) < 0) {
126 fprintf(stderr, "Error in prime replacement\n");
127 exit(1);
129 free(prime.data);
130 free(generator.data);
132 } while (prime_nums[++i] != 0);
134 return 0;
137 int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
138 int kx_priority[16] =
139 { GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP,
140 GNUTLS_KX_ANON_DH, 0 };
141 int cipher_priority[16] =
142 { GNUTLS_CIPHER_RIJNDAEL_128_CBC, GNUTLS_CIPHER_3DES_CBC,
143 GNUTLS_CIPHER_ARCFOUR, 0 };
144 int comp_priority[16] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
145 int mac_priority[16] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
146 int cert_type_priority[16] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
148 GNUTLS_STATE initialize_state(void)
150 GNUTLS_STATE state;
151 int ret;
153 gnutls_init(&state, GNUTLS_SERVER);
154 if ((ret = gnutls_db_set_name(state, "gnutls-rsm.db")) < 0)
155 fprintf(stderr,
156 "*** DB error (%d). Resuming will not be possible.\n\n",
157 ret);
159 /* null cipher is here only for debuging
160 * purposes.
162 gnutls_cipher_set_priority(state, cipher_priority);
163 gnutls_compression_set_priority(state, comp_priority);
164 gnutls_kx_set_priority(state, kx_priority);
165 gnutls_protocol_set_priority(state, protocol_priority);
166 gnutls_mac_set_priority(state, mac_priority);
167 gnutls_cert_type_set_priority(state, cert_type_priority);
169 gnutls_dh_set_prime_bits(state, DEFAULT_PRIME_BITS);
171 gnutls_cred_set(state, GNUTLS_CRD_ANON, dh_cred);
172 gnutls_cred_set(state, GNUTLS_CRD_SRP, srp_cred);
173 gnutls_cred_set(state, GNUTLS_CRD_CERTIFICATE, cert_cred);
175 gnutls_mac_set_priority(state, mac_priority);
177 gnutls_certificate_server_set_request(state, GNUTLS_CERT_REQUEST);
179 return state;
182 /* Creates html with the current state information.
184 #define tmp2 &http_buffer[strlen(http_buffer)]
185 void peer_print_info(GNUTLS_STATE state)
187 const char *tmp;
188 unsigned char sesid[32];
189 int sesid_size, i;
191 /* print session_id */
192 gnutls_session_get_id(state, sesid, &sesid_size);
193 sprintf(tmp2, "\n<p>Session ID: <i>");
194 for (i = 0; i < sesid_size; i++)
195 sprintf(tmp2, "%.2X", sesid[i]);
196 sprintf(tmp2, "</i></p>\n");
198 /* Here unlike print_info() we use the kx algorithm to distinguish
199 * the functions to call.
202 /* print srp specific data */
203 if (gnutls_kx_get(state) == GNUTLS_KX_SRP) {
204 sprintf(tmp2, "<p>Connected as user '%s'.</p>\n",
205 gnutls_srp_server_get_username(state));
208 if (gnutls_kx_get(state) == GNUTLS_KX_ANON_DH) {
209 sprintf(tmp2,
210 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
211 gnutls_dh_get_prime_bits(state));
214 /* print state information */
215 strcat(http_buffer, "<P>\n");
217 tmp = gnutls_protocol_get_name(gnutls_protocol_get_version(state));
218 sprintf(tmp2, "Protocol version: <b>%s</b><br>\n", tmp);
220 if (gnutls_auth_get_type(state) == GNUTLS_CRD_CERTIFICATE) {
221 tmp =
222 gnutls_cert_type_get_name(gnutls_cert_type_get(state));
223 sprintf(tmp2, "Certificate Type: <b>%s</b><br>\n", tmp);
226 tmp = gnutls_kx_get_name(gnutls_kx_get(state));
227 sprintf(tmp2, "Key Exchange: <b>%s</b><br>\n", tmp);
229 if (gnutls_kx_get(state) == GNUTLS_KX_DHE_RSA
230 || gnutls_kx_get(state) == GNUTLS_KX_DHE_DSS) {
231 sprintf(tmp2,
232 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
233 gnutls_dh_get_prime_bits(state));
236 tmp = gnutls_compression_get_name(gnutls_compression_get(state));
237 sprintf(tmp2, "Compression: <b>%s</b><br>\n", tmp);
239 tmp = gnutls_cipher_get_name(gnutls_cipher_get(state));
240 sprintf(tmp2, "Cipher: <b>%s</b><br>\n", tmp);
242 tmp = gnutls_mac_get_name(gnutls_mac_get(state));
243 sprintf(tmp2, "MAC: <b>%s</b><br>\n", tmp);
245 strcat(http_buffer, "</P>\n");
247 return;
250 /* actually something like readline.
251 * if rnl!=1 then reads an http request in the form REQ\n\n
253 int read_request(GNUTLS_STATE state, char *data, int data_size, int rnl)
255 int n, rc, nl = 0;
256 char c, *ptr, p1 = 0, p2 = 0;
258 ptr = data;
259 for (n = 1; n < data_size; n++) {
260 do {
261 rc = gnutls_record_recv(state, &c, 1);
262 } while (rc == GNUTLS_E_INTERRUPTED
263 || rc == GNUTLS_E_AGAIN);
265 if (rc == 1) {
266 *ptr++ = c;
267 if (c == '\n' && rnl == 1)
268 break;
270 if (c == '\n' && p1 == '\r' && p2 == '\n') {
271 nl++;
272 if (nl == 1)
273 break;
275 p2 = p1;
276 p1 = c;
278 } else if (rc == 0) {
279 if (n == 1)
280 return 0;
281 else
282 break;
283 } else {
284 return rc;
288 *ptr = 0;
289 return n;
292 void check_alert(GNUTLS_STATE state, int ret)
294 int last_alert;
296 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
297 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
298 last_alert = gnutls_alert_get(state);
299 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
300 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
301 printf
302 ("* Received NO_RENEGOTIATION alert. Client Does not support renegotiation.\n");
303 else
304 printf("* Received alert '%d'.\n", ret);
308 static void gaa_parser(int argc, char **argv);
310 int main(int argc, char **argv)
312 int err, listen_sd, i;
313 int sd, ret;
314 struct sockaddr_in sa_serv;
315 struct sockaddr_in sa_cli;
316 int client_len;
317 char topbuf[512];
318 GNUTLS_STATE state;
319 char buffer[MAX_BUF + 1];
320 int optval = 1;
321 char name[256];
323 signal(SIGPIPE, SIG_IGN);
325 gaa_parser(argc, argv);
327 if (http == 1) {
328 strcpy(name, "HTTP Server");
329 } else {
330 strcpy(name, "Echo Server");
333 if (gnutls_global_init() < 0) {
334 fprintf(stderr, "global state initialization error\n");
335 exit(1);
338 /* Note that servers must generate parameters for
339 * Diffie Hellman. See gnutls_dh_params_generate(), and
340 * gnutls_dh_params_set().
342 if (generate != 0)
343 generate_dh_primes();
345 if (gnutls_certificate_allocate_sc(&cert_cred) < 0) {
346 fprintf(stderr, "memory error\n");
347 exit(1);
350 if (gnutls_certificate_set_x509_trust_file
351 (cert_cred, CAFILE, CRLFILE) < 0) {
352 fprintf(stderr,
353 "X509 PARSE ERROR\nDid you have ca.pem?\n");
354 exit(1);
357 if (gnutls_certificate_set_openpgp_key_file
358 (cert_cred, PGP_CERTFILE, PGP_KEYFILE) < 0) {
359 fprintf(stderr,
360 "Error while reading the OpenPGP key pair\n");
363 gnutls_certificate_set_openpgp_keyserver(cert_cred, "wwwkeys.pgp.net", 0);
365 if (gnutls_certificate_set_x509_key_file
366 (cert_cred, CERTFILE1, KEYFILE1) < 0) {
367 fprintf(stderr,
368 "X509 PARSE ERROR\nDid you have key.pem and cert.pem?\n");
369 exit(1);
372 if (gnutls_certificate_set_x509_key_file
373 (cert_cred, CERTFILE2, KEYFILE2) < 0) {
374 fprintf(stderr,
375 "X509 PARSE ERROR\nDid you have key.pem and cert.pem?\n");
376 exit(1);
379 if (generate!=0)
380 if (gnutls_certificate_set_dh_params(cert_cred, dh_params) < 0) {
381 fprintf(stderr,
382 "Error while setting DH parameters\n");
383 exit(1);
386 /* this is a password file (created with the included srpcrypt utility)
387 * Read README.crypt prior to using SRP.
389 gnutls_srp_allocate_server_sc(&srp_cred);
390 gnutls_srp_set_server_cred_file(srp_cred, SRP_PASSWD,
391 SRP_PASSWD_CONF);
393 gnutls_anon_allocate_server_sc(&dh_cred);
394 if (generate!=0)
395 gnutls_anon_set_server_dh_params( dh_cred, dh_params);
397 listen_sd = socket(AF_INET, SOCK_STREAM, 0);
398 ERR(listen_sd, "socket");
400 memset(&sa_serv, '\0', sizeof(sa_serv));
401 sa_serv.sin_family = AF_INET;
402 sa_serv.sin_addr.s_addr = INADDR_ANY;
403 sa_serv.sin_port = htons(port); /* Server Port number */
405 setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval,
406 sizeof(int));
407 err = bind(listen_sd, (SA *) & sa_serv, sizeof(sa_serv));
408 ERR(err, "bind");
409 err = listen(listen_sd, 1024);
410 ERR(err, "listen");
412 printf("%s ready. Listening to port '%d'.\n\n", name, port);
414 client_len = sizeof(sa_cli);
416 for (;;) {
417 state = initialize_state();
419 sd = accept(listen_sd, (SA *) & sa_cli, &client_len);
421 printf("- connection from %s, port %d\n",
422 inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf,
423 sizeof(topbuf)), ntohs(sa_cli.sin_port));
426 gnutls_transport_set_ptr(state, sd);
427 do {
428 ret = gnutls_handshake(state);
429 } while (ret == GNUTLS_E_INTERRUPTED
430 || ret == GNUTLS_E_AGAIN);
432 if (ret < 0) {
433 close(sd);
434 gnutls_deinit(state);
435 fprintf(stderr,
436 "*** Handshake has failed (%s)\n\n",
437 gnutls_strerror(ret));
438 check_alert(state, ret);
439 continue;
441 printf("- Handshake was completed\n");
443 print_info(state);
445 i = 0;
446 for (;;) {
447 bzero(buffer, MAX_BUF + 1);
448 ret =
449 read_request(state, buffer, MAX_BUF,
450 (http == 0) ? 1 : 2);
452 if (gnutls_error_is_fatal(ret) == 1 || ret == 0) {
453 fflush(stdout);
454 if (ret == 0) {
455 printf
456 ("\n- Peer has closed the GNUTLS connection\n");
457 fflush(stdout);
458 break;
459 } else {
460 fprintf(stderr,
461 "\n*** Received corrupted data(%d). Closing the connection.\n\n",
462 ret);
463 break;
468 if (ret > 0) {
469 if (http == 0) {
470 printf
471 ("* Read %d bytes from client.\n",
472 strlen(buffer));
473 do {
474 ret =
475 gnutls_record_send(state,
476 buffer,
477 strlen
478 (buffer));
479 } while (ret ==
480 GNUTLS_E_INTERRUPTED
481 || ret == GNUTLS_E_AGAIN);
482 printf
483 ("* Wrote %d bytes to client.\n",
484 ret);
485 } else {
486 strcpy(http_buffer, HTTP_BEGIN);
487 peer_print_info(state);
488 strcat(http_buffer, HTTP_END);
489 do {
490 ret =
491 gnutls_record_send(state,
492 http_buffer,
493 strlen
494 (http_buffer));
495 } while (ret ==
496 GNUTLS_E_INTERRUPTED
497 || ret == GNUTLS_E_AGAIN);
499 printf
500 ("- Served request. Closing connection.\n");
501 break;
504 i++;
505 #ifdef RENEGOTIATE
506 if (i == 20) {
507 do {
508 ret = gnutls_rehandshake(state);
509 } while (ret == GNUTLS_E_INTERRUPTED
510 || ret == GNUTLS_E_AGAIN);
512 printf("* Requesting rehandshake.\n");
513 /* continue handshake proccess */
514 do {
515 ret = gnutls_handshake(state);
516 } while (ret == GNUTLS_E_INTERRUPTED
517 || ret == GNUTLS_E_AGAIN);
518 printf("* Rehandshake returned %d\n", ret);
520 #endif
522 check_alert(state, ret);
524 if (http != 0) {
525 break; /* close the connection */
528 printf("\n");
529 do {
530 ret = gnutls_bye(state, GNUTLS_SHUT_WR);
531 } while (ret == GNUTLS_E_INTERRUPTED
532 || ret == GNUTLS_E_AGAIN);
533 /* do not wait for
534 * the peer to close the connection.
536 close(sd);
537 gnutls_deinit(state);
540 close(listen_sd);
542 gnutls_certificate_free_sc(cert_cred);
543 gnutls_srp_free_server_sc(srp_cred);
544 gnutls_anon_free_server_sc(dh_cred);
546 gnutls_global_deinit();
548 return 0;
553 static gaainfo info;
554 void gaa_parser(int argc, char **argv)
556 int i, j;
558 if (gaa(argc, argv, &info) != -1) {
559 fprintf(stderr, "Error in the arguments.\n");
560 exit(1);
563 if (info.http == 0)
564 http = 0;
565 else
566 http = 1;
568 if (info.generate == 0)
569 generate = 0;
570 else
571 generate = 1;
573 port = info.port;
575 if (info.proto != NULL && info.nproto > 0) {
576 for (j = i = 0; i < info.nproto; i++) {
577 if (strncasecmp(info.proto[i], "SSL", 3) == 0)
578 protocol_priority[j++] = GNUTLS_SSL3;
579 if (strncasecmp(info.proto[i], "TLS", 3) == 0)
580 protocol_priority[j++] = GNUTLS_TLS1;
582 protocol_priority[j] = 0;
585 if (info.ciphers != NULL && info.nciphers > 0) {
586 for (j = i = 0; i < info.nciphers; i++) {
587 if (strncasecmp(info.ciphers[i], "RIJ", 3) == 0)
588 cipher_priority[j++] =
589 GNUTLS_CIPHER_RIJNDAEL_128_CBC;
590 if (strncasecmp(info.ciphers[i], "TWO", 3) == 0)
591 cipher_priority[j++] =
592 GNUTLS_CIPHER_TWOFISH_128_CBC;
593 if (strncasecmp(info.ciphers[i], "3DE", 3) == 0)
594 cipher_priority[j++] =
595 GNUTLS_CIPHER_3DES_CBC;
596 if (strncasecmp(info.ciphers[i], "ARC", 3) == 0)
597 cipher_priority[j++] =
598 GNUTLS_CIPHER_ARCFOUR;
600 cipher_priority[j] = 0;
603 if (info.macs != NULL && info.nmacs > 0) {
604 for (j = i = 0; i < info.nmacs; i++) {
605 if (strncasecmp(info.macs[i], "MD5", 3) == 0)
606 mac_priority[j++] = GNUTLS_MAC_MD5;
607 if (strncasecmp(info.macs[i], "SHA", 3) == 0)
608 mac_priority[j++] = GNUTLS_MAC_SHA;
610 mac_priority[j] = 0;
613 if (info.ctype != NULL && info.nctype > 0) {
614 for (j = i = 0; i < info.nctype; i++) {
615 if (strncasecmp(info.ctype[i], "OPE", 3) == 0)
616 cert_type_priority[j++] =
617 GNUTLS_CRT_OPENPGP;
618 if (strncasecmp(info.ctype[i], "X", 1) == 0)
619 cert_type_priority[j++] = GNUTLS_CRT_X509;
621 cert_type_priority[j] = 0;
624 if (info.kx != NULL && info.nkx > 0) {
625 for (j = i = 0; i < info.nkx; i++) {
626 if (strncasecmp(info.kx[i], "SRP", 3) == 0)
627 kx_priority[j++] = GNUTLS_KX_SRP;
628 if (strncasecmp(info.kx[i], "RSA", 3) == 0)
629 kx_priority[j++] = GNUTLS_KX_RSA;
630 if (strncasecmp(info.kx[i], "DHE_RSA", 7) == 0)
631 kx_priority[j++] = GNUTLS_KX_DHE_RSA;
632 if (strncasecmp(info.kx[i], "DHE_DSS", 7) == 0)
633 kx_priority[j++] = GNUTLS_KX_DHE_DSS;
634 if (strncasecmp(info.kx[i], "ANON", 4) == 0)
635 kx_priority[j++] = GNUTLS_KX_ANON_DH;
637 kx_priority[j] = 0;
640 if (info.comp != NULL && info.ncomp > 0) {
641 for (j = i = 0; i < info.ncomp; i++) {
642 if (strncasecmp(info.comp[i], "NUL", 3) == 0)
643 comp_priority[j++] = GNUTLS_COMP_NULL;
644 if (strncasecmp(info.comp[i], "ZLI", 1) == 0)
645 comp_priority[j++] = GNUTLS_COMP_ZLIB;
647 comp_priority[j] = 0;