diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-12-26 17:08:20 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-12-28 16:08:55 +0200 |
commit | 7e4d424ef99f39a2a6d5fd13146281d9744d3c0b (patch) | |
tree | 5693dc03580ea90a90fcfd68a84c0128e4cf8a38 /doc | |
parent | e38f4775671c15170638c865d2edf3025930ef76 (diff) | |
download | gnutls-7e4d424ef99f39a2a6d5fd13146281d9744d3c0b.tar.gz |
Added DTLS server example.
Diffstat (limited to 'doc')
-rw-r--r-- | doc/cha-gtls-app.texi | 2 | ||||
-rw-r--r-- | doc/cha-gtls-examples.texi | 29 | ||||
-rw-r--r-- | doc/examples/Makefile.am | 2 | ||||
-rw-r--r-- | doc/examples/ex-serv-dtls.c | 408 | ||||
-rw-r--r-- | doc/examples/ex-serv1.c | 16 |
5 files changed, 433 insertions, 24 deletions
diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi index 715471c4df..be12188529 100644 --- a/doc/cha-gtls-app.texi +++ b/doc/cha-gtls-app.texi @@ -750,7 +750,7 @@ COMP-NULL, COMP-DEFLATE. Catch all is COMP-ALL. @item TLS versions @tab VERS-SSL3.0, VERS-TLS1.0, VERS-TLS1.1, -VERS-TLS1.2. Catch all is VERS-TLS-ALL. +VERS-TLS1.2, VERS-DTLS1.0. Catch all is VERS-TLS-ALL. @item Signature algorithms @tab SIGN-RSA-SHA1, SIGN-RSA-SHA224, diff --git a/doc/cha-gtls-examples.texi b/doc/cha-gtls-examples.texi index 7ce4ee13ed..23f76100d8 100644 --- a/doc/cha-gtls-examples.texi +++ b/doc/cha-gtls-examples.texi @@ -150,21 +150,22 @@ This section contains examples of @acronym{TLS} and @acronym{SSL} servers, using @acronym{GnuTLS}. @menu -* Echo Server with X.509 authentication:: -* Echo Server with OpenPGP authentication:: -* Echo Server with SRP authentication:: -* Echo Server with anonymous authentication:: +* Echo server with X.509 authentication:: +* Echo server with OpenPGP authentication:: +* Echo server with SRP authentication:: +* Echo server with anonymous authentication:: +* Echo DTLS server with X.509 authentication:: @end menu -@node Echo Server with X.509 authentication +@node Echo server with X.509 authentication @subsection Echo server with @acronym{X.509} authentication This example is a very simple echo server which supports -@acronym{X.509} authentication, using the RSA ciphersuites. +@acronym{X.509} authentication. @verbatiminclude examples/ex-serv1.c -@node Echo Server with OpenPGP authentication +@node Echo server with OpenPGP authentication @subsection Echo server with @acronym{OpenPGP} authentication @cindex OpenPGP server @@ -176,7 +177,7 @@ them to keep these examples as simple as possible. @verbatiminclude examples/ex-serv-pgp.c -@node Echo Server with SRP authentication +@node Echo server with SRP authentication @subsection Echo server with @acronym{SRP} authentication This is a server which supports @acronym{SRP} authentication. It is @@ -185,14 +186,22 @@ server. Here it is separate for simplicity. @verbatiminclude examples/ex-serv-srp.c -@node Echo Server with anonymous authentication -@subsection Echo Server with anonymous authentication +@node Echo server with anonymous authentication +@subsection Echo server with anonymous authentication This example server support anonymous authentication, and could be used to serve the example client for anonymous authentication. @verbatiminclude examples/ex-serv-anon.c +@node Echo DTLS server with X.509 authentication +@subsection Echo DTLS server with @acronym{X.509} authentication + +This example is a very simple echo server using Datagram TLS and +@acronym{X.509} authentication. + +@verbatiminclude examples/ex-serv-dtls.c + @node Miscellaneous examples @section Miscellaneous examples diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 0ed1eae2db..38d25a5dd2 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -45,7 +45,7 @@ noinst_PROGRAMS = ex-client-resume ex-client-udp noinst_PROGRAMS += ex-cert-select ex-rfc2818 if ENABLE_PKI -noinst_PROGRAMS += ex-crq ex-serv1 +noinst_PROGRAMS += ex-crq ex-serv1 ex-serv-dtls endif if ENABLE_CXX diff --git a/doc/examples/ex-serv-dtls.c b/doc/examples/ex-serv-dtls.c new file mode 100644 index 0000000000..bdcbe3bb61 --- /dev/null +++ b/doc/examples/ex-serv-dtls.c @@ -0,0 +1,408 @@ +/* This example code is placed in the public domain. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/select.h> +#include <netdb.h> +#include <string.h> +#include <unistd.h> +#include <gnutls/gnutls.h> +#include <gnutls/dtls.h> + +#define KEYFILE "key.pem" +#define CERTFILE "cert.pem" +#define CAFILE "ca.pem" +#define CRLFILE "crl.pem" + +/* This is a sample DTLS echo server, using X.509 authentication. + */ + +#define SA struct sockaddr +#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);} +#define MAX_BUFFER 1024 +#define PORT 5556 /* listen to 5556 port */ + +typedef struct { + gnutls_session_t session; + int fd; + struct sockaddr * cli_addr; + socklen_t cli_addr_size; +} priv_data_st; + +static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms); +static ssize_t push_func (gnutls_transport_ptr_t p, const void * data, size_t size); +static ssize_t pull_func(gnutls_transport_ptr_t p, void * data, size_t size); +static const char * +human_addr (const struct sockaddr *sa, socklen_t salen, + char *buf, size_t buflen); +static int wait_for_connection(int fd); +static gnutls_session_t initialize_tls_session (void); +static int generate_dh_params (void); + +/* These are global */ +static gnutls_certificate_credentials_t x509_cred; +static gnutls_priority_t priority_cache; +static gnutls_dh_params_t dh_params; + +int +main (void) +{ + int err, listen_sd; + int sock, ret; + struct sockaddr_in sa_serv; + struct sockaddr_in cli_addr; + socklen_t cli_addr_size; + gnutls_session_t session; + char buffer[MAX_BUFFER]; + priv_data_st priv; + gnutls_datum_t cookie_key; + gnutls_dtls_prestate_st prestate; + int mtu = 1400; + unsigned char sequence[8]; + + /* this must be called once in the program + */ + gnutls_global_init (); + + gnutls_certificate_allocate_credentials (&x509_cred); + gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE, + GNUTLS_X509_FMT_PEM); + + gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE, + GNUTLS_X509_FMT_PEM); + + gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE, + GNUTLS_X509_FMT_PEM); + + generate_dh_params (); + + gnutls_certificate_set_dh_params (x509_cred, dh_params); + + ret = gnutls_priority_init (&priority_cache, "NORMAL:-VERS-TLS-ALL:+VERS-DTLS1.0", NULL); + if (ret < 0) + { + fprintf(stderr, "Error in the priority string\n"); + exit(1); + } + + ret = gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE); + if (ret < 0) + { + fprintf(stderr, "Cannot generate key\n"); + exit(1); + } + + /* Socket operations + */ + listen_sd = socket (AF_INET, SOCK_DGRAM, 0); + SOCKET_ERR (listen_sd, "socket"); + + memset (&sa_serv, '\0', sizeof (sa_serv)); + sa_serv.sin_family = AF_INET; + sa_serv.sin_addr.s_addr = INADDR_ANY; + sa_serv.sin_port = htons (PORT); /* Server Port number */ + +#ifdef IP_DONTFRAG + { + int optval = 1; + if (setsockopt (s, IPPROTO_IP, IP_DONTFRAG, + (const void *) &optval, sizeof (optval)) < 0) + { + perror ("setsockopt(IP_DF) failed"); + } + } +#endif + err = bind (listen_sd, (SA *) &sa_serv, sizeof (sa_serv)); + SOCKET_ERR (err, "bind"); + + printf ("UDP server ready. Listening to port '%d'.\n\n", PORT); + + for (;;) + { + printf("Waiting for connection...\n"); + sock = wait_for_connection(listen_sd); + if (sock < 0) + continue; + + cli_addr_size = sizeof(cli_addr); + ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size); + if (ret > 0) + { + memset(&prestate, 0, sizeof(prestate)); + ret = gnutls_dtls_cookie_verify(&cookie_key, &cli_addr, sizeof(cli_addr), buffer, ret, &prestate); + if (ret < 0) /* cookie not valid */ + { + priv_data_st s; + + memset(&s, 0, sizeof(s)); + s.fd = sock; + s.cli_addr = (void*)&cli_addr; + s.cli_addr_size = sizeof(cli_addr); + + printf("Sending hello verify request to %s\n", human_addr ((struct sockaddr *) + &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); + gnutls_dtls_cookie_send(&cookie_key, &cli_addr, sizeof(cli_addr), &prestate, (gnutls_transport_ptr_t)&s, push_func); + + /* discard peeked data*/ + recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&cli_addr, &cli_addr_size); + usleep(100); + continue; + } + printf ("Accepted connection from %s\n", + human_addr ((struct sockaddr *) + &cli_addr, sizeof(cli_addr), buffer, + sizeof (buffer))); + } + else + continue; + + session = initialize_tls_session (); + gnutls_dtls_prestate_set(session, &prestate); + gnutls_dtls_set_mtu(session, mtu); + + priv.session = session; + priv.fd = sock; + priv.cli_addr = (struct sockaddr *)&cli_addr; + priv.cli_addr_size = sizeof(cli_addr); + + gnutls_transport_set_ptr (session, &priv); + gnutls_transport_set_push_function (session, push_func); + gnutls_transport_set_pull_function (session, pull_func); + gnutls_transport_set_pull_timeout_function (session, pull_timeout_func); + + do + { + ret = gnutls_handshake(session); + } + while(gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) + { + fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret)); + gnutls_deinit(session); + continue; + } + + printf ("- Handshake was completed\n"); + + for(;;) + { + do { + ret = gnutls_record_recv_seq(session, buffer, MAX_BUFFER, sequence); + } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + if (ret < 0) + { + fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret)); + break; + } + if (ret == 0) + { + printf("EOF\n\n"); + break; + } + buffer[ret] = 0; + printf("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence[0], + sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], + sequence[6], sequence[7], buffer); + + /* reply back */ + ret = gnutls_record_send(session, buffer, ret); + if (ret < 0) + { + fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret)); + break; + } + } + + gnutls_bye (session, GNUTLS_SHUT_WR); + gnutls_deinit (session); + + } + close (listen_sd); + + gnutls_certificate_free_credentials (x509_cred); + gnutls_priority_deinit (priority_cache); + + gnutls_global_deinit (); + + return 0; + +} + +static int wait_for_connection(int fd) +{ + fd_set rd, wr; + int n; + + FD_ZERO (&rd); + FD_ZERO (&wr); + + FD_SET (fd, &rd); + + /* waiting part */ + n = select (fd + 1, &rd, &wr, NULL, NULL); + if (n == -1 && errno == EINTR) + return -1; + if (n < 0) + { + perror ("select()"); + exit (1); + } + + return fd; +} + +/* Wait for data to be received within a timeout period in milliseconds + */ +static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms) +{ +fd_set rfds; +struct timeval tv; +priv_data_st *priv = ptr; +struct sockaddr_in cli_addr; +socklen_t cli_addr_size; +int ret; +char c; + + FD_ZERO(&rfds); + FD_SET(priv->fd, &rfds); + + tv.tv_sec = 0; + tv.tv_usec = ms * 1000; + + ret = select(priv->fd+1, &rfds, NULL, NULL, &tv); + + if (ret <= 0) + return ret; + + /* only report ok if the next message is from the peer we expect + * from + */ + cli_addr_size = sizeof(cli_addr); + ret = recvfrom(priv->fd, &c, 1, MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size); + if (ret > 0) + { + if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr))==0) + return 1; + } + + return 0; +} + +static ssize_t push_func (gnutls_transport_ptr_t p, const void * data, size_t size) +{ +priv_data_st *priv = p; + + return sendto(priv->fd, data, size, 0, priv->cli_addr, priv->cli_addr_size); +} + +static ssize_t pull_func(gnutls_transport_ptr_t p, void * data, size_t size) +{ +priv_data_st *priv = p; +struct sockaddr_in cli_addr; +socklen_t cli_addr_size; +char buffer[64]; +int ret; + + cli_addr_size = sizeof(cli_addr); + ret = recvfrom(priv->fd, data, size, 0, (struct sockaddr*)&cli_addr, &cli_addr_size); + if (ret == -1) + return ret; + + if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr))==0) + return ret; + + printf ("Denied connection from %s\n", + human_addr ((struct sockaddr *) + &cli_addr, sizeof(cli_addr), buffer, + sizeof (buffer))); + + gnutls_transport_set_errno(priv->session, EAGAIN); + return -1; +} + +static const char * +human_addr (const struct sockaddr *sa, socklen_t salen, + char *buf, size_t buflen) +{ + const char *save_buf = buf; + size_t l; + + if (!buf || !buflen) + return NULL; + + *buf = '\0'; + + switch (sa->sa_family) + { +#if HAVE_IPV6 + case AF_INET6: + snprintf (buf, buflen, "IPv6 "); + break; +#endif + + case AF_INET: + snprintf (buf, buflen, "IPv4 "); + break; + } + + l = strlen (buf); + buf += l; + buflen -= l; + + if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0) + return NULL; + + l = strlen (buf); + buf += l; + buflen -= l; + + strncat (buf, " port ", buflen); + + l = strlen (buf); + buf += l; + buflen -= l; + + if (getnameinfo (sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0) + return NULL; + + return save_buf; +} + +static gnutls_session_t +initialize_tls_session (void) +{ + gnutls_session_t session; + + gnutls_init (&session, GNUTLS_SERVER|GNUTLS_DATAGRAM); + + gnutls_priority_set (session, priority_cache); + + gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + return session; +} + +static int generate_dh_params (void) +{ + int bits = gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LOW); + + /* Generate Diffie-Hellman parameters - for use with DHE + * kx algorithms. When short bit length is used, it might + * be wise to regenerate parameters often. + */ + gnutls_dh_params_init (&dh_params); + gnutls_dh_params_generate2 (dh_params, bits); + + return 0; +} diff --git a/doc/examples/ex-serv1.c b/doc/examples/ex-serv1.c index 7166657e9d..97eba2f729 100644 --- a/doc/examples/ex-serv1.c +++ b/doc/examples/ex-serv1.c @@ -28,7 +28,6 @@ #define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);} #define MAX_BUF 1024 #define PORT 5556 /* listen to 5556 port */ -#define DH_BITS 1024 /* These are global */ gnutls_certificate_credentials_t x509_cred; @@ -49,11 +48,6 @@ initialize_tls_session (void) */ gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST); - /* Set maximum compatibility mode. This is only suggested on public webservers - * that need to trade security for compatibility - */ - gnutls_session_enable_compatibility_mode (session); - return session; } @@ -62,16 +56,14 @@ static gnutls_dh_params_t dh_params; static int generate_dh_params (void) { + int bits = gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LOW); /* Generate Diffie-Hellman parameters - for use with DHE * kx algorithms. When short bit length is used, it might - * be wise to regenerate parameters. - * - * Check the ex-serv-export.c example for using static - * parameters. + * be wise to regenerate parameters often. */ gnutls_dh_params_init (&dh_params); - gnutls_dh_params_generate2 (dh_params, DH_BITS); + gnutls_dh_params_generate2 (dh_params, bits); return 0; } @@ -105,7 +97,7 @@ main (void) generate_dh_params (); - gnutls_priority_init (&priority_cache, "NORMAL", NULL); + gnutls_priority_init (&priority_cache, "PERFORMANCE:%SERVER_PRECEDENCE", NULL); gnutls_certificate_set_dh_params (x509_cred, dh_params); |