Added flag to prohibit renegotiations.
[BearSSL] / tools / sslio.c
1 /*
2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <errno.h>
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <poll.h>
39
40 #include "brssl.h"
41 #include "bearssl.h"
42
43 static void
44 dump_blob(const char *name, const void *data, size_t len)
45 {
46 const unsigned char *buf;
47 size_t u;
48
49 buf = data;
50 fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
51 for (u = 0; u < len; u ++) {
52 if ((u & 15) == 0) {
53 fprintf(stderr, "\n%08lX ", (unsigned long)u);
54 } else if ((u & 7) == 0) {
55 fprintf(stderr, " ");
56 }
57 fprintf(stderr, " %02x", buf[u]);
58 }
59 fprintf(stderr, "\n");
60 }
61
62 /*
63 * Inspect the provided data in case it is a "command" to trigger a
64 * special behaviour. If the command is recognised, then it is executed
65 * and this function returns 1. Otherwise, this function returns 0.
66 */
67 static int
68 run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len)
69 {
70 if (len < 2 || len > 3) {
71 return 0;
72 }
73 if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
74 return 0;
75 }
76 if (len == 2 && buf[1] != '\n') {
77 return 0;
78 }
79 switch (buf[0]) {
80 case 'Q':
81 fprintf(stderr, "closing...\n");
82 br_ssl_engine_close(cc);
83 return 1;
84 case 'R':
85 if (br_ssl_engine_renegotiate(cc)) {
86 fprintf(stderr, "renegotiating...\n");
87 } else {
88 fprintf(stderr, "not renegotiating.\n");
89 }
90 return 1;
91 case 'F':
92 /*
93 * Session forget is nominally client-only. But the
94 * session parameters are in the engine structure, which
95 * is the first field of the client context, so the cast
96 * still works properly. On the server, this forgetting
97 * has no effect.
98 */
99 fprintf(stderr, "forgetting session...\n");
100 br_ssl_client_forget_session((br_ssl_client_context *)cc);
101 return 1;
102 default:
103 return 0;
104 }
105 }
106
107 /* see brssl.h */
108 int
109 run_ssl_engine(br_ssl_engine_context *cc, int fd, unsigned flags)
110 {
111 int hsdetails;
112 int retcode;
113 int verbose;
114 int trace;
115
116 hsdetails = 0;
117 retcode = 0;
118 verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
119 trace = (flags & RUN_ENGINE_TRACE) != 0;
120
121 /*
122 * Make sure that stdin and stdout are non-blocking.
123 */
124 fcntl(0, F_SETFL, O_NONBLOCK);
125 fcntl(1, F_SETFL, O_NONBLOCK);
126
127 /*
128 * Perform the loop.
129 */
130 for (;;) {
131 unsigned st;
132 int sendrec, recvrec, sendapp, recvapp;
133 struct pollfd pfd[3];
134 int n;
135 size_t u, k_fd, k_in, k_out;
136
137 /*
138 * Get current engine state.
139 */
140 st = br_ssl_engine_current_state(cc);
141 if (st == BR_SSL_CLOSED) {
142 int err;
143
144 err = br_ssl_engine_last_error(cc);
145 if (err == BR_ERR_OK) {
146 if (verbose) {
147 fprintf(stderr,
148 "SSL closed normally\n");
149 }
150 retcode = 0;
151 goto engine_exit;
152 } else {
153 fprintf(stderr, "ERROR: SSL error %d", err);
154 retcode = err;
155 if (err >= BR_ERR_SEND_FATAL_ALERT) {
156 err -= BR_ERR_SEND_FATAL_ALERT;
157 fprintf(stderr,
158 " (sent alert %d)\n", err);
159 } else if (err >= BR_ERR_RECV_FATAL_ALERT) {
160 err -= BR_ERR_RECV_FATAL_ALERT;
161 fprintf(stderr,
162 " (received alert %d)\n", err);
163 } else {
164 const char *ename;
165
166 ename = find_error_name(err, NULL);
167 if (ename == NULL) {
168 ename = "unknown";
169 }
170 fprintf(stderr, " (%s)\n", ename);
171 }
172 goto engine_exit;
173 }
174 }
175
176 /*
177 * Compute descriptors that must be polled, depending
178 * on engine state.
179 */
180 sendrec = ((st & BR_SSL_SENDREC) != 0);
181 recvrec = ((st & BR_SSL_RECVREC) != 0);
182 sendapp = ((st & BR_SSL_SENDAPP) != 0);
183 recvapp = ((st & BR_SSL_RECVAPP) != 0);
184 if (verbose && sendapp && !hsdetails) {
185 char csn[80];
186
187 fprintf(stderr, "Handshake completed\n");
188 fprintf(stderr, " version: ");
189 switch (cc->session.version) {
190 case BR_SSL30:
191 fprintf(stderr, "SSL 3.0");
192 break;
193 case BR_TLS10:
194 fprintf(stderr, "TLS 1.0");
195 break;
196 case BR_TLS11:
197 fprintf(stderr, "TLS 1.1");
198 break;
199 case BR_TLS12:
200 fprintf(stderr, "TLS 1.2");
201 break;
202 default:
203 fprintf(stderr, "unknown (0x%04X)",
204 (unsigned)cc->session.version);
205 break;
206 }
207 fprintf(stderr, "\n");
208 get_suite_name_ext(
209 cc->session.cipher_suite, csn, sizeof csn);
210 fprintf(stderr, " cipher suite: %s\n", csn);
211 fprintf(stderr, " secure renegotiation: %s\n",
212 cc->reneg == 1 ? "no" : "yes");
213 hsdetails = 1;
214 }
215
216 k_fd = 0;
217 k_in = 0;
218 k_out = 0;
219
220 u = 0;
221 if (sendrec || recvrec) {
222 pfd[u].fd = fd;
223 pfd[u].revents = 0;
224 pfd[u].events = 0;
225 if (sendrec) {
226 pfd[u].events |= POLLOUT;
227 }
228 if (recvrec) {
229 pfd[u].events |= POLLIN;
230 }
231 k_fd = u;
232 u ++;
233 }
234 if (sendapp) {
235 pfd[u].fd = 0;
236 pfd[u].revents = 0;
237 pfd[u].events = POLLIN;
238 k_in = u;
239 u ++;
240 }
241 if (recvapp) {
242 pfd[u].fd = 1;
243 pfd[u].revents = 0;
244 pfd[u].events = POLLOUT;
245 k_out = u;
246 u ++;
247 }
248 n = poll(pfd, u, -1);
249 if (n < 0) {
250 if (errno == EINTR) {
251 continue;
252 }
253 perror("ERROR: poll()");
254 retcode = -2;
255 goto engine_exit;
256 }
257 if (n == 0) {
258 continue;
259 }
260
261 /*
262 * We transform closures/errors into read+write accesses
263 * so as to force the read() or write() call that will
264 * detect the situation.
265 */
266 while (u -- > 0) {
267 if (pfd[u].revents & (POLLERR | POLLHUP)) {
268 pfd[u].revents |= POLLIN | POLLOUT;
269 }
270 }
271
272 /*
273 * We give preference to outgoing data, on stdout and on
274 * the socket.
275 */
276 if (recvapp) {
277 if (pfd[k_out].revents & POLLOUT) {
278 unsigned char *buf;
279 size_t len;
280 ssize_t wlen;
281
282 buf = br_ssl_engine_recvapp_buf(cc, &len);
283 wlen = write(1, buf, len);
284 if (wlen <= 0) {
285 if (verbose) {
286 fprintf(stderr,
287 "stdout closed...\n");
288 }
289 retcode = -2;
290 goto engine_exit;
291 }
292 br_ssl_engine_recvapp_ack(cc, wlen);
293 continue;
294 }
295 }
296 if (sendrec) {
297 if (pfd[k_fd].revents & POLLOUT) {
298 unsigned char *buf;
299 size_t len;
300 ssize_t wlen;
301
302 buf = br_ssl_engine_sendrec_buf(cc, &len);
303 wlen = write(fd, buf, len);
304 if (wlen <= 0) {
305 if (verbose) {
306 fprintf(stderr,
307 "socket closed...\n");
308 }
309 retcode = -1;
310 goto engine_exit;
311 }
312 if (trace) {
313 dump_blob("Outgoing bytes", buf, wlen);
314 }
315 br_ssl_engine_sendrec_ack(cc, wlen);
316 continue;
317 }
318 }
319 if (recvrec) {
320 if (pfd[k_fd].revents & POLLIN) {
321 unsigned char *buf;
322 size_t len;
323 ssize_t rlen;
324
325 buf = br_ssl_engine_recvrec_buf(cc, &len);
326 rlen = read(fd, buf, len);
327 if (rlen <= 0) {
328 if (verbose) {
329 fprintf(stderr,
330 "socket closed...\n");
331 }
332 retcode = -1;
333 goto engine_exit;
334 }
335 if (trace) {
336 dump_blob("Incoming bytes", buf, rlen);
337 }
338 br_ssl_engine_recvrec_ack(cc, rlen);
339 continue;
340 }
341 }
342 if (sendapp) {
343 if (pfd[k_in].revents & POLLIN) {
344 unsigned char *buf;
345 size_t len;
346 ssize_t rlen;
347
348 buf = br_ssl_engine_sendapp_buf(cc, &len);
349 rlen = read(0, buf, len);
350 if (rlen <= 0) {
351 if (verbose) {
352 fprintf(stderr,
353 "stdin closed...\n");
354 }
355 br_ssl_engine_close(cc);
356 } else if (!run_command(cc, buf, rlen)) {
357 br_ssl_engine_sendapp_ack(cc, rlen);
358 }
359 br_ssl_engine_flush(cc, 0);
360 continue;
361 }
362 }
363
364 /* We should never reach that point. */
365 fprintf(stderr, "ERROR: poll() misbehaves\n");
366 retcode = -2;
367 goto engine_exit;
368 }
369
370 /*
371 * Release allocated structures.
372 */
373 engine_exit:
374 return retcode;
375 }