1 /* This example code is placed in the public domain. */
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <arpa/inet.h>
13 #include <netinet/in.h>
14 #include <sys/select.h>
18 #include <gnutls/gnutls.h>
19 #include <gnutls/dtls.h>
21 #define KEYFILE "key.pem"
22 #define CERTFILE "cert.pem"
23 #define CAFILE "/etc/ssl/certs/ca-certificates.crt"
24 #define CRLFILE "crl.pem"
26 /* This is a sample DTLS echo server, using X.509 authentication.
27 * Note that error checking is minimal to simplify the example.
30 #define MAX_BUFFER 1024
35 gnutls_session_t session
;
37 struct sockaddr
*cli_addr
;
38 socklen_t cli_addr_size
;
41 static int pull_timeout_func (gnutls_transport_ptr_t ptr
, unsigned int ms
);
42 static ssize_t
push_func (gnutls_transport_ptr_t p
, const void *data
,
44 static ssize_t
pull_func (gnutls_transport_ptr_t p
, void *data
, size_t size
);
45 static const char *human_addr (const struct sockaddr
*sa
, socklen_t salen
,
46 char *buf
, size_t buflen
);
47 static int wait_for_connection (int fd
);
48 static gnutls_session_t
initialize_tls_session (void);
49 static int generate_dh_params (void);
51 /* Use global credentials and parameters to simplify
53 static gnutls_certificate_credentials_t x509_cred
;
54 static gnutls_priority_t priority_cache
;
55 static gnutls_dh_params_t dh_params
;
62 struct sockaddr_in sa_serv
;
63 struct sockaddr_in cli_addr
;
64 socklen_t cli_addr_size
;
65 gnutls_session_t session
;
66 char buffer
[MAX_BUFFER
];
68 gnutls_datum_t cookie_key
;
69 gnutls_dtls_prestate_st prestate
;
71 unsigned char sequence
[8];
73 /* this must be called once in the program
75 gnutls_global_init ();
77 gnutls_certificate_allocate_credentials (&x509_cred
);
78 gnutls_certificate_set_x509_trust_file (x509_cred
, CAFILE
,
81 gnutls_certificate_set_x509_crl_file (x509_cred
, CRLFILE
,
84 ret
= gnutls_certificate_set_x509_key_file (x509_cred
, CERTFILE
, KEYFILE
,
88 printf("No certificate or key were found\n");
92 generate_dh_params ();
94 gnutls_certificate_set_dh_params (x509_cred
, dh_params
);
96 gnutls_priority_init (&priority_cache
,
97 "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE",
100 gnutls_key_generate (&cookie_key
, GNUTLS_COOKIE_KEY_SIZE
);
104 listen_sd
= socket (AF_INET
, SOCK_DGRAM
, 0);
106 memset (&sa_serv
, '\0', sizeof (sa_serv
));
107 sa_serv
.sin_family
= AF_INET
;
108 sa_serv
.sin_addr
.s_addr
= INADDR_ANY
;
109 sa_serv
.sin_port
= htons (PORT
);
111 { /* DTLS requires the IP don't fragment (DF) bit to be set */
112 #if defined(IP_DONTFRAG)
114 setsockopt (listen_sd
, IPPROTO_IP
, IP_DONTFRAG
,
115 (const void *) &optval
, sizeof (optval
));
116 #elif defined(IP_MTU_DISCOVER)
117 int optval
= IP_PMTUDISC_DO
;
118 setsockopt(listen_sd
, IPPROTO_IP
, IP_MTU_DISCOVER
,
119 (const void*) &optval
, sizeof (optval
));
123 bind (listen_sd
, (struct sockaddr
*) &sa_serv
, sizeof (sa_serv
));
125 printf ("UDP server ready. Listening to port '%d'.\n\n", PORT
);
129 printf ("Waiting for connection...\n");
130 sock
= wait_for_connection (listen_sd
);
134 cli_addr_size
= sizeof (cli_addr
);
135 ret
= recvfrom (sock
, buffer
, sizeof (buffer
), MSG_PEEK
,
136 (struct sockaddr
*) &cli_addr
, &cli_addr_size
);
139 memset (&prestate
, 0, sizeof (prestate
));
140 ret
= gnutls_dtls_cookie_verify (&cookie_key
, &cli_addr
,
141 sizeof (cli_addr
), buffer
, ret
,
143 if (ret
< 0) /* cookie not valid */
147 memset (&s
, 0, sizeof (s
));
149 s
.cli_addr
= (void *) &cli_addr
;
150 s
.cli_addr_size
= sizeof (cli_addr
);
152 printf ("Sending hello verify request to %s\n",
153 human_addr ((struct sockaddr
*) &cli_addr
,
154 sizeof (cli_addr
), buffer
,
157 gnutls_dtls_cookie_send (&cookie_key
, &cli_addr
,
158 sizeof (cli_addr
), &prestate
,
159 (gnutls_transport_ptr_t
) & s
,
162 /* discard peeked data */
163 recvfrom (sock
, buffer
, sizeof (buffer
), 0,
164 (struct sockaddr
*) &cli_addr
, &cli_addr_size
);
168 printf ("Accepted connection from %s\n",
169 human_addr ((struct sockaddr
*)
170 &cli_addr
, sizeof (cli_addr
), buffer
,
176 session
= initialize_tls_session ();
177 gnutls_dtls_prestate_set (session
, &prestate
);
178 gnutls_dtls_set_mtu (session
, mtu
);
180 priv
.session
= session
;
182 priv
.cli_addr
= (struct sockaddr
*) &cli_addr
;
183 priv
.cli_addr_size
= sizeof (cli_addr
);
185 gnutls_transport_set_ptr (session
, &priv
);
186 gnutls_transport_set_push_function (session
, push_func
);
187 gnutls_transport_set_pull_function (session
, pull_func
);
188 gnutls_transport_set_pull_timeout_function (session
, pull_timeout_func
);
192 ret
= gnutls_handshake (session
);
194 while (ret
< 0 && gnutls_error_is_fatal (ret
) == 0);
198 fprintf (stderr
, "Error in handshake(): %s\n",
199 gnutls_strerror (ret
));
200 gnutls_deinit (session
);
204 printf ("- Handshake was completed\n");
210 ret
= gnutls_record_recv_seq (session
, buffer
, MAX_BUFFER
,
213 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
217 fprintf (stderr
, "Error in recv(): %s\n",
218 gnutls_strerror (ret
));
227 printf ("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n",
228 sequence
[0], sequence
[1], sequence
[2], sequence
[3],
229 sequence
[4], sequence
[5], sequence
[6], sequence
[7], buffer
);
232 ret
= gnutls_record_send (session
, buffer
, ret
);
235 fprintf (stderr
, "Error in send(): %s\n",
236 gnutls_strerror (ret
));
241 gnutls_bye (session
, GNUTLS_SHUT_WR
);
242 gnutls_deinit (session
);
247 gnutls_certificate_free_credentials (x509_cred
);
248 gnutls_priority_deinit (priority_cache
);
250 gnutls_global_deinit ();
257 wait_for_connection (int fd
)
268 n
= select (fd
+ 1, &rd
, &wr
, NULL
, NULL
);
269 if (n
== -1 && errno
== EINTR
)
280 /* Wait for data to be received within a timeout period in milliseconds
283 pull_timeout_func (gnutls_transport_ptr_t ptr
, unsigned int ms
)
287 priv_data_st
*priv
= ptr
;
288 struct sockaddr_in cli_addr
;
289 socklen_t cli_addr_size
;
294 FD_SET (priv
->fd
, &rfds
);
297 tv
.tv_usec
= ms
* 1000;
299 while(tv
.tv_usec
>= 1000000)
301 tv
.tv_usec
-= 1000000;
305 ret
= select (priv
->fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
310 /* only report ok if the next message is from the peer we expect
313 cli_addr_size
= sizeof (cli_addr
);
315 recvfrom (priv
->fd
, &c
, 1, MSG_PEEK
, (struct sockaddr
*) &cli_addr
,
319 if (cli_addr_size
== priv
->cli_addr_size
320 && memcmp (&cli_addr
, priv
->cli_addr
, sizeof (cli_addr
)) == 0)
328 push_func (gnutls_transport_ptr_t p
, const void *data
, size_t size
)
330 priv_data_st
*priv
= p
;
332 return sendto (priv
->fd
, data
, size
, 0, priv
->cli_addr
,
333 priv
->cli_addr_size
);
337 pull_func (gnutls_transport_ptr_t p
, void *data
, size_t size
)
339 priv_data_st
*priv
= p
;
340 struct sockaddr_in cli_addr
;
341 socklen_t cli_addr_size
;
345 cli_addr_size
= sizeof (cli_addr
);
347 recvfrom (priv
->fd
, data
, size
, 0, (struct sockaddr
*) &cli_addr
,
352 if (cli_addr_size
== priv
->cli_addr_size
353 && memcmp (&cli_addr
, priv
->cli_addr
, sizeof (cli_addr
)) == 0)
356 printf ("Denied connection from %s\n",
357 human_addr ((struct sockaddr
*)
358 &cli_addr
, sizeof (cli_addr
), buffer
, sizeof (buffer
)));
360 gnutls_transport_set_errno (priv
->session
, EAGAIN
);
365 human_addr (const struct sockaddr
*sa
, socklen_t salen
,
366 char *buf
, size_t buflen
)
368 const char *save_buf
= buf
;
376 switch (sa
->sa_family
)
380 snprintf (buf
, buflen
, "IPv6 ");
385 snprintf (buf
, buflen
, "IPv4 ");
393 if (getnameinfo (sa
, salen
, buf
, buflen
, NULL
, 0, NI_NUMERICHOST
) != 0)
400 strncat (buf
, " port ", buflen
);
406 if (getnameinfo (sa
, salen
, NULL
, 0, buf
, buflen
, NI_NUMERICSERV
) != 0)
412 static gnutls_session_t
413 initialize_tls_session (void)
415 gnutls_session_t session
;
417 gnutls_init (&session
, GNUTLS_SERVER
| GNUTLS_DATAGRAM
);
419 gnutls_priority_set (session
, priority_cache
);
421 gnutls_credentials_set (session
, GNUTLS_CRD_CERTIFICATE
, x509_cred
);
427 generate_dh_params (void)
429 int bits
= gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH
, GNUTLS_SEC_PARAM_LOW
);
431 /* Generate Diffie-Hellman parameters - for use with DHE
432 * kx algorithms. When short bit length is used, it might
433 * be wise to regenerate parameters often.
435 gnutls_dh_params_init (&dh_params
);
436 gnutls_dh_params_generate2 (dh_params
, bits
);