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"
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"
47 #define SRP_PASSWD "srp/tpasswd"
48 #define SRP_PASSWD_CONF "srp/tpasswd.conf"
50 /* konqueror cannot handle sending the page in multiple
54 static char http_buffer
[16 * 1024];
55 static int generate
= 0;
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);}
71 #define HTTP_BEGIN "HTTP/1.0 200 OK\n" \
72 "Content-Type: text/html\n" \
75 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
78 #define HTTP_END "</BODY></HTML>\n\n"
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
;
102 if (gnutls_dh_params_init( &dh_params
) < 0) {
103 fprintf(stderr
, "Error in dh parameter initialization\n");
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.
114 ("Generating Diffie Hellman parameters [%d]. Please wait...",
118 if (gnutls_dh_params_generate
119 (&prime
, &generator
, prime_nums
[i
]) < 0) {
120 fprintf(stderr
, "Error in prime generation\n");
124 if (gnutls_dh_params_set
125 (dh_params
, prime
, generator
, prime_nums
[i
]) < 0) {
126 fprintf(stderr
, "Error in prime replacement\n");
130 free(generator
.data
);
132 } while (prime_nums
[++i
] != 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)
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
) {
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
) {
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");
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
)
256 char c
, *ptr
, p1
= 0, p2
= 0;
259 for (n
= 1; n
< data_size
; n
++) {
261 rc
= gnutls_record_recv(state
, &c
, 1);
262 } while (rc
== GNUTLS_E_INTERRUPTED
263 || rc
== GNUTLS_E_AGAIN
);
267 if (c
== '\n' && rnl
== 1)
270 if (c
== '\n' && p1
== '\r' && p2
== '\n') {
278 } else if (rc
== 0) {
292 void check_alert(GNUTLS_STATE state
, int ret
)
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
)
302 ("* Received NO_RENEGOTIATION alert. Client Does not support renegotiation.\n");
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
;
314 struct sockaddr_in sa_serv
;
315 struct sockaddr_in sa_cli
;
319 char buffer
[MAX_BUF
+ 1];
323 signal(SIGPIPE
, SIG_IGN
);
325 gaa_parser(argc
, argv
);
328 strcpy(name
, "HTTP Server");
330 strcpy(name
, "Echo Server");
333 if (gnutls_global_init() < 0) {
334 fprintf(stderr
, "global state initialization error\n");
338 /* Note that servers must generate parameters for
339 * Diffie Hellman. See gnutls_dh_params_generate(), and
340 * gnutls_dh_params_set().
343 generate_dh_primes();
345 if (gnutls_certificate_allocate_sc(&cert_cred
) < 0) {
346 fprintf(stderr
, "memory error\n");
350 if (gnutls_certificate_set_x509_trust_file
351 (cert_cred
, CAFILE
, CRLFILE
) < 0) {
353 "X509 PARSE ERROR\nDid you have ca.pem?\n");
357 if (gnutls_certificate_set_openpgp_key_file
358 (cert_cred
, PGP_CERTFILE
, PGP_KEYFILE
) < 0) {
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) {
368 "X509 PARSE ERROR\nDid you have key.pem and cert.pem?\n");
372 if (gnutls_certificate_set_x509_key_file
373 (cert_cred
, CERTFILE2
, KEYFILE2
) < 0) {
375 "X509 PARSE ERROR\nDid you have key.pem and cert.pem?\n");
380 if (gnutls_certificate_set_dh_params(cert_cred
, dh_params
) < 0) {
382 "Error while setting DH parameters\n");
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
,
393 gnutls_anon_allocate_server_sc(&dh_cred
);
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
,
407 err
= bind(listen_sd
, (SA
*) & sa_serv
, sizeof(sa_serv
));
409 err
= listen(listen_sd
, 1024);
412 printf("%s ready. Listening to port '%d'.\n\n", name
, port
);
414 client_len
= sizeof(sa_cli
);
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
);
428 ret
= gnutls_handshake(state
);
429 } while (ret
== GNUTLS_E_INTERRUPTED
430 || ret
== GNUTLS_E_AGAIN
);
434 gnutls_deinit(state
);
436 "*** Handshake has failed (%s)\n\n",
437 gnutls_strerror(ret
));
438 check_alert(state
, ret
);
441 printf("- Handshake was completed\n");
447 bzero(buffer
, MAX_BUF
+ 1);
449 read_request(state
, buffer
, MAX_BUF
,
450 (http
== 0) ? 1 : 2);
452 if (gnutls_error_is_fatal(ret
) == 1 || ret
== 0) {
456 ("\n- Peer has closed the GNUTLS connection\n");
461 "\n*** Received corrupted data(%d). Closing the connection.\n\n",
471 ("* Read %d bytes from client.\n",
475 gnutls_record_send(state
,
481 || ret
== GNUTLS_E_AGAIN
);
483 ("* Wrote %d bytes to client.\n",
486 strcpy(http_buffer
, HTTP_BEGIN
);
487 peer_print_info(state
);
488 strcat(http_buffer
, HTTP_END
);
491 gnutls_record_send(state
,
497 || ret
== GNUTLS_E_AGAIN
);
500 ("- Served request. Closing connection.\n");
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 */
515 ret
= gnutls_handshake(state
);
516 } while (ret
== GNUTLS_E_INTERRUPTED
517 || ret
== GNUTLS_E_AGAIN
);
518 printf("* Rehandshake returned %d\n", ret
);
522 check_alert(state
, ret
);
525 break; /* close the connection */
530 ret
= gnutls_bye(state
, GNUTLS_SHUT_WR
);
531 } while (ret
== GNUTLS_E_INTERRUPTED
532 || ret
== GNUTLS_E_AGAIN
);
534 * the peer to close the connection.
537 gnutls_deinit(state
);
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();
554 void gaa_parser(int argc
, char **argv
)
558 if (gaa(argc
, argv
, &info
) != -1) {
559 fprintf(stderr
, "Error in the arguments.\n");
568 if (info
.generate
== 0)
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
;
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
++] =
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
;
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;