Added API for external hashing of ServerKeyExchange, and signature algorithm identifi...
[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 /*
71 * A single static slot for saving session parameters.
72 */
73 static br_ssl_session_parameters slot;
74 static int slot_used = 0;
75
76 size_t u;
77
78 if (len < 2 || len > 3) {
79 return 0;
80 }
81 if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
82 return 0;
83 }
84 if (len == 2 && buf[1] != '\n') {
85 return 0;
86 }
87 switch (buf[0]) {
88 case 'Q':
89 fprintf(stderr, "closing...\n");
90 br_ssl_engine_close(cc);
91 return 1;
92 case 'R':
93 if (br_ssl_engine_renegotiate(cc)) {
94 fprintf(stderr, "renegotiating...\n");
95 } else {
96 fprintf(stderr, "not renegotiating.\n");
97 }
98 return 1;
99 case 'F':
100 /*
101 * Session forget is nominally client-only. But the
102 * session parameters are in the engine structure, which
103 * is the first field of the client context, so the cast
104 * still works properly. On the server, this forgetting
105 * has no effect.
106 */
107 fprintf(stderr, "forgetting session...\n");
108 br_ssl_client_forget_session((br_ssl_client_context *)cc);
109 return 1;
110 case 'S':
111 fprintf(stderr, "saving session parameters...\n");
112 br_ssl_engine_get_session_parameters(cc, &slot);
113 fprintf(stderr, " id = ");
114 for (u = 0; u < slot.session_id_len; u ++) {
115 fprintf(stderr, "%02X", slot.session_id[u]);
116 }
117 fprintf(stderr, "\n");
118 slot_used = 1;
119 return 1;
120 case 'P':
121 if (slot_used) {
122 fprintf(stderr, "restoring session parameters...\n");
123 fprintf(stderr, " id = ");
124 for (u = 0; u < slot.session_id_len; u ++) {
125 fprintf(stderr, "%02X", slot.session_id[u]);
126 }
127 fprintf(stderr, "\n");
128 br_ssl_engine_set_session_parameters(cc, &slot);
129 return 1;
130 }
131 return 0;
132 default:
133 return 0;
134 }
135 }
136
137 /* see brssl.h */
138 int
139 run_ssl_engine(br_ssl_engine_context *cc, int fd, unsigned flags)
140 {
141 int hsdetails;
142 int retcode;
143 int verbose;
144 int trace;
145
146 hsdetails = 0;
147 retcode = 0;
148 verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
149 trace = (flags & RUN_ENGINE_TRACE) != 0;
150
151 /*
152 * Make sure that stdin and stdout are non-blocking.
153 */
154 fcntl(0, F_SETFL, O_NONBLOCK);
155 fcntl(1, F_SETFL, O_NONBLOCK);
156
157 /*
158 * Perform the loop.
159 */
160 for (;;) {
161 unsigned st;
162 int sendrec, recvrec, sendapp, recvapp;
163 struct pollfd pfd[3];
164 int n;
165 size_t u, k_fd, k_in, k_out;
166
167 /*
168 * Get current engine state.
169 */
170 st = br_ssl_engine_current_state(cc);
171 if (st == BR_SSL_CLOSED) {
172 int err;
173
174 err = br_ssl_engine_last_error(cc);
175 if (err == BR_ERR_OK) {
176 if (verbose) {
177 fprintf(stderr,
178 "SSL closed normally\n");
179 }
180 retcode = 0;
181 goto engine_exit;
182 } else {
183 fprintf(stderr, "ERROR: SSL error %d", err);
184 retcode = err;
185 if (err >= BR_ERR_SEND_FATAL_ALERT) {
186 err -= BR_ERR_SEND_FATAL_ALERT;
187 fprintf(stderr,
188 " (sent alert %d)\n", err);
189 } else if (err >= BR_ERR_RECV_FATAL_ALERT) {
190 err -= BR_ERR_RECV_FATAL_ALERT;
191 fprintf(stderr,
192 " (received alert %d)\n", err);
193 } else {
194 const char *ename;
195
196 ename = find_error_name(err, NULL);
197 if (ename == NULL) {
198 ename = "unknown";
199 }
200 fprintf(stderr, " (%s)\n", ename);
201 }
202 goto engine_exit;
203 }
204 }
205
206 /*
207 * Compute descriptors that must be polled, depending
208 * on engine state.
209 */
210 sendrec = ((st & BR_SSL_SENDREC) != 0);
211 recvrec = ((st & BR_SSL_RECVREC) != 0);
212 sendapp = ((st & BR_SSL_SENDAPP) != 0);
213 recvapp = ((st & BR_SSL_RECVAPP) != 0);
214 if (verbose && sendapp && !hsdetails) {
215 char csn[80];
216 const char *pname;
217
218 fprintf(stderr, "Handshake completed\n");
219 fprintf(stderr, " version: ");
220 switch (cc->session.version) {
221 case BR_SSL30:
222 fprintf(stderr, "SSL 3.0");
223 break;
224 case BR_TLS10:
225 fprintf(stderr, "TLS 1.0");
226 break;
227 case BR_TLS11:
228 fprintf(stderr, "TLS 1.1");
229 break;
230 case BR_TLS12:
231 fprintf(stderr, "TLS 1.2");
232 break;
233 default:
234 fprintf(stderr, "unknown (0x%04X)",
235 (unsigned)cc->session.version);
236 break;
237 }
238 fprintf(stderr, "\n");
239 get_suite_name_ext(
240 cc->session.cipher_suite, csn, sizeof csn);
241 fprintf(stderr, " cipher suite: %s\n", csn);
242 fprintf(stderr, " secure renegotiation: %s\n",
243 cc->reneg == 1 ? "no" : "yes");
244 pname = br_ssl_engine_get_selected_protocol(cc);
245 if (pname != NULL) {
246 fprintf(stderr,
247 " protocol name (ALPN): %s\n",
248 pname);
249 }
250 hsdetails = 1;
251 }
252
253 k_fd = 0;
254 k_in = 0;
255 k_out = 0;
256
257 u = 0;
258 if (sendrec || recvrec) {
259 pfd[u].fd = fd;
260 pfd[u].revents = 0;
261 pfd[u].events = 0;
262 if (sendrec) {
263 pfd[u].events |= POLLOUT;
264 }
265 if (recvrec) {
266 pfd[u].events |= POLLIN;
267 }
268 k_fd = u;
269 u ++;
270 }
271 if (sendapp) {
272 pfd[u].fd = 0;
273 pfd[u].revents = 0;
274 pfd[u].events = POLLIN;
275 k_in = u;
276 u ++;
277 }
278 if (recvapp) {
279 pfd[u].fd = 1;
280 pfd[u].revents = 0;
281 pfd[u].events = POLLOUT;
282 k_out = u;
283 u ++;
284 }
285 n = poll(pfd, u, -1);
286 if (n < 0) {
287 if (errno == EINTR) {
288 continue;
289 }
290 perror("ERROR: poll()");
291 retcode = -2;
292 goto engine_exit;
293 }
294 if (n == 0) {
295 continue;
296 }
297
298 /*
299 * We transform closures/errors into read+write accesses
300 * so as to force the read() or write() call that will
301 * detect the situation.
302 */
303 while (u -- > 0) {
304 if (pfd[u].revents & (POLLERR | POLLHUP)) {
305 pfd[u].revents |= POLLIN | POLLOUT;
306 }
307 }
308
309 /*
310 * We give preference to outgoing data, on stdout and on
311 * the socket.
312 */
313 if (recvapp) {
314 if (pfd[k_out].revents & POLLOUT) {
315 unsigned char *buf;
316 size_t len;
317 ssize_t wlen;
318
319 buf = br_ssl_engine_recvapp_buf(cc, &len);
320 wlen = write(1, buf, len);
321 if (wlen <= 0) {
322 if (verbose) {
323 fprintf(stderr,
324 "stdout closed...\n");
325 }
326 retcode = -2;
327 goto engine_exit;
328 }
329 br_ssl_engine_recvapp_ack(cc, wlen);
330 continue;
331 }
332 }
333 if (sendrec) {
334 if (pfd[k_fd].revents & POLLOUT) {
335 unsigned char *buf;
336 size_t len;
337 ssize_t wlen;
338
339 buf = br_ssl_engine_sendrec_buf(cc, &len);
340 wlen = write(fd, buf, len);
341 if (wlen <= 0) {
342 if (verbose) {
343 fprintf(stderr,
344 "socket closed...\n");
345 }
346 retcode = -1;
347 goto engine_exit;
348 }
349 if (trace) {
350 dump_blob("Outgoing bytes", buf, wlen);
351 }
352 br_ssl_engine_sendrec_ack(cc, wlen);
353 continue;
354 }
355 }
356 if (recvrec) {
357 if (pfd[k_fd].revents & POLLIN) {
358 unsigned char *buf;
359 size_t len;
360 ssize_t rlen;
361
362 buf = br_ssl_engine_recvrec_buf(cc, &len);
363 rlen = read(fd, buf, len);
364 if (rlen <= 0) {
365 if (verbose) {
366 fprintf(stderr,
367 "socket closed...\n");
368 }
369 retcode = -1;
370 goto engine_exit;
371 }
372 if (trace) {
373 dump_blob("Incoming bytes", buf, rlen);
374 }
375 br_ssl_engine_recvrec_ack(cc, rlen);
376 continue;
377 }
378 }
379 if (sendapp) {
380 if (pfd[k_in].revents & POLLIN) {
381 unsigned char *buf;
382 size_t len;
383 ssize_t rlen;
384
385 buf = br_ssl_engine_sendapp_buf(cc, &len);
386 rlen = read(0, buf, len);
387 if (rlen <= 0) {
388 if (verbose) {
389 fprintf(stderr,
390 "stdin closed...\n");
391 }
392 br_ssl_engine_close(cc);
393 } else if (!run_command(cc, buf, rlen)) {
394 br_ssl_engine_sendapp_ack(cc, rlen);
395 }
396 br_ssl_engine_flush(cc, 0);
397 continue;
398 }
399 }
400
401 /* We should never reach that point. */
402 fprintf(stderr, "ERROR: poll() misbehaves\n");
403 retcode = -2;
404 goto engine_exit;
405 }
406
407 /*
408 * Release allocated structures.
409 */
410 engine_exit:
411 return retcode;
412 }