2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
31 #include <sys/types.h>
32 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
44 dump_blob(const char *name
, const void *data
, size_t len
)
46 const unsigned char *buf
;
50 fprintf(stderr
, "%s (len = %lu)", name
, (unsigned long)len
);
51 for (u
= 0; u
< len
; u
++) {
53 fprintf(stderr
, "\n%08lX ", (unsigned long)u
);
54 } else if ((u
& 7) == 0) {
57 fprintf(stderr
, " %02x", buf
[u
]);
59 fprintf(stderr
, "\n");
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.
68 run_command(br_ssl_engine_context
*cc
, unsigned char *buf
, size_t len
)
71 * A single static slot for saving session parameters.
73 static br_ssl_session_parameters slot
;
74 static int slot_used
= 0;
78 if (len
< 2 || len
> 3) {
81 if (len
== 3 && (buf
[1] != '\r' || buf
[2] != '\n')) {
84 if (len
== 2 && buf
[1] != '\n') {
89 fprintf(stderr
, "closing...\n");
90 br_ssl_engine_close(cc
);
93 if (br_ssl_engine_renegotiate(cc
)) {
94 fprintf(stderr
, "renegotiating...\n");
96 fprintf(stderr
, "not renegotiating.\n");
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
107 fprintf(stderr
, "forgetting session...\n");
108 br_ssl_client_forget_session((br_ssl_client_context
*)cc
);
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
]);
117 fprintf(stderr
, "\n");
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
]);
127 fprintf(stderr
, "\n");
128 br_ssl_engine_set_session_parameters(cc
, &slot
);
139 run_ssl_engine(br_ssl_engine_context
*cc
, int fd
, unsigned flags
)
148 verbose
= (flags
& RUN_ENGINE_VERBOSE
) != 0;
149 trace
= (flags
& RUN_ENGINE_TRACE
) != 0;
152 * Make sure that stdin and stdout are non-blocking.
154 fcntl(0, F_SETFL
, O_NONBLOCK
);
155 fcntl(1, F_SETFL
, O_NONBLOCK
);
162 int sendrec
, recvrec
, sendapp
, recvapp
;
163 struct pollfd pfd
[3];
165 size_t u
, k_fd
, k_in
, k_out
;
168 * Get current engine state.
170 st
= br_ssl_engine_current_state(cc
);
171 if (st
== BR_SSL_CLOSED
) {
174 err
= br_ssl_engine_last_error(cc
);
175 if (err
== BR_ERR_OK
) {
178 "SSL closed normally\n");
183 fprintf(stderr
, "ERROR: SSL error %d", err
);
185 if (err
>= BR_ERR_SEND_FATAL_ALERT
) {
186 err
-= BR_ERR_SEND_FATAL_ALERT
;
188 " (sent alert %d)\n", err
);
189 } else if (err
>= BR_ERR_RECV_FATAL_ALERT
) {
190 err
-= BR_ERR_RECV_FATAL_ALERT
;
192 " (received alert %d)\n", err
);
196 ename
= find_error_name(err
, NULL
);
200 fprintf(stderr
, " (%s)\n", ename
);
207 * Compute descriptors that must be polled, depending
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
) {
217 fprintf(stderr
, "Handshake completed\n");
218 fprintf(stderr
, " version: ");
219 switch (cc
->session
.version
) {
221 fprintf(stderr
, "SSL 3.0");
224 fprintf(stderr
, "TLS 1.0");
227 fprintf(stderr
, "TLS 1.1");
230 fprintf(stderr
, "TLS 1.2");
233 fprintf(stderr
, "unknown (0x%04X)",
234 (unsigned)cc
->session
.version
);
237 fprintf(stderr
, "\n");
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");
251 if (sendrec
|| recvrec
) {
256 pfd
[u
].events
|= POLLOUT
;
259 pfd
[u
].events
|= POLLIN
;
267 pfd
[u
].events
= POLLIN
;
274 pfd
[u
].events
= POLLOUT
;
278 n
= poll(pfd
, u
, -1);
280 if (errno
== EINTR
) {
283 perror("ERROR: poll()");
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.
297 if (pfd
[u
].revents
& (POLLERR
| POLLHUP
)) {
298 pfd
[u
].revents
|= POLLIN
| POLLOUT
;
303 * We give preference to outgoing data, on stdout and on
307 if (pfd
[k_out
].revents
& POLLOUT
) {
312 buf
= br_ssl_engine_recvapp_buf(cc
, &len
);
313 wlen
= write(1, buf
, len
);
317 "stdout closed...\n");
322 br_ssl_engine_recvapp_ack(cc
, wlen
);
327 if (pfd
[k_fd
].revents
& POLLOUT
) {
332 buf
= br_ssl_engine_sendrec_buf(cc
, &len
);
333 wlen
= write(fd
, buf
, len
);
337 "socket closed...\n");
343 dump_blob("Outgoing bytes", buf
, wlen
);
345 br_ssl_engine_sendrec_ack(cc
, wlen
);
350 if (pfd
[k_fd
].revents
& POLLIN
) {
355 buf
= br_ssl_engine_recvrec_buf(cc
, &len
);
356 rlen
= read(fd
, buf
, len
);
360 "socket closed...\n");
366 dump_blob("Incoming bytes", buf
, rlen
);
368 br_ssl_engine_recvrec_ack(cc
, rlen
);
373 if (pfd
[k_in
].revents
& POLLIN
) {
378 buf
= br_ssl_engine_sendapp_buf(cc
, &len
);
379 rlen
= read(0, buf
, len
);
383 "stdin closed...\n");
385 br_ssl_engine_close(cc
);
386 } else if (!run_command(cc
, buf
, rlen
)) {
387 br_ssl_engine_sendapp_ack(cc
, rlen
);
389 br_ssl_engine_flush(cc
, 0);
394 /* We should never reach that point. */
395 fprintf(stderr
, "ERROR: poll() misbehaves\n");
401 * Release allocated structures.