Some more Doxygen API documentation (X.509 processing).
[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
217 fprintf(stderr, "Handshake completed\n");
218 fprintf(stderr, " version: ");
219 switch (cc->session.version) {
220 case BR_SSL30:
221 fprintf(stderr, "SSL 3.0");
222 break;
223 case BR_TLS10:
224 fprintf(stderr, "TLS 1.0");
225 break;
226 case BR_TLS11:
227 fprintf(stderr, "TLS 1.1");
228 break;
229 case BR_TLS12:
230 fprintf(stderr, "TLS 1.2");
231 break;
232 default:
233 fprintf(stderr, "unknown (0x%04X)",
234 (unsigned)cc->session.version);
235 break;
236 }
237 fprintf(stderr, "\n");
238 get_suite_name_ext(
239 cc->session.cipher_suite, csn, sizeof csn);
240 fprintf(stderr, " cipher suite: %s\n", csn);
241 fprintf(stderr, " secure renegotiation: %s\n",
242 cc->reneg == 1 ? "no" : "yes");
243 hsdetails = 1;
244 }
245
246 k_fd = 0;
247 k_in = 0;
248 k_out = 0;
249
250 u = 0;
251 if (sendrec || recvrec) {
252 pfd[u].fd = fd;
253 pfd[u].revents = 0;
254 pfd[u].events = 0;
255 if (sendrec) {
256 pfd[u].events |= POLLOUT;
257 }
258 if (recvrec) {
259 pfd[u].events |= POLLIN;
260 }
261 k_fd = u;
262 u ++;
263 }
264 if (sendapp) {
265 pfd[u].fd = 0;
266 pfd[u].revents = 0;
267 pfd[u].events = POLLIN;
268 k_in = u;
269 u ++;
270 }
271 if (recvapp) {
272 pfd[u].fd = 1;
273 pfd[u].revents = 0;
274 pfd[u].events = POLLOUT;
275 k_out = u;
276 u ++;
277 }
278 n = poll(pfd, u, -1);
279 if (n < 0) {
280 if (errno == EINTR) {
281 continue;
282 }
283 perror("ERROR: poll()");
284 retcode = -2;
285 goto engine_exit;
286 }
287 if (n == 0) {
288 continue;
289 }
290
291 /*
292 * We transform closures/errors into read+write accesses
293 * so as to force the read() or write() call that will
294 * detect the situation.
295 */
296 while (u -- > 0) {
297 if (pfd[u].revents & (POLLERR | POLLHUP)) {
298 pfd[u].revents |= POLLIN | POLLOUT;
299 }
300 }
301
302 /*
303 * We give preference to outgoing data, on stdout and on
304 * the socket.
305 */
306 if (recvapp) {
307 if (pfd[k_out].revents & POLLOUT) {
308 unsigned char *buf;
309 size_t len;
310 ssize_t wlen;
311
312 buf = br_ssl_engine_recvapp_buf(cc, &len);
313 wlen = write(1, buf, len);
314 if (wlen <= 0) {
315 if (verbose) {
316 fprintf(stderr,
317 "stdout closed...\n");
318 }
319 retcode = -2;
320 goto engine_exit;
321 }
322 br_ssl_engine_recvapp_ack(cc, wlen);
323 continue;
324 }
325 }
326 if (sendrec) {
327 if (pfd[k_fd].revents & POLLOUT) {
328 unsigned char *buf;
329 size_t len;
330 ssize_t wlen;
331
332 buf = br_ssl_engine_sendrec_buf(cc, &len);
333 wlen = write(fd, buf, len);
334 if (wlen <= 0) {
335 if (verbose) {
336 fprintf(stderr,
337 "socket closed...\n");
338 }
339 retcode = -1;
340 goto engine_exit;
341 }
342 if (trace) {
343 dump_blob("Outgoing bytes", buf, wlen);
344 }
345 br_ssl_engine_sendrec_ack(cc, wlen);
346 continue;
347 }
348 }
349 if (recvrec) {
350 if (pfd[k_fd].revents & POLLIN) {
351 unsigned char *buf;
352 size_t len;
353 ssize_t rlen;
354
355 buf = br_ssl_engine_recvrec_buf(cc, &len);
356 rlen = read(fd, buf, len);
357 if (rlen <= 0) {
358 if (verbose) {
359 fprintf(stderr,
360 "socket closed...\n");
361 }
362 retcode = -1;
363 goto engine_exit;
364 }
365 if (trace) {
366 dump_blob("Incoming bytes", buf, rlen);
367 }
368 br_ssl_engine_recvrec_ack(cc, rlen);
369 continue;
370 }
371 }
372 if (sendapp) {
373 if (pfd[k_in].revents & POLLIN) {
374 unsigned char *buf;
375 size_t len;
376 ssize_t rlen;
377
378 buf = br_ssl_engine_sendapp_buf(cc, &len);
379 rlen = read(0, buf, len);
380 if (rlen <= 0) {
381 if (verbose) {
382 fprintf(stderr,
383 "stdin closed...\n");
384 }
385 br_ssl_engine_close(cc);
386 } else if (!run_command(cc, buf, rlen)) {
387 br_ssl_engine_sendapp_ack(cc, rlen);
388 }
389 br_ssl_engine_flush(cc, 0);
390 continue;
391 }
392 }
393
394 /* We should never reach that point. */
395 fprintf(stderr, "ERROR: poll() misbehaves\n");
396 retcode = -2;
397 goto engine_exit;
398 }
399
400 /*
401 * Release allocated structures.
402 */
403 engine_exit:
404 return retcode;
405 }