1 /*
2 * Copyright (C) 2015 Red Hat, Inc.
3 *
4 * Author: Nikos Mavrogiannopoulos
5 *
6 * This file is part of GnuTLS.
7 *
8 * GnuTLS is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * GnuTLS is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GnuTLS; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #if defined(_WIN32)
31
main()32 int main()
33 {
34 exit(77);
35 }
36
37 #else
38
39 #include <string.h>
40 #include <sys/types.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #include <sys/wait.h>
44 #include <arpa/inet.h>
45 #include <unistd.h>
46 #include <gnutls/gnutls.h>
47 #include <gnutls/dtls.h>
48 #include <signal.h>
49 #include <assert.h>
50
51 #include "utils.h"
52 #include "cert-common.h"
53
54 static void terminate(void);
55
56 /* This program tests whether EtM is negotiated as expected.
57 */
58
server_log_func(int level,const char * str)59 static void server_log_func(int level, const char *str)
60 {
61 fprintf(stderr, "server|<%d>| %s", level, str);
62 }
63
client_log_func(int level,const char * str)64 static void client_log_func(int level, const char *str)
65 {
66 fprintf(stderr, "client|<%d>| %s", level, str);
67 }
68
69 /* A very basic TLS client, with anonymous authentication.
70 */
71
72 #define MAX_BUF 1024
73
client(int fd,const char * prio,unsigned etm)74 static void client(int fd, const char *prio, unsigned etm)
75 {
76 int ret;
77 char buffer[MAX_BUF + 1];
78 gnutls_anon_client_credentials_t anoncred;
79 gnutls_certificate_credentials_t x509_cred;
80 gnutls_session_t session;
81 /* Need to enable anonymous KX specifically. */
82
83 global_init();
84
85 if (debug) {
86 gnutls_global_set_log_function(client_log_func);
87 gnutls_global_set_log_level(7);
88 }
89
90 gnutls_anon_allocate_client_credentials(&anoncred);
91 gnutls_certificate_allocate_credentials(&x509_cred);
92
93 /* Initialize TLS session
94 */
95 gnutls_init(&session, GNUTLS_CLIENT|GNUTLS_DATAGRAM);
96
97 /* Use default priorities */
98 assert(gnutls_priority_set_direct(session, prio, NULL)>=0);
99
100 /* put the anonymous credentials to the current session
101 */
102 gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
103 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
104
105 gnutls_transport_set_int(session, fd);
106
107 /* Perform the TLS handshake
108 */
109 do {
110 ret = gnutls_handshake(session);
111 }
112 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
113
114 if (ret < 0) {
115 fail("client: Handshake failed\n");
116 gnutls_perror(ret);
117 exit(1);
118 } else {
119 if (debug)
120 success("client: Handshake was completed\n");
121 }
122
123 if (debug)
124 success("client: TLS version is: %s\n",
125 gnutls_protocol_get_name
126 (gnutls_protocol_get_version(session)));
127
128 if (etm != 0 && gnutls_session_etm_status(session) == 0) {
129 fail("client: EtM was not negotiated with %s!\n", prio);
130 exit(1);
131 } else if (etm == 0 && gnutls_session_etm_status(session) != 0) {
132 fail("client: EtM was negotiated with %s!\n", prio);
133 exit(1);
134 }
135
136 if (etm != 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) == 0)) {
137 fail("client: EtM was not negotiated with %s!\n", prio);
138 exit(1);
139 } else if (etm == 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) != 0)) {
140 fail("client: EtM was negotiated with %s!\n", prio);
141 exit(1);
142 }
143
144 do {
145 do {
146 ret = gnutls_record_recv(session, buffer, MAX_BUF);
147 } while (ret == GNUTLS_E_AGAIN
148 || ret == GNUTLS_E_INTERRUPTED);
149 } while (ret > 0);
150
151 if (ret == 0) {
152 if (debug)
153 success
154 ("client: Peer has closed the TLS connection\n");
155 goto end;
156 } else if (ret < 0) {
157 if (ret != 0) {
158 fail("client: Error: %s\n", gnutls_strerror(ret));
159 exit(1);
160 }
161 }
162
163 gnutls_bye(session, GNUTLS_SHUT_WR);
164
165 end:
166
167 close(fd);
168
169 gnutls_deinit(session);
170
171 gnutls_anon_free_client_credentials(anoncred);
172 gnutls_certificate_free_credentials(x509_cred);
173
174 gnutls_global_deinit();
175 }
176
177
178 /* These are global */
179 pid_t child;
180
terminate(void)181 static void terminate(void)
182 {
183 kill(child, SIGTERM);
184 exit(1);
185 }
186
server(int fd,const char * prio,unsigned etm)187 static void server(int fd, const char *prio, unsigned etm)
188 {
189 int ret;
190 char buffer[MAX_BUF + 1];
191 gnutls_session_t session;
192 gnutls_anon_server_credentials_t anoncred;
193 gnutls_certificate_credentials_t x509_cred;
194 unsigned to_send = sizeof(buffer)/4;
195
196 /* this must be called once in the program
197 */
198 global_init();
199 memset(buffer, 0, sizeof(buffer));
200
201 if (debug) {
202 gnutls_global_set_log_function(server_log_func);
203 gnutls_global_set_log_level(4711);
204 }
205
206 gnutls_certificate_allocate_credentials(&x509_cred);
207 gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert,
208 &server_key,
209 GNUTLS_X509_FMT_PEM);
210
211 gnutls_anon_allocate_server_credentials(&anoncred);
212
213 gnutls_init(&session, GNUTLS_SERVER|GNUTLS_DATAGRAM);
214
215 /* avoid calling all the priority functions, since the defaults
216 * are adequate.
217 */
218 assert(gnutls_priority_set_direct(session, prio, NULL) >= 0);
219
220 gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
221 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
222
223 gnutls_transport_set_int(session, fd);
224
225 do {
226 ret = gnutls_handshake(session);
227 } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
228 if (ret < 0) {
229 close(fd);
230 gnutls_deinit(session);
231 fail("server: Handshake has failed (%s)\n\n",
232 gnutls_strerror(ret));
233 terminate();
234 }
235
236 if (etm != 0 && gnutls_session_etm_status(session) == 0) {
237 fail("server: EtM was not negotiated with %s!\n", prio);
238 exit(1);
239 } else if (etm == 0 && gnutls_session_etm_status(session) != 0) {
240 fail("server: EtM was negotiated with %s!\n", prio);
241 exit(1);
242 }
243
244 if (etm != 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) == 0)) {
245 fail("server: EtM was not negotiated with %s!\n", prio);
246 exit(1);
247 } else if (etm == 0 && ((gnutls_session_get_flags(session) & GNUTLS_SFLAGS_ETM) != 0)) {
248 fail("server: EtM was negotiated with %s!\n", prio);
249 exit(1);
250 }
251
252 if (debug)
253 success("server: Handshake was completed\n");
254
255 if (debug)
256 success("server: TLS version is: %s\n",
257 gnutls_protocol_get_name
258 (gnutls_protocol_get_version(session)));
259
260 do {
261 do {
262 ret =
263 gnutls_record_send(session, buffer,
264 sizeof(buffer));
265 } while (ret == GNUTLS_E_AGAIN
266 || ret == GNUTLS_E_INTERRUPTED);
267
268 if (ret < 0) {
269 fail("Error sending %d byte packet: %s\n", to_send,
270 gnutls_strerror(ret));
271 terminate();
272 }
273 to_send++;
274 }
275 while (to_send < 64);
276
277 to_send = -1;
278 /* do not wait for the peer to close the connection.
279 */
280 gnutls_bye(session, GNUTLS_SHUT_WR);
281
282 close(fd);
283 gnutls_deinit(session);
284
285 gnutls_anon_free_server_credentials(anoncred);
286 gnutls_certificate_free_credentials(x509_cred);
287
288 gnutls_global_deinit();
289
290 if (debug)
291 success("server: finished\n");
292 }
293
start(const char * prio,unsigned etm)294 static void start(const char *prio, unsigned etm)
295 {
296 int fd[2];
297 int ret;
298
299 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
300 if (ret < 0) {
301 perror("socketpair");
302 exit(1);
303 }
304
305 child = fork();
306 if (child < 0) {
307 perror("fork");
308 fail("fork");
309 exit(1);
310 }
311
312 if (child) {
313 /* parent */
314 close(fd[1]);
315 server(fd[0], prio, etm);
316 kill(child, SIGTERM);
317 } else {
318 close(fd[0]);
319 client(fd[1], prio, etm);
320 exit(0);
321 }
322 }
323
324 #define AES_CBC "NONE:+VERS-DTLS1.0:-CIPHER-ALL:+AES-128-CBC:+SHA1:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL"
325 #define AES_CBC_SHA256 "NONE:+VERS-DTLS1.2:-CIPHER-ALL:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA256:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL"
326 #define AES_GCM "NONE:+VERS-DTLS1.2:-CIPHER-ALL:+RSA:+AES-128-GCM:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL"
327
ch_handler(int sig)328 static void ch_handler(int sig)
329 {
330 int status;
331 wait(&status);
332 check_wait_status(status);
333 return;
334 }
335
doit(void)336 void doit(void)
337 {
338 signal(SIGCHLD, ch_handler);
339
340 start(AES_CBC, 1);
341 start(AES_CBC_SHA256, 1);
342 start(AES_GCM, 0);
343 }
344
345 #endif /* _WIN32 */
346