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;
47 char *srp_passwd_conf
;
56 char *x509_crlfile
= NULL
;
60 /* This is a sample TCP echo server.
61 * This will behave as an http server if any argument in the
62 * command line is present
66 #define SA struct sockaddr
67 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
70 #define HTTP_BEGIN "HTTP/1.0 200 OK\n" \
71 "Content-Type: text/html\n" \
74 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
77 #define HTTP_END "</BODY></HTML>\n\n"
81 /* These are global */
82 GNUTLS_SRP_SERVER_CREDENTIALS srp_cred
;
83 GNUTLS_ANON_SERVER_CREDENTIALS dh_cred
;
84 GNUTLS_CERTIFICATE_SERVER_CREDENTIALS cert_cred
;
87 #define DEFAULT_PRIME_BITS 1024
89 /* we use primes up to 1024 in this server.
90 * otherwise we should add them here.
92 static int prime_nums
[] = { 768, 1024, 0 };
94 GNUTLS_DH_PARAMS dh_params
;
96 static int generate_dh_primes(void)
98 gnutls_datum prime
, generator
;
101 if (gnutls_dh_params_init(&dh_params
) < 0) {
102 fprintf(stderr
, "Error in dh parameter initialization\n");
107 /* Generate Diffie Hellman parameters - for use with DHE
108 * kx algorithms. These should be discarded and regenerated
109 * once a day, once a week or once a month. Depends on the
110 * security requirements.
113 ("Generating Diffie Hellman parameters [%d]. Please wait...",
117 if (gnutls_dh_params_generate(&prime
, &generator
, prime_nums
[i
]) < 0) {
118 fprintf(stderr
, "Error in prime generation\n");
122 if (gnutls_dh_params_set
123 (dh_params
, prime
, generator
, prime_nums
[i
]) < 0) {
124 fprintf(stderr
, "Error in prime replacement\n");
128 free(generator
.data
);
130 } while (prime_nums
[++i
] != 0);
135 int protocol_priority
[16] = { GNUTLS_TLS1
, GNUTLS_SSL3
, 0 };
136 int kx_priority
[16] =
137 { GNUTLS_KX_DHE_DSS
, GNUTLS_KX_RSA
, GNUTLS_KX_DHE_RSA
, GNUTLS_KX_SRP
,
140 int cipher_priority
[16] =
141 { GNUTLS_CIPHER_RIJNDAEL_128_CBC
, GNUTLS_CIPHER_3DES_CBC
,
142 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)
153 gnutls_init(&state
, GNUTLS_SERVER
);
154 if ((ret
= gnutls_db_set_name(state
, "gnutls-rsm.db")) < 0)
156 "*** DB error (%d). Resuming will not be possible.\n\n",
159 /* null cipher is here only for debuging
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
);
182 /* Creates html with the current state information.
184 #define tmp2 &http_buffer[strlen(http_buffer)]
185 void peer_print_info(GNUTLS_STATE state
)
188 unsigned char sesid
[32];
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
) {
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
= gnutls_cert_type_get_name(gnutls_cert_type_get(state
));
222 sprintf(tmp2
, "Certificate Type: <b>%s</b><br>\n", tmp
);
225 tmp
= gnutls_kx_get_name(gnutls_kx_get(state
));
226 sprintf(tmp2
, "Key Exchange: <b>%s</b><br>\n", tmp
);
228 if (gnutls_kx_get(state
) == GNUTLS_KX_DHE_RSA
229 || gnutls_kx_get(state
) == GNUTLS_KX_DHE_DSS
) {
231 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
232 gnutls_dh_get_prime_bits(state
));
235 tmp
= gnutls_compression_get_name(gnutls_compression_get(state
));
236 sprintf(tmp2
, "Compression: <b>%s</b><br>\n", tmp
);
238 tmp
= gnutls_cipher_get_name(gnutls_cipher_get(state
));
239 sprintf(tmp2
, "Cipher: <b>%s</b><br>\n", tmp
);
241 tmp
= gnutls_mac_get_name(gnutls_mac_get(state
));
242 sprintf(tmp2
, "MAC: <b>%s</b><br>\n", tmp
);
244 strcat(http_buffer
, "</P>\n");
249 /* actually something like readline.
250 * if rnl!=1 then reads an http request in the form REQ\n\n
252 int read_request(GNUTLS_STATE state
, char *data
, int data_size
, int rnl
)
255 char c
, *ptr
, p1
= 0, p2
= 0;
258 for (n
= 1; n
< data_size
; n
++) {
260 rc
= gnutls_record_recv(state
, &c
, 1);
261 } while (rc
== GNUTLS_E_INTERRUPTED
|| rc
== GNUTLS_E_AGAIN
);
265 if (c
== '\n' && rnl
== 1)
268 if (c
== '\n' && p1
== '\r' && p2
== '\n') {
276 } else if (rc
== 0) {
291 void check_alert(GNUTLS_STATE state
, int ret
)
295 if (ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
296 || ret
== GNUTLS_E_FATAL_ALERT_RECEIVED
) {
297 last_alert
= gnutls_alert_get(state
);
298 if (last_alert
== GNUTLS_A_NO_RENEGOTIATION
&&
299 ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
)
301 ("* Received NO_RENEGOTIATION alert. Client Does not support renegotiation.\n");
303 printf("* Received alert '%d'.\n", ret
);
307 static void gaa_parser(int argc
, char **argv
);
309 int main(int argc
, char **argv
)
311 int err
, listen_sd
, i
;
313 struct sockaddr_in sa_serv
;
314 struct sockaddr_in sa_cli
;
318 char buffer
[MAX_BUF
+ 1];
322 signal(SIGPIPE
, SIG_IGN
);
324 gaa_parser(argc
, argv
);
327 strcpy(name
, "HTTP Server");
329 strcpy(name
, "Echo Server");
332 if (gnutls_global_init() < 0) {
333 fprintf(stderr
, "global state initialization error\n");
337 /* Note that servers must generate parameters for
338 * Diffie Hellman. See gnutls_dh_params_generate(), and
339 * gnutls_dh_params_set().
342 generate_dh_primes();
344 if (gnutls_certificate_allocate_sc(&cert_cred
) < 0) {
345 fprintf(stderr
, "memory error\n");
349 if (x509_cafile
!= NULL
) {
350 if ((ret
=gnutls_certificate_set_x509_trust_file
351 (cert_cred
, x509_cafile
, x509ctype
)) < 0) {
352 fprintf(stderr
, "Error reading '%s'\n", x509_cafile
);
355 printf("Processed %d CA certificate(s).\n", ret
);
359 if (pgp_keyring
!= NULL
) {
361 gnutls_certificate_set_openpgp_keyring_file(cert_cred
, pgp_keyring
);
363 fprintf(stderr
, "Error setting the OpenPGP keyring file\n");
367 if (pgp_trustdb
!= NULL
) {
368 gnutls_certificate_set_openpgp_trustdb(cert_cred
, pgp_trustdb
);
371 if (pgp_certfile
!= NULL
)
372 if (gnutls_certificate_set_openpgp_key_file
373 (cert_cred
, pgp_certfile
, pgp_keyfile
) < 0) {
375 "Error while reading the OpenPGP key pair ('%s', '%s')\n",
376 pgp_certfile
, pgp_keyfile
);
379 gnutls_certificate_set_openpgp_keyserver(cert_cred
, pgp_keyserver
, 0);
381 if (x509_certfile
!= NULL
)
382 if (gnutls_certificate_set_x509_key_file
383 (cert_cred
, x509_certfile
, x509_keyfile
, x509ctype
) < 0) {
385 "Error reading '%s' or '%s'\n", x509_certfile
,
391 if (gnutls_certificate_set_dh_params(cert_cred
, dh_params
) < 0) {
392 fprintf(stderr
, "Error while setting DH parameters\n");
396 /* this is a password file (created with the included srpcrypt utility)
397 * Read README.crypt prior to using SRP.
399 gnutls_srp_allocate_server_sc(&srp_cred
);
401 if (srp_passwd
!=NULL
)
402 if ((ret
=gnutls_srp_set_server_cred_file(srp_cred
, srp_passwd
, srp_passwd_conf
)) < 0) {
403 /* only exit is this function is not disabled
405 fprintf(stderr
, "Error while setting SRP parameters\n");
408 gnutls_anon_allocate_server_sc(&dh_cred
);
410 gnutls_anon_set_server_dh_params(dh_cred
, dh_params
);
412 listen_sd
= socket(AF_INET
, SOCK_STREAM
, 0);
413 ERR(listen_sd
, "socket");
415 memset(&sa_serv
, '\0', sizeof(sa_serv
));
416 sa_serv
.sin_family
= AF_INET
;
417 sa_serv
.sin_addr
.s_addr
= INADDR_ANY
;
418 sa_serv
.sin_port
= htons(port
); /* Server Port number */
420 setsockopt(listen_sd
, SOL_SOCKET
, SO_REUSEADDR
, &optval
, sizeof(int));
421 err
= bind(listen_sd
, (SA
*) & sa_serv
, sizeof(sa_serv
));
423 err
= listen(listen_sd
, 1024);
426 printf("%s ready. Listening to port '%d'.\n\n", name
, port
);
428 client_len
= sizeof(sa_cli
);
431 state
= initialize_state();
433 sd
= accept(listen_sd
, (SA
*) & sa_cli
, &client_len
);
435 printf("- connection from %s, port %d\n",
436 inet_ntop(AF_INET
, &sa_cli
.sin_addr
, topbuf
,
437 sizeof(topbuf
)), ntohs(sa_cli
.sin_port
));
440 gnutls_transport_set_ptr(state
, sd
);
442 ret
= gnutls_handshake(state
);
443 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
447 gnutls_deinit(state
);
449 "*** Handshake has failed (%s)\n\n",
450 gnutls_strerror(ret
));
451 check_alert(state
, ret
);
454 printf("- Handshake was completed\n");
455 if ( gnutls_session_is_resumed( state
)!=0)
456 printf("*** This is a resumed session\n");
462 bzero(buffer
, MAX_BUF
+ 1);
463 ret
= read_request(state
, buffer
, MAX_BUF
, (http
== 0) ? 1 : 2);
465 if (gnutls_error_is_fatal(ret
) == 1 || ret
== 0) {
468 printf("\n- Peer has closed the GNUTLS connection\n");
473 "\n*** Received corrupted data(%d). Closing the connection.\n\n",
482 printf("* Read %d bytes from client.\n", strlen(buffer
));
484 ret
= gnutls_record_send(state
, buffer
, strlen(buffer
));
486 GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
487 printf("* Wrote %d bytes to client.\n", ret
);
489 strcpy(http_buffer
, HTTP_BEGIN
);
490 peer_print_info(state
);
491 strcat(http_buffer
, HTTP_END
);
494 gnutls_record_send(state
,
495 http_buffer
, strlen(http_buffer
));
497 GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
499 printf("- Served request. Closing connection.\n");
507 ret
= gnutls_rehandshake(state
);
508 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
510 printf("* Requesting rehandshake.\n");
511 /* continue handshake proccess */
513 ret
= gnutls_handshake(state
);
514 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
515 printf("* Rehandshake returned %d\n", ret
);
519 check_alert(state
, ret
);
522 break; /* close the connection */
527 ret
= gnutls_bye(state
, GNUTLS_SHUT_WR
);
528 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
530 * the peer to close the connection.
533 gnutls_deinit(state
);
538 gnutls_certificate_free_sc(cert_cred
);
539 gnutls_srp_free_server_sc(srp_cred
);
540 gnutls_anon_free_server_sc(dh_cred
);
542 gnutls_global_deinit();
548 #define DEFAULT_X509_KEYFILE "x509/key.pem"
549 #define DEFAULT_X509_CERTFILE "x509/cert.pem"
551 #define DEFAULT_X509_KEYFILE2 "x509/key-dsa.pem"
552 #define DEFAULT_X509_CERTFILE2 "x509/cert-dsa.pem"
554 #define DEFAULT_PGP_KEYFILE "openpgp/sec.asc"
555 #define DEFAULT_PGP_CERTFILE "openpgp/pub.asc"
557 #define DEFAULT_X509_CAFILE "x509/ca.pem"
558 #define DEFAULT_X509_CRLFILE NULL;
560 #define DEFAULT_SRP_PASSWD "srp/tpasswd"
561 #define DEFAULT_SRP_PASSWD_CONF "srp/tpasswd.conf"
566 void gaa_parser(int argc
, char **argv
)
570 if (gaa(argc
, argv
, &info
) != -1) {
572 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
581 if (info
.fmtder
== 0)
582 x509ctype
= GNUTLS_X509_FMT_PEM
;
584 x509ctype
= GNUTLS_X509_FMT_DER
;
586 if (info
.generate
== 0)
594 if (info
.x509_certfile
!= NULL
)
595 x509_certfile
= info
.x509_certfile
;
597 x509_certfile
= DEFAULT_X509_CERTFILE
;
599 if (info
.x509_keyfile
!= NULL
)
600 x509_keyfile
= info
.x509_keyfile
;
602 x509_keyfile
= DEFAULT_X509_KEYFILE
;
604 if (info
.x509_cafile
!= NULL
)
605 x509_cafile
= info
.x509_certfile
;
607 x509_cafile
= DEFAULT_X509_CAFILE
;
609 if (info
.pgp_certfile
!= NULL
)
610 pgp_certfile
= info
.pgp_certfile
;
612 pgp_certfile
= DEFAULT_PGP_CERTFILE
;
614 if (info
.pgp_keyfile
!= NULL
)
615 pgp_keyfile
= info
.pgp_keyfile
;
617 pgp_keyfile
= DEFAULT_PGP_KEYFILE
;
619 if (info
.srp_passwd
!= NULL
)
620 srp_passwd
= info
.srp_passwd
;
622 srp_passwd
= DEFAULT_SRP_PASSWD
;
624 if (info
.srp_passwd_conf
!= NULL
)
625 srp_passwd_conf
= info
.srp_passwd_conf
;
627 srp_passwd_conf
= DEFAULT_SRP_PASSWD_CONF
;
629 x509_certfile
= info
.x509_certfile
;
630 x509_keyfile
= info
.x509_keyfile
;
631 x509_cafile
= info
.x509_cafile
;
632 pgp_certfile
= info
.pgp_certfile
;
633 pgp_keyfile
= info
.pgp_keyfile
;
634 srp_passwd
= info
.srp_passwd
;
635 srp_passwd_conf
= info
.srp_passwd_conf
;
638 pgp_keyserver
= info
.pgp_keyserver
;
639 pgp_keyring
= info
.pgp_keyring
;
640 pgp_trustdb
= info
.pgp_trustdb
;
642 if (info
.proto
!= NULL
&& info
.nproto
> 0) {
643 for (j
= i
= 0; i
< info
.nproto
; i
++) {
644 if (strncasecmp(info
.proto
[i
], "SSL", 3) == 0)
645 protocol_priority
[j
++] = GNUTLS_SSL3
;
646 if (strncasecmp(info
.proto
[i
], "TLS", 3) == 0)
647 protocol_priority
[j
++] = GNUTLS_TLS1
;
649 protocol_priority
[j
] = 0;
652 if (info
.ciphers
!= NULL
&& info
.nciphers
> 0) {
653 for (j
= i
= 0; i
< info
.nciphers
; i
++) {
654 if (strncasecmp(info
.ciphers
[i
], "RIJ", 3) == 0)
655 cipher_priority
[j
++] = GNUTLS_CIPHER_RIJNDAEL_128_CBC
;
656 if (strncasecmp(info
.ciphers
[i
], "TWO", 3) == 0)
657 cipher_priority
[j
++] = GNUTLS_CIPHER_TWOFISH_128_CBC
;
658 if (strncasecmp(info
.ciphers
[i
], "3DE", 3) == 0)
659 cipher_priority
[j
++] = GNUTLS_CIPHER_3DES_CBC
;
660 if (strncasecmp(info
.ciphers
[i
], "ARC", 3) == 0)
661 cipher_priority
[j
++] = GNUTLS_CIPHER_ARCFOUR
;
663 cipher_priority
[j
] = 0;
666 if (info
.macs
!= NULL
&& info
.nmacs
> 0) {
667 for (j
= i
= 0; i
< info
.nmacs
; i
++) {
668 if (strncasecmp(info
.macs
[i
], "MD5", 3) == 0)
669 mac_priority
[j
++] = GNUTLS_MAC_MD5
;
670 if (strncasecmp(info
.macs
[i
], "SHA", 3) == 0)
671 mac_priority
[j
++] = GNUTLS_MAC_SHA
;
676 if (info
.ctype
!= NULL
&& info
.nctype
> 0) {
677 for (j
= i
= 0; i
< info
.nctype
; i
++) {
678 if (strncasecmp(info
.ctype
[i
], "OPE", 3) == 0)
679 cert_type_priority
[j
++] = GNUTLS_CRT_OPENPGP
;
680 if (strncasecmp(info
.ctype
[i
], "X", 1) == 0)
681 cert_type_priority
[j
++] = GNUTLS_CRT_X509
;
683 cert_type_priority
[j
] = 0;
686 if (info
.kx
!= NULL
&& info
.nkx
> 0) {
687 for (j
= i
= 0; i
< info
.nkx
; i
++) {
688 if (strncasecmp(info
.kx
[i
], "SRP", 3) == 0)
689 kx_priority
[j
++] = GNUTLS_KX_SRP
;
690 if (strncasecmp(info
.kx
[i
], "RSA", 3) == 0)
691 kx_priority
[j
++] = GNUTLS_KX_RSA
;
692 if (strncasecmp(info
.kx
[i
], "DHE_RSA", 7) == 0)
693 kx_priority
[j
++] = GNUTLS_KX_DHE_RSA
;
694 if (strncasecmp(info
.kx
[i
], "DHE_DSS", 7) == 0)
695 kx_priority
[j
++] = GNUTLS_KX_DHE_DSS
;
696 if (strncasecmp(info
.kx
[i
], "ANON", 4) == 0)
697 kx_priority
[j
++] = GNUTLS_KX_ANON_DH
;
702 if (info
.comp
!= NULL
&& info
.ncomp
> 0) {
703 for (j
= i
= 0; i
< info
.ncomp
; i
++) {
704 if (strncasecmp(info
.comp
[i
], "NUL", 3) == 0)
705 comp_priority
[j
++] = GNUTLS_COMP_NULL
;
706 if (strncasecmp(info
.comp
[i
], "ZLI", 1) == 0)
707 comp_priority
[j
++] = GNUTLS_COMP_ZLIB
;
709 comp_priority
[j
] = 0;