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
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
30 #include "../lib/gnutls.h"
36 /* konqueror cannot handle sending the page in multiple
40 static char http_buffer
[16 * 1024];
41 static int generate
= 0;
46 char *srp_passwd_conf
;
55 char *x509_crlfile
= NULL
;
59 /* This is a sample TCP echo server.
60 * This will behave as an http server if any argument in the
61 * command line is present
65 #define SA struct sockaddr
66 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
69 #define HTTP_BEGIN "HTTP/1.0 200 OK\n" \
70 "Content-Type: text/html\n" \
73 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
76 #define HTTP_END "</BODY></HTML>\n\n"
80 /* These are global */
81 GNUTLS_SRP_SERVER_CREDENTIALS srp_cred
;
82 GNUTLS_ANON_SERVER_CREDENTIALS dh_cred
;
83 GNUTLS_CERTIFICATE_SERVER_CREDENTIALS cert_cred
;
86 #define DEFAULT_PRIME_BITS 1024
88 /* we use primes up to 1024 in this server.
89 * otherwise we should add them here.
91 static int prime_nums
[] = { 768, 1024, 0 };
93 GNUTLS_DH_PARAMS dh_params
;
95 static int generate_dh_primes(void)
97 gnutls_datum prime
, generator
;
100 if (gnutls_dh_params_init(&dh_params
) < 0) {
101 fprintf(stderr
, "Error in dh parameter initialization\n");
106 /* Generate Diffie Hellman parameters - for use with DHE
107 * kx algorithms. These should be discarded and regenerated
108 * once a day, once a week or once a month. Depends on the
109 * security requirements.
112 ("Generating Diffie Hellman parameters [%d]. Please wait...",
116 if (gnutls_dh_params_generate(&prime
, &generator
, prime_nums
[i
]) < 0) {
117 fprintf(stderr
, "Error in prime generation\n");
121 if (gnutls_dh_params_set
122 (dh_params
, prime
, generator
, prime_nums
[i
]) < 0) {
123 fprintf(stderr
, "Error in prime replacement\n");
127 free(generator
.data
);
129 } while (prime_nums
[++i
] != 0);
134 int protocol_priority
[16] = { GNUTLS_TLS1
, GNUTLS_SSL3
, 0 };
135 int kx_priority
[16] =
136 { GNUTLS_KX_DHE_DSS
, GNUTLS_KX_RSA
, GNUTLS_KX_DHE_RSA
, GNUTLS_KX_SRP
,
139 int cipher_priority
[16] =
140 { GNUTLS_CIPHER_RIJNDAEL_128_CBC
, GNUTLS_CIPHER_3DES_CBC
,
141 GNUTLS_CIPHER_ARCFOUR
, 0
143 int comp_priority
[16] = { GNUTLS_COMP_ZLIB
, GNUTLS_COMP_NULL
, 0 };
144 int mac_priority
[16] = { GNUTLS_MAC_SHA
, GNUTLS_MAC_MD5
, 0 };
145 int cert_type_priority
[16] = { GNUTLS_CRT_X509
, GNUTLS_CRT_OPENPGP
, 0 };
147 GNUTLS_STATE
initialize_state(void)
152 gnutls_init(&state
, GNUTLS_SERVER
);
153 if ((ret
= gnutls_db_set_name(state
, "gnutls-rsm.db")) < 0)
155 "*** DB error (%d). Resuming will not be possible.\n\n",
158 /* null cipher is here only for debuging
161 gnutls_cipher_set_priority(state
, cipher_priority
);
162 gnutls_compression_set_priority(state
, comp_priority
);
163 gnutls_kx_set_priority(state
, kx_priority
);
164 gnutls_protocol_set_priority(state
, protocol_priority
);
165 gnutls_mac_set_priority(state
, mac_priority
);
166 gnutls_cert_type_set_priority(state
, cert_type_priority
);
168 gnutls_dh_set_prime_bits(state
, DEFAULT_PRIME_BITS
);
170 gnutls_cred_set(state
, GNUTLS_CRD_ANON
, dh_cred
);
171 gnutls_cred_set(state
, GNUTLS_CRD_SRP
, srp_cred
);
172 gnutls_cred_set(state
, GNUTLS_CRD_CERTIFICATE
, cert_cred
);
174 gnutls_mac_set_priority(state
, mac_priority
);
176 gnutls_certificate_server_set_request(state
, GNUTLS_CERT_REQUEST
);
181 /* Creates html with the current state information.
183 #define tmp2 &http_buffer[strlen(http_buffer)]
184 void peer_print_info(GNUTLS_STATE state
)
187 unsigned char sesid
[32];
190 /* print session_id */
191 gnutls_session_get_id(state
, sesid
, &sesid_size
);
192 sprintf(tmp2
, "\n<p>Session ID: <i>");
193 for (i
= 0; i
< sesid_size
; i
++)
194 sprintf(tmp2
, "%.2X", sesid
[i
]);
195 sprintf(tmp2
, "</i></p>\n");
197 /* Here unlike print_info() we use the kx algorithm to distinguish
198 * the functions to call.
201 /* print srp specific data */
202 if (gnutls_kx_get(state
) == GNUTLS_KX_SRP
) {
203 sprintf(tmp2
, "<p>Connected as user '%s'.</p>\n",
204 gnutls_srp_server_get_username(state
));
207 if (gnutls_kx_get(state
) == GNUTLS_KX_ANON_DH
) {
209 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
210 gnutls_dh_get_prime_bits(state
));
213 /* print state information */
214 strcat(http_buffer
, "<P>\n");
216 tmp
= gnutls_protocol_get_name(gnutls_protocol_get_version(state
));
217 sprintf(tmp2
, "Protocol version: <b>%s</b><br>\n", tmp
);
219 if (gnutls_auth_get_type(state
) == GNUTLS_CRD_CERTIFICATE
) {
220 tmp
= gnutls_cert_type_get_name(gnutls_cert_type_get(state
));
221 sprintf(tmp2
, "Certificate Type: <b>%s</b><br>\n", tmp
);
224 tmp
= gnutls_kx_get_name(gnutls_kx_get(state
));
225 sprintf(tmp2
, "Key Exchange: <b>%s</b><br>\n", tmp
);
227 if (gnutls_kx_get(state
) == GNUTLS_KX_DHE_RSA
228 || gnutls_kx_get(state
) == GNUTLS_KX_DHE_DSS
) {
230 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
231 gnutls_dh_get_prime_bits(state
));
234 tmp
= gnutls_compression_get_name(gnutls_compression_get(state
));
235 sprintf(tmp2
, "Compression: <b>%s</b><br>\n", tmp
);
237 tmp
= gnutls_cipher_get_name(gnutls_cipher_get(state
));
238 sprintf(tmp2
, "Cipher: <b>%s</b><br>\n", tmp
);
240 tmp
= gnutls_mac_get_name(gnutls_mac_get(state
));
241 sprintf(tmp2
, "MAC: <b>%s</b><br>\n", tmp
);
243 strcat(http_buffer
, "</P>\n");
248 /* actually something like readline.
249 * if rnl!=1 then reads an http request in the form REQ\n\n
251 int read_request(GNUTLS_STATE state
, char *data
, int data_size
, int rnl
)
254 char c
, *ptr
, p1
= 0, p2
= 0;
257 for (n
= 1; n
< data_size
; n
++) {
259 rc
= gnutls_record_recv(state
, &c
, 1);
260 } while (rc
== GNUTLS_E_INTERRUPTED
|| rc
== GNUTLS_E_AGAIN
);
264 if (c
== '\n' && rnl
== 1)
267 if (c
== '\n' && p1
== '\r' && p2
== '\n') {
275 } else if (rc
== 0) {
290 void check_alert(GNUTLS_STATE state
, int ret
)
294 if (ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
295 || ret
== GNUTLS_E_FATAL_ALERT_RECEIVED
) {
296 last_alert
= gnutls_alert_get(state
);
297 if (last_alert
== GNUTLS_A_NO_RENEGOTIATION
&&
298 ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
)
300 ("* Received NO_RENEGOTIATION alert. Client Does not support renegotiation.\n");
302 printf("* Received alert '%d'.\n", ret
);
306 static void gaa_parser(int argc
, char **argv
);
308 int main(int argc
, char **argv
)
310 int err
, listen_sd
, i
;
312 struct sockaddr_in sa_serv
;
313 struct sockaddr_in sa_cli
;
317 char buffer
[MAX_BUF
+ 1];
321 signal(SIGPIPE
, SIG_IGN
);
323 gaa_parser(argc
, argv
);
326 strcpy(name
, "HTTP Server");
328 strcpy(name
, "Echo Server");
331 if (gnutls_global_init() < 0) {
332 fprintf(stderr
, "global state initialization error\n");
336 /* Note that servers must generate parameters for
337 * Diffie Hellman. See gnutls_dh_params_generate(), and
338 * gnutls_dh_params_set().
341 generate_dh_primes();
343 if (gnutls_certificate_allocate_sc(&cert_cred
) < 0) {
344 fprintf(stderr
, "memory error\n");
348 if (x509_cafile
!= NULL
)
349 if (gnutls_certificate_set_x509_trust_file
350 (cert_cred
, x509_cafile
, x509_crlfile
, GNUTLS_X509_FMT_DER
) < 0) {
351 fprintf(stderr
, "Error reading '%s'\n", x509_cafile
);
355 if (pgp_keyring
!= NULL
) {
357 gnutls_certificate_set_openpgp_keyring_file(cert_cred
, pgp_keyring
);
359 fprintf(stderr
, "Error setting the OpenPGP keyring file\n");
363 if (pgp_trustdb
!= NULL
) {
364 gnutls_certificate_set_openpgp_trustdb(cert_cred
, pgp_trustdb
);
367 if (pgp_certfile
!= NULL
)
368 if (gnutls_certificate_set_openpgp_key_file
369 (cert_cred
, pgp_certfile
, pgp_keyfile
) < 0) {
371 "Error while reading the OpenPGP key pair ('%s', '%s')\n",
372 pgp_certfile
, pgp_keyfile
);
375 gnutls_certificate_set_openpgp_keyserver(cert_cred
, pgp_keyserver
, 0);
377 if (x509_certfile
!= NULL
)
378 if (gnutls_certificate_set_x509_key_file
379 (cert_cred
, x509_certfile
, x509_keyfile
, GNUTLS_X509_FMT_DER
) < 0) {
381 "Error reading '%s' or '%s'\n", x509_certfile
,
387 if (gnutls_certificate_set_dh_params(cert_cred
, dh_params
) < 0) {
388 fprintf(stderr
, "Error while setting DH parameters\n");
392 /* this is a password file (created with the included srpcrypt utility)
393 * Read README.crypt prior to using SRP.
395 gnutls_srp_allocate_server_sc(&srp_cred
);
396 gnutls_srp_set_server_cred_file(srp_cred
, srp_passwd
, srp_passwd_conf
);
398 gnutls_anon_allocate_server_sc(&dh_cred
);
400 gnutls_anon_set_server_dh_params(dh_cred
, dh_params
);
402 listen_sd
= socket(AF_INET
, SOCK_STREAM
, 0);
403 ERR(listen_sd
, "socket");
405 memset(&sa_serv
, '\0', sizeof(sa_serv
));
406 sa_serv
.sin_family
= AF_INET
;
407 sa_serv
.sin_addr
.s_addr
= INADDR_ANY
;
408 sa_serv
.sin_port
= htons(port
); /* Server Port number */
410 setsockopt(listen_sd
, SOL_SOCKET
, SO_REUSEADDR
, &optval
, sizeof(int));
411 err
= bind(listen_sd
, (SA
*) & sa_serv
, sizeof(sa_serv
));
413 err
= listen(listen_sd
, 1024);
416 printf("%s ready. Listening to port '%d'.\n\n", name
, port
);
418 client_len
= sizeof(sa_cli
);
421 state
= initialize_state();
423 sd
= accept(listen_sd
, (SA
*) & sa_cli
, &client_len
);
425 printf("- connection from %s, port %d\n",
426 inet_ntop(AF_INET
, &sa_cli
.sin_addr
, topbuf
,
427 sizeof(topbuf
)), ntohs(sa_cli
.sin_port
));
430 gnutls_transport_set_ptr(state
, sd
);
432 ret
= gnutls_handshake(state
);
433 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
437 gnutls_deinit(state
);
439 "*** Handshake has failed (%s)\n\n",
440 gnutls_strerror(ret
));
441 check_alert(state
, ret
);
444 printf("- Handshake was completed\n");
450 bzero(buffer
, MAX_BUF
+ 1);
451 ret
= read_request(state
, buffer
, MAX_BUF
, (http
== 0) ? 1 : 2);
453 if (gnutls_error_is_fatal(ret
) == 1 || ret
== 0) {
456 printf("\n- Peer has closed the GNUTLS connection\n");
461 "\n*** Received corrupted data(%d). Closing the connection.\n\n",
470 printf("* Read %d bytes from client.\n", strlen(buffer
));
472 ret
= gnutls_record_send(state
, buffer
, strlen(buffer
));
474 GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
475 printf("* Wrote %d bytes to client.\n", ret
);
477 strcpy(http_buffer
, HTTP_BEGIN
);
478 peer_print_info(state
);
479 strcat(http_buffer
, HTTP_END
);
482 gnutls_record_send(state
,
483 http_buffer
, strlen(http_buffer
));
485 GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
487 printf("- Served request. Closing connection.\n");
495 ret
= gnutls_rehandshake(state
);
496 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
498 printf("* Requesting rehandshake.\n");
499 /* continue handshake proccess */
501 ret
= gnutls_handshake(state
);
502 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
503 printf("* Rehandshake returned %d\n", ret
);
507 check_alert(state
, ret
);
510 break; /* close the connection */
515 ret
= gnutls_bye(state
, GNUTLS_SHUT_WR
);
516 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
518 * the peer to close the connection.
521 gnutls_deinit(state
);
526 gnutls_certificate_free_sc(cert_cred
);
527 gnutls_srp_free_server_sc(srp_cred
);
528 gnutls_anon_free_server_sc(dh_cred
);
530 gnutls_global_deinit();
536 #define DEFAULT_X509_KEYFILE "x509/key.pem"
537 #define DEFAULT_X509_CERTFILE "x509/cert.pem"
539 #define DEFAULT_X509_KEYFILE2 "x509/key-dsa.pem"
540 #define DEFAULT_X509_CERTFILE2 "x509/cert-dsa.pem"
542 #define DEFAULT_PGP_KEYFILE "openpgp/sec.asc"
543 #define DEFAULT_PGP_CERTFILE "openpgp/pub.asc"
545 #define DEFAULT_X509_CAFILE "x509/ca.pem"
546 #define DEFAULT_X509_CRLFILE NULL;
548 #define DEFAULT_SRP_PASSWD "srp/tpasswd"
549 #define DEFAULT_SRP_PASSWD_CONF "srp/tpasswd.conf"
554 void gaa_parser(int argc
, char **argv
)
558 if (gaa(argc
, argv
, &info
) != -1) {
560 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
569 if (info
.generate
== 0)
577 if (info
.x509_certfile
!= NULL
)
578 x509_certfile
= info
.x509_certfile
;
580 x509_certfile
= DEFAULT_X509_CERTFILE
;
582 if (info
.x509_keyfile
!= NULL
)
583 x509_keyfile
= info
.x509_keyfile
;
585 x509_keyfile
= DEFAULT_X509_KEYFILE
;
587 if (info
.x509_cafile
!= NULL
)
588 x509_cafile
= info
.x509_certfile
;
590 x509_cafile
= DEFAULT_X509_CAFILE
;
592 if (info
.pgp_certfile
!= NULL
)
593 pgp_certfile
= info
.pgp_certfile
;
595 pgp_certfile
= DEFAULT_PGP_CERTFILE
;
597 if (info
.pgp_keyfile
!= NULL
)
598 pgp_keyfile
= info
.pgp_keyfile
;
600 pgp_keyfile
= DEFAULT_PGP_KEYFILE
;
602 if (info
.srp_passwd
!= NULL
)
603 srp_passwd
= info
.srp_passwd
;
605 srp_passwd
= DEFAULT_SRP_PASSWD
;
607 if (info
.srp_passwd_conf
!= NULL
)
608 srp_passwd_conf
= info
.srp_passwd_conf
;
610 srp_passwd_conf
= DEFAULT_SRP_PASSWD_CONF
;
612 x509_certfile
= info
.x509_certfile
;
613 x509_keyfile
= info
.x509_keyfile
;
614 x509_cafile
= info
.x509_cafile
;
615 pgp_certfile
= info
.pgp_certfile
;
616 pgp_keyfile
= info
.pgp_keyfile
;
617 srp_passwd
= info
.srp_passwd
;
618 srp_passwd_conf
= info
.srp_passwd_conf
;
621 pgp_keyserver
= info
.pgp_keyserver
;
622 pgp_keyring
= info
.pgp_keyring
;
623 pgp_trustdb
= info
.pgp_trustdb
;
625 if (info
.proto
!= NULL
&& info
.nproto
> 0) {
626 for (j
= i
= 0; i
< info
.nproto
; i
++) {
627 if (strncasecmp(info
.proto
[i
], "SSL", 3) == 0)
628 protocol_priority
[j
++] = GNUTLS_SSL3
;
629 if (strncasecmp(info
.proto
[i
], "TLS", 3) == 0)
630 protocol_priority
[j
++] = GNUTLS_TLS1
;
632 protocol_priority
[j
] = 0;
635 if (info
.ciphers
!= NULL
&& info
.nciphers
> 0) {
636 for (j
= i
= 0; i
< info
.nciphers
; i
++) {
637 if (strncasecmp(info
.ciphers
[i
], "RIJ", 3) == 0)
638 cipher_priority
[j
++] = GNUTLS_CIPHER_RIJNDAEL_128_CBC
;
639 if (strncasecmp(info
.ciphers
[i
], "TWO", 3) == 0)
640 cipher_priority
[j
++] = GNUTLS_CIPHER_TWOFISH_128_CBC
;
641 if (strncasecmp(info
.ciphers
[i
], "3DE", 3) == 0)
642 cipher_priority
[j
++] = GNUTLS_CIPHER_3DES_CBC
;
643 if (strncasecmp(info
.ciphers
[i
], "ARC", 3) == 0)
644 cipher_priority
[j
++] = GNUTLS_CIPHER_ARCFOUR
;
646 cipher_priority
[j
] = 0;
649 if (info
.macs
!= NULL
&& info
.nmacs
> 0) {
650 for (j
= i
= 0; i
< info
.nmacs
; i
++) {
651 if (strncasecmp(info
.macs
[i
], "MD5", 3) == 0)
652 mac_priority
[j
++] = GNUTLS_MAC_MD5
;
653 if (strncasecmp(info
.macs
[i
], "SHA", 3) == 0)
654 mac_priority
[j
++] = GNUTLS_MAC_SHA
;
659 if (info
.ctype
!= NULL
&& info
.nctype
> 0) {
660 for (j
= i
= 0; i
< info
.nctype
; i
++) {
661 if (strncasecmp(info
.ctype
[i
], "OPE", 3) == 0)
662 cert_type_priority
[j
++] = GNUTLS_CRT_OPENPGP
;
663 if (strncasecmp(info
.ctype
[i
], "X", 1) == 0)
664 cert_type_priority
[j
++] = GNUTLS_CRT_X509
;
666 cert_type_priority
[j
] = 0;
669 if (info
.kx
!= NULL
&& info
.nkx
> 0) {
670 for (j
= i
= 0; i
< info
.nkx
; i
++) {
671 if (strncasecmp(info
.kx
[i
], "SRP", 3) == 0)
672 kx_priority
[j
++] = GNUTLS_KX_SRP
;
673 if (strncasecmp(info
.kx
[i
], "RSA", 3) == 0)
674 kx_priority
[j
++] = GNUTLS_KX_RSA
;
675 if (strncasecmp(info
.kx
[i
], "DHE_RSA", 7) == 0)
676 kx_priority
[j
++] = GNUTLS_KX_DHE_RSA
;
677 if (strncasecmp(info
.kx
[i
], "DHE_DSS", 7) == 0)
678 kx_priority
[j
++] = GNUTLS_KX_DHE_DSS
;
679 if (strncasecmp(info
.kx
[i
], "ANON", 4) == 0)
680 kx_priority
[j
++] = GNUTLS_KX_ANON_DH
;
685 if (info
.comp
!= NULL
&& info
.ncomp
> 0) {
686 for (j
= i
= 0; i
< info
.ncomp
; i
++) {
687 if (strncasecmp(info
.comp
[i
], "NUL", 3) == 0)
688 comp_priority
[j
++] = GNUTLS_COMP_NULL
;
689 if (strncasecmp(info
.comp
[i
], "ZLI", 1) == 0)
690 comp_priority
[j
++] = GNUTLS_COMP_ZLIB
;
692 comp_priority
[j
] = 0;