1 /**
2 * @file
3 * Application layered TCP/TLS connection API (to be used from TCPIP thread)
4 *
5 * This file provides a TLS layer using mbedTLS
6 */
7
8 /*
9 * Copyright (c) 2017 Simon Goldschmidt
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
26 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
28 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 *
34 * This file is part of the lwIP TCP/IP stack.
35 *
36 * Author: Simon Goldschmidt <[email protected]>
37 *
38 * Watch out:
39 * - 'sent' is always called with len==0 to the upper layer. This is because keeping
40 * track of the ratio of application data and TLS overhead would be too much.
41 *
42 * Mandatory security-related configuration:
43 * - define ALTCP_MBEDTLS_RNG_FN to a custom GOOD rng function returning 0 on success:
44 * int my_rng_fn(void *ctx, unsigned char *buffer , size_t len)
45 * - define ALTCP_MBEDTLS_ENTROPY_PTR and ALTCP_MBEDTLS_ENTROPY_LEN to something providing
46 * GOOD custom entropy
47 *
48 * Missing things / @todo:
49 * - RX data is acknowledged after receiving (tcp_recved is called when enqueueing
50 * the pbuf for mbedTLS receive, not when processed by mbedTLS or the inner
51 * connection; altcp_recved() from inner connection does nothing)
52 * - Client connections starting with 'connect()' are not handled yet...
53 * - some unhandled things are caught by LWIP_ASSERTs...
54 */
55
56 #include "lwip/opt.h"
57
58 #if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
59
60 #include "lwip/apps/altcp_tls_mbedtls_opts.h"
61
62 #if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
63
64 #include "lwip/altcp.h"
65 #include "lwip/altcp_tls.h"
66 #include "lwip/priv/altcp_priv.h"
67
68 #include "altcp_tls_mbedtls_structs.h"
69 #include "altcp_tls_mbedtls_mem.h"
70
71 /* @todo: which includes are really needed? */
72 #include "mbedtls/entropy.h"
73 #include "mbedtls/ctr_drbg.h"
74 #include "mbedtls/certs.h"
75 #include "mbedtls/x509.h"
76 #include "mbedtls/ssl.h"
77 #include "mbedtls/net.h"
78 #include "mbedtls/error.h"
79 #include "mbedtls/debug.h"
80 #include "mbedtls/platform.h"
81 #include "mbedtls/memory_buffer_alloc.h"
82 #include "mbedtls/ssl_cache.h"
83
84 #include "mbedtls/ssl_internal.h" /* to call mbedtls_flush_output after ERR_MEM */
85
86 #include <string.h>
87
88 #ifndef ALTCP_MBEDTLS_ENTROPY_PTR
89 #define ALTCP_MBEDTLS_ENTROPY_PTR NULL
90 #endif
91 #ifndef ALTCP_MBEDTLS_ENTROPY_LEN
92 #define ALTCP_MBEDTLS_ENTROPY_LEN 0
93 #endif
94
95 /* Variable prototype, the actual declaration is at the end of this file
96 since it contains pointers to static functions declared here */
97 extern const struct altcp_functions altcp_mbedtls_functions;
98
99 /** Our global mbedTLS configuration (server-specific, not connection-specific) */
100 struct altcp_tls_config {
101 mbedtls_ssl_config conf;
102 mbedtls_entropy_context entropy;
103 mbedtls_ctr_drbg_context ctr_drbg;
104 mbedtls_x509_crt *cert;
105 mbedtls_pk_context *pkey;
106 mbedtls_x509_crt *ca;
107 #if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS
108 /** Inter-connection cache for fast connection startup */
109 struct mbedtls_ssl_cache_context cache;
110 #endif
111 };
112
113 static err_t altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err);
114 static err_t altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn);
115 static err_t altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state);
116 static err_t altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state);
117 static int altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size);
118
119
120 /* callback functions from inner/lower connection: */
121
122 /** Accept callback from lower connection (i.e. TCP)
123 * Allocate one of our structures, assign it to the new connection's 'state' and
124 * call the new connection's 'accepted' callback. If that succeeds, we wait
125 * to receive connection setup handshake bytes from the client.
126 */
127 static err_t
altcp_mbedtls_lower_accept(void * arg,struct altcp_pcb * accepted_conn,err_t err)128 altcp_mbedtls_lower_accept(void *arg, struct altcp_pcb *accepted_conn, err_t err)
129 {
130 struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg;
131 if (listen_conn && listen_conn->state && listen_conn->accept) {
132 err_t setup_err;
133 altcp_mbedtls_state_t *listen_state = (altcp_mbedtls_state_t *)listen_conn->state;
134 /* create a new altcp_conn to pass to the next 'accept' callback */
135 struct altcp_pcb *new_conn = altcp_alloc();
136 if (new_conn == NULL) {
137 return ERR_MEM;
138 }
139 setup_err = altcp_mbedtls_setup(listen_state->conf, new_conn, accepted_conn);
140 if (setup_err != ERR_OK) {
141 altcp_free(new_conn);
142 return setup_err;
143 }
144 return listen_conn->accept(listen_conn->arg, new_conn, err);
145 }
146 return ERR_ARG;
147 }
148
149 /** Connected callback from lower connection (i.e. TCP).
150 * Not really implemented/tested yet...
151 */
152 static err_t
altcp_mbedtls_lower_connected(void * arg,struct altcp_pcb * inner_conn,err_t err)153 altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err)
154 {
155 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
156 LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
157 if (conn && conn->state) {
158 LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
159 /* upper connected is called when handshake is done */
160 if (err != ERR_OK) {
161 if (conn->connected) {
162 return conn->connected(conn->arg, conn, err);
163 }
164 }
165 return altcp_mbedtls_lower_recv_process(conn, (altcp_mbedtls_state_t *)conn->state);
166 }
167 return ERR_VAL;
168 }
169
170 /* Call recved for possibly more than an u16_t */
171 static void
altcp_mbedtls_lower_recved(struct altcp_pcb * inner_conn,int recvd_cnt)172 altcp_mbedtls_lower_recved(struct altcp_pcb *inner_conn, int recvd_cnt)
173 {
174 while (recvd_cnt > 0) {
175 u16_t recvd_part = (u16_t)LWIP_MIN(recvd_cnt, 0xFFFF);
176 altcp_recved(inner_conn, recvd_part);
177 recvd_cnt -= recvd_part;
178 }
179 }
180
181 /** Recv callback from lower connection (i.e. TCP)
182 * This one mainly differs between connection setup/handshake (data is fed into mbedTLS only)
183 * and application phase (data is decoded by mbedTLS and passed on to the application).
184 */
185 static err_t
altcp_mbedtls_lower_recv(void * arg,struct altcp_pcb * inner_conn,struct pbuf * p,err_t err)186 altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err)
187 {
188 altcp_mbedtls_state_t *state;
189 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
190
191 LWIP_ASSERT("no err expected", err == ERR_OK);
192 LWIP_UNUSED_ARG(err);
193
194 if (!conn) {
195 /* no connection given as arg? should not happen, but prevent pbuf/conn leaks */
196 if (p != NULL) {
197 pbuf_free(p);
198 }
199 altcp_close(inner_conn);
200 return ERR_CLSD;
201 }
202 state = (altcp_mbedtls_state_t *)conn->state;
203 LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
204 if (!state) {
205 /* already closed */
206 if (p != NULL) {
207 pbuf_free(p);
208 }
209 altcp_close(inner_conn);
210 return ERR_CLSD;
211 }
212
213 /* handle NULL pbuf (inner connection closed) */
214 if (p == NULL) {
215 /* remote host sent FIN, remember this (SSL state is destroyed
216 when both sides are closed only!) */
217 if ((state->flags & (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) ==
218 (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) {
219 /* need to notify upper layer (e.g. 'accept' called or 'connect' succeeded) */
220 if ((state->rx != NULL) || (state->rx_app != NULL)) {
221 state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED;
222 /* this is a normal close (FIN) but we have unprocessed data, so delay the FIN */
223 altcp_mbedtls_handle_rx_appldata(conn, state);
224 return ERR_OK;
225 }
226 state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED;
227 if (conn->recv) {
228 return conn->recv(conn->arg, conn, NULL, ERR_OK);
229 }
230 } else {
231 /* before connection setup is done: call 'err' */
232 if (conn->err) {
233 conn->err(conn->arg, ERR_CLSD);
234 }
235 altcp_close(conn);
236 }
237 return ERR_OK;
238 }
239
240 /* If we come here, the connection is in good state (handshake phase or application data phase).
241 Queue up the pbuf for processing as handshake data or application data. */
242 if (state->rx == NULL) {
243 state->rx = p;
244 } else {
245 LWIP_ASSERT("rx pbuf overflow", (int)p->tot_len + (int)p->len <= 0xFFFF);
246 pbuf_cat(state->rx, p);
247 }
248 return altcp_mbedtls_lower_recv_process(conn, state);
249 }
250
251 static err_t
altcp_mbedtls_lower_recv_process(struct altcp_pcb * conn,altcp_mbedtls_state_t * state)252 altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
253 {
254 if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
255 /* handle connection setup (handshake not done) */
256 int ret = mbedtls_ssl_handshake(&state->ssl_context);
257 /* try to send data... */
258 altcp_output(conn->inner_conn);
259 if (state->bio_bytes_read) {
260 /* acknowledge all bytes read */
261 altcp_mbedtls_lower_recved(conn->inner_conn, state->bio_bytes_read);
262 state->bio_bytes_read = 0;
263 }
264
265 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
266 /* handshake not done, wait for more recv calls */
267 LWIP_ASSERT("in this state, the rx chain should be empty", state->rx == NULL);
268 return ERR_OK;
269 }
270 if (ret != 0) {
271 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_handshake failed: %d\n", ret));
272 /* handshake failed, connection has to be closed */
273 if (conn->err) {
274 conn->err(conn->arg, ERR_CLSD);
275 }
276
277 if (altcp_close(conn) != ERR_OK) {
278 altcp_abort(conn);
279 }
280 return ERR_OK;
281 }
282 /* If we come here, handshake succeeded. */
283 LWIP_ASSERT("state", state->bio_bytes_read == 0);
284 LWIP_ASSERT("state", state->bio_bytes_appl == 0);
285 state->flags |= ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE;
286 /* issue "connect" callback" to upper connection (this can only happen for active open) */
287 if (conn->connected) {
288 err_t err;
289 err = conn->connected(conn->arg, conn, ERR_OK);
290 if (err != ERR_OK) {
291 return err;
292 }
293 }
294 if (state->rx == NULL) {
295 return ERR_OK;
296 }
297 }
298 /* handle application data */
299 return altcp_mbedtls_handle_rx_appldata(conn, state);
300 }
301
302 /* Pass queued decoded rx data to application */
303 static err_t
altcp_mbedtls_pass_rx_data(struct altcp_pcb * conn,altcp_mbedtls_state_t * state)304 altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
305 {
306 err_t err;
307 struct pbuf *buf;
308 LWIP_ASSERT("conn != NULL", conn != NULL);
309 LWIP_ASSERT("state != NULL", state != NULL);
310 buf = state->rx_app;
311 if (buf) {
312 if (conn->recv) {
313 u16_t tot_len = state->rx_app->tot_len;
314 /* this needs to be increased first because the 'recved' call may come nested */
315 state->rx_passed_unrecved += tot_len;
316 state->flags |= ALTCP_MBEDTLS_FLAGS_UPPER_CALLED;
317 err = conn->recv(conn->arg, conn, state->rx_app, ERR_OK);
318 if (err != ERR_OK) {
319 if (err == ERR_ABRT) {
320 return ERR_ABRT;
321 }
322 /* not received, leave the pbuf(s) queued (and decrease 'unrecved' again) */
323 state->rx_passed_unrecved -= tot_len;
324 LWIP_ASSERT("state->rx_passed_unrecved >= 0", state->rx_passed_unrecved >= 0);
325 if (state->rx_passed_unrecved < 0) {
326 state->rx_passed_unrecved = 0;
327 }
328 return err;
329 }
330 } else {
331 pbuf_free(buf);
332 }
333 state->rx_app = NULL;
334 } else if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) ==
335 ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) {
336 state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED;
337 if (conn->recv) {
338 return conn->recv(conn->arg, conn, NULL, ERR_OK);
339 }
340 }
341
342 return ERR_OK;
343 }
344
345 /* Helper function that processes rx application data stored in rx pbuf chain */
346 static err_t
altcp_mbedtls_handle_rx_appldata(struct altcp_pcb * conn,altcp_mbedtls_state_t * state)347 altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
348 {
349 int ret;
350 LWIP_ASSERT("state != NULL", state != NULL);
351 if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
352 /* handshake not done yet */
353 return ERR_VAL;
354 }
355 do {
356 /* allocate a full-sized unchained PBUF_POOL: this is for RX! */
357 struct pbuf *buf = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
358 if (buf == NULL) {
359 /* We're short on pbufs, try again later from 'poll' or 'recv' callbacks.
360 @todo: close on excessive allocation failures or leave this up to upper conn? */
361 return ERR_OK;
362 }
363
364 /* decrypt application data, this pulls encrypted RX data off state->rx pbuf chain */
365 ret = mbedtls_ssl_read(&state->ssl_context, (unsigned char *)buf->payload, PBUF_POOL_BUFSIZE);
366 if (ret < 0) {
367 if (ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT) {
368 /* client is initiating a new connection using the same source port -> close connection or make handshake */
369 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("new connection on same source port\n"));
370 LWIP_ASSERT("TODO: new connection on same source port, close this connection", 0);
371 } else if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) {
372 if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
373 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was closed gracefully\n"));
374 } else if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
375 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was reset by peer\n"));
376 }
377 pbuf_free(buf);
378 return ERR_OK;
379 } else {
380 pbuf_free(buf);
381 return ERR_OK;
382 }
383 pbuf_free(buf);
384 altcp_abort(conn);
385 return ERR_ABRT;
386 } else {
387 err_t err;
388 if (ret) {
389 LWIP_ASSERT("bogus receive length", ret <= PBUF_POOL_BUFSIZE);
390 /* trim pool pbuf to actually decoded length */
391 pbuf_realloc(buf, (u16_t)ret);
392
393 state->bio_bytes_appl += ret;
394 if (mbedtls_ssl_get_bytes_avail(&state->ssl_context) == 0) {
395 /* Record is done, now we know the share between application and protocol bytes
396 and can adjust the RX window by the protocol bytes.
397 The rest is 'recved' by the application calling our 'recved' fn. */
398 int overhead_bytes;
399 LWIP_ASSERT("bogus byte counts", state->bio_bytes_read > state->bio_bytes_appl);
400 overhead_bytes = state->bio_bytes_read - state->bio_bytes_appl;
401 altcp_mbedtls_lower_recved(conn->inner_conn, overhead_bytes);
402 state->bio_bytes_read = 0;
403 state->bio_bytes_appl = 0;
404 }
405
406 if (state->rx_app == NULL) {
407 state->rx_app = buf;
408 } else {
409 pbuf_cat(state->rx_app, buf);
410 }
411 } else {
412 pbuf_free(buf);
413 buf = NULL;
414 }
415 err = altcp_mbedtls_pass_rx_data(conn, state);
416 if (err != ERR_OK) {
417 if (err == ERR_ABRT) {
418 /* recv callback needs to return this as the pcb is deallocated */
419 return ERR_ABRT;
420 }
421 /* we hide all other errors as we retry feeding the pbuf to the app later */
422 return ERR_OK;
423 }
424 }
425 } while (ret > 0);
426 return ERR_OK;
427 }
428
429 /** Receive callback function called from mbedtls (set via mbedtls_ssl_set_bio)
430 * This function mainly copies data from pbufs and frees the pbufs after copying.
431 */
432 static int
altcp_mbedtls_bio_recv(void * ctx,unsigned char * buf,size_t len)433 altcp_mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len)
434 {
435 struct altcp_pcb *conn = (struct altcp_pcb *)ctx;
436 altcp_mbedtls_state_t *state;
437 struct pbuf *p;
438 u16_t ret;
439 u16_t copy_len;
440 err_t err;
441
442 LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
443 if ((conn == NULL) || (conn->state == NULL)) {
444 return MBEDTLS_ERR_NET_INVALID_CONTEXT;
445 }
446 state = (altcp_mbedtls_state_t *)conn->state;
447 p = state->rx;
448
449 /* @todo: return MBEDTLS_ERR_NET_CONN_RESET/MBEDTLS_ERR_NET_RECV_FAILED? */
450
451 if ((p == NULL) || ((p->len == 0) && (p->next == NULL))) {
452 if (p) {
453 pbuf_free(p);
454 }
455 state->rx = NULL;
456 if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) ==
457 ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) {
458 /* close queued but not passed up yet */
459 return 0;
460 }
461 return MBEDTLS_ERR_SSL_WANT_READ;
462 }
463 /* limit number of bytes again to copy from first pbuf in a chain only */
464 copy_len = (u16_t)LWIP_MIN(len, p->len);
465 /* copy the data */
466 ret = pbuf_copy_partial(p, buf, copy_len, 0);
467 LWIP_ASSERT("ret == copy_len", ret == copy_len);
468 /* hide the copied bytes from the pbuf */
469 err = pbuf_remove_header(p, ret);
470 LWIP_ASSERT("error", err == ERR_OK);
471 if (p->len == 0) {
472 /* the first pbuf has been fully read, free it */
473 state->rx = p->next;
474 p->next = NULL;
475 pbuf_free(p);
476 }
477
478 state->bio_bytes_read += (int)ret;
479 return ret;
480 }
481
482 /** Sent callback from lower connection (i.e. TCP)
483 * This only informs the upper layer to try to send more, not about
484 * the number of ACKed bytes.
485 */
486 static err_t
altcp_mbedtls_lower_sent(void * arg,struct altcp_pcb * inner_conn,u16_t len)487 altcp_mbedtls_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len)
488 {
489 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
490 LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
491 LWIP_UNUSED_ARG(len);
492 if (conn) {
493 altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
494 LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
495 if (!state || !(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
496 /* @todo: do something here? */
497 return ERR_OK;
498 }
499 /* try to send more if we failed before */
500 mbedtls_ssl_flush_output(&state->ssl_context);
501 /* call upper sent with len==0 if the application already sent data */
502 if ((state->flags & ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT) && conn->sent) {
503 return conn->sent(conn->arg, conn, 0);
504 }
505 }
506 return ERR_OK;
507 }
508
509 /** Poll callback from lower connection (i.e. TCP)
510 * Just pass this on to the application.
511 * @todo: retry sending?
512 */
513 static err_t
altcp_mbedtls_lower_poll(void * arg,struct altcp_pcb * inner_conn)514 altcp_mbedtls_lower_poll(void *arg, struct altcp_pcb *inner_conn)
515 {
516 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
517 LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
518 if (conn) {
519 LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
520 /* check if there's unreceived rx data */
521 if (conn->state) {
522 altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
523 /* try to send more if we failed before */
524 mbedtls_ssl_flush_output(&state->ssl_context);
525 if (altcp_mbedtls_handle_rx_appldata(conn, state) == ERR_ABRT) {
526 return ERR_ABRT;
527 }
528 }
529 if (conn->poll) {
530 return conn->poll(conn->arg, conn);
531 }
532 }
533 return ERR_OK;
534 }
535
536 static void
altcp_mbedtls_lower_err(void * arg,err_t err)537 altcp_mbedtls_lower_err(void *arg, err_t err)
538 {
539 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
540 if (conn) {
541 conn->inner_conn = NULL; /* already freed */
542 if (conn->err) {
543 conn->err(conn->arg, err);
544 }
545 altcp_free(conn);
546 }
547 }
548
549 /* setup functions */
550
551 static void
altcp_mbedtls_remove_callbacks(struct altcp_pcb * inner_conn)552 altcp_mbedtls_remove_callbacks(struct altcp_pcb *inner_conn)
553 {
554 altcp_arg(inner_conn, NULL);
555 altcp_recv(inner_conn, NULL);
556 altcp_sent(inner_conn, NULL);
557 altcp_err(inner_conn, NULL);
558 altcp_poll(inner_conn, NULL, inner_conn->pollinterval);
559 }
560
561 static void
altcp_mbedtls_setup_callbacks(struct altcp_pcb * conn,struct altcp_pcb * inner_conn)562 altcp_mbedtls_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
563 {
564 altcp_arg(inner_conn, conn);
565 altcp_recv(inner_conn, altcp_mbedtls_lower_recv);
566 altcp_sent(inner_conn, altcp_mbedtls_lower_sent);
567 altcp_err(inner_conn, altcp_mbedtls_lower_err);
568 /* tcp_poll is set when interval is set by application */
569 /* listen is set totally different :-) */
570 }
571
572 static err_t
altcp_mbedtls_setup(void * conf,struct altcp_pcb * conn,struct altcp_pcb * inner_conn)573 altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
574 {
575 int ret;
576 struct altcp_tls_config *config = (struct altcp_tls_config *)conf;
577 altcp_mbedtls_state_t *state;
578 if (!conf) {
579 return ERR_ARG;
580 }
581 LWIP_ASSERT("invalid inner_conn", conn != inner_conn);
582
583 /* allocate mbedtls context */
584 state = altcp_mbedtls_alloc(conf);
585 if (state == NULL) {
586 return ERR_MEM;
587 }
588 /* initialize mbedtls context: */
589 mbedtls_ssl_init(&state->ssl_context);
590 ret = mbedtls_ssl_setup(&state->ssl_context, &config->conf);
591 if (ret != 0) {
592 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_setup failed\n"));
593 /* @todo: convert 'ret' to err_t */
594 altcp_mbedtls_free(conf, state);
595 return ERR_MEM;
596 }
597 /* tell mbedtls about our I/O functions */
598 mbedtls_ssl_set_bio(&state->ssl_context, conn, altcp_mbedtls_bio_send, altcp_mbedtls_bio_recv, NULL);
599
600 altcp_mbedtls_setup_callbacks(conn, inner_conn);
601 conn->inner_conn = inner_conn;
602 conn->fns = &altcp_mbedtls_functions;
603 conn->state = state;
604 return ERR_OK;
605 }
606
607 struct altcp_pcb *
altcp_tls_wrap(struct altcp_tls_config * config,struct altcp_pcb * inner_pcb)608 altcp_tls_wrap(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb)
609 {
610 struct altcp_pcb *ret;
611 if (inner_pcb == NULL) {
612 return NULL;
613 }
614 ret = altcp_alloc();
615 if (ret != NULL) {
616 if (altcp_mbedtls_setup(config, ret, inner_pcb) != ERR_OK) {
617 altcp_free(ret);
618 return NULL;
619 }
620 }
621 return ret;
622 }
623
624 void *
altcp_tls_context(struct altcp_pcb * conn)625 altcp_tls_context(struct altcp_pcb *conn)
626 {
627 if (conn && conn->state) {
628 altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
629 return &state->ssl_context;
630 }
631 return NULL;
632 }
633
634 #if ALTCP_MBEDTLS_DEBUG != LWIP_DBG_OFF
635 static void
altcp_mbedtls_debug(void * ctx,int level,const char * file,int line,const char * str)636 altcp_mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str)
637 {
638 LWIP_UNUSED_ARG(str);
639 LWIP_UNUSED_ARG(level);
640 LWIP_UNUSED_ARG(file);
641 LWIP_UNUSED_ARG(line);
642 LWIP_UNUSED_ARG(ctx);
643 /* @todo: output debug string :-) */
644 }
645 #endif
646
647 #ifndef ALTCP_MBEDTLS_RNG_FN
648 /** ATTENTION: It is *really* important to *NOT* use this dummy RNG in production code!!!! */
649 static int
dummy_rng(void * ctx,unsigned char * buffer,size_t len)650 dummy_rng(void *ctx, unsigned char *buffer, size_t len)
651 {
652 static size_t ctr;
653 size_t i;
654 LWIP_UNUSED_ARG(ctx);
655 for (i = 0; i < len; i++) {
656 buffer[i] = (unsigned char)++ctr;
657 }
658 return 0;
659 }
660 #define ALTCP_MBEDTLS_RNG_FN dummy_rng
661 #endif /* ALTCP_MBEDTLS_RNG_FN */
662
663 /** Create new TLS configuration
664 * ATTENTION: Server certificate and private key have to be added outside this function!
665 */
666 static struct altcp_tls_config *
altcp_tls_create_config(int is_server,int have_cert,int have_pkey,int have_ca)667 altcp_tls_create_config(int is_server, int have_cert, int have_pkey, int have_ca)
668 {
669 size_t sz;
670 int ret;
671 struct altcp_tls_config *conf;
672 mbedtls_x509_crt *mem;
673
674 if (TCP_WND < MBEDTLS_SSL_MAX_CONTENT_LEN) {
675 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG|LWIP_DBG_LEVEL_SERIOUS,
676 ("altcp_tls: TCP_WND is smaller than the RX decrypion buffer, connection RX might stall!\n"));
677 }
678
679 altcp_mbedtls_mem_init();
680
681 sz = sizeof(struct altcp_tls_config);
682 if (have_cert) {
683 sz += sizeof(mbedtls_x509_crt);
684 }
685 if (have_ca) {
686 sz += sizeof(mbedtls_x509_crt);
687 }
688 if (have_pkey) {
689 sz += sizeof(mbedtls_pk_context);
690 }
691
692 conf = (struct altcp_tls_config *)altcp_mbedtls_alloc_config(sz);
693 if (conf == NULL) {
694 return NULL;
695 }
696 mem = (mbedtls_x509_crt *)(conf + 1);
697 if (have_cert) {
698 conf->cert = mem;
699 mem++;
700 }
701 if (have_ca) {
702 conf->ca = mem;
703 mem++;
704 }
705 if (have_pkey) {
706 conf->pkey = (mbedtls_pk_context *)mem;
707 }
708
709 mbedtls_ssl_config_init(&conf->conf);
710 mbedtls_entropy_init(&conf->entropy);
711 mbedtls_ctr_drbg_init(&conf->ctr_drbg);
712
713 /* Seed the RNG */
714 ret = mbedtls_ctr_drbg_seed(&conf->ctr_drbg, ALTCP_MBEDTLS_RNG_FN, &conf->entropy, ALTCP_MBEDTLS_ENTROPY_PTR, ALTCP_MBEDTLS_ENTROPY_LEN);
715 if (ret != 0) {
716 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ctr_drbg_seed failed: %d\n", ret));
717 altcp_mbedtls_free_config(conf);
718 return NULL;
719 }
720
721 /* Setup ssl context (@todo: what's different for a client here? -> might better be done on listen/connect) */
722 ret = mbedtls_ssl_config_defaults(&conf->conf, is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
723 MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
724 if (ret != 0) {
725 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_config_defaults failed: %d\n", ret));
726 altcp_mbedtls_free_config(conf);
727 return NULL;
728 }
729 mbedtls_ssl_conf_authmode(&conf->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
730
731 mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &conf->ctr_drbg);
732 #if ALTCP_MBEDTLS_DEBUG != LWIP_DBG_OFF
733 mbedtls_ssl_conf_dbg(&conf->conf, altcp_mbedtls_debug, stdout);
734 #endif
735 #if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS
736 mbedtls_ssl_conf_session_cache(&conf->conf, &conf->cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set);
737 mbedtls_ssl_cache_set_timeout(&conf->cache, 30);
738 mbedtls_ssl_cache_set_max_entries(&conf->cache, 30);
739 #endif
740
741 return conf;
742 }
743
744 /** Create new TLS configuration
745 * This is a suboptimal version that gets the encrypted private key and its password,
746 * as well as the server certificate.
747 */
748 struct altcp_tls_config *
altcp_tls_create_config_server_privkey_cert(const u8_t * privkey,size_t privkey_len,const u8_t * privkey_pass,size_t privkey_pass_len,const u8_t * cert,size_t cert_len)749 altcp_tls_create_config_server_privkey_cert(const u8_t *privkey, size_t privkey_len,
750 const u8_t *privkey_pass, size_t privkey_pass_len,
751 const u8_t *cert, size_t cert_len)
752 {
753 int ret;
754 mbedtls_x509_crt *srvcert;
755 mbedtls_pk_context *pkey;
756 struct altcp_tls_config *conf = altcp_tls_create_config(1, 1, 1, 0);
757 if (conf == NULL) {
758 return NULL;
759 }
760
761 srvcert = conf->cert;
762 mbedtls_x509_crt_init(srvcert);
763
764 pkey = conf->pkey;
765 mbedtls_pk_init(pkey);
766
767 /* Load the certificates and private key */
768 ret = mbedtls_x509_crt_parse(srvcert, cert, cert_len);
769 if (ret != 0) {
770 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse failed: %d\n", ret));
771 altcp_mbedtls_free_config(conf);
772 return NULL;
773 }
774
775 ret = mbedtls_pk_parse_key(pkey, (const unsigned char *) privkey, privkey_len, privkey_pass, privkey_pass_len);
776 if (ret != 0) {
777 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_public_key failed: %d\n", ret));
778 mbedtls_x509_crt_free(srvcert);
779 altcp_mbedtls_free_config(conf);
780 return NULL;
781 }
782
783 mbedtls_ssl_conf_ca_chain(&conf->conf, srvcert->next, NULL);
784 ret = mbedtls_ssl_conf_own_cert(&conf->conf, srvcert, pkey);
785 if (ret != 0) {
786 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d\n", ret));
787 mbedtls_x509_crt_free(srvcert);
788 mbedtls_pk_free(pkey);
789 altcp_mbedtls_free_config(conf);
790 return NULL;
791 }
792 return conf;
793 }
794
795 static struct altcp_tls_config *
altcp_tls_create_config_client_common(const u8_t * ca,size_t ca_len,int is_2wayauth)796 altcp_tls_create_config_client_common(const u8_t *ca, size_t ca_len, int is_2wayauth)
797 {
798 int ret;
799 struct altcp_tls_config *conf = altcp_tls_create_config(0, is_2wayauth, is_2wayauth, ca != NULL);
800 if (conf == NULL) {
801 return NULL;
802 }
803
804 /* Initialize the CA certificate if provided
805 * CA certificate is optional (to save memory) but recommended for production environment
806 * Without CA certificate, connection will be prone to man-in-the-middle attacks */
807 if (ca) {
808 mbedtls_x509_crt_init(conf->ca);
809 ret = mbedtls_x509_crt_parse(conf->ca, ca, ca_len);
810 if (ret != 0) {
811 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse ca failed: %d 0x%x", ret, -1*ret));
812 altcp_mbedtls_free_config(conf);
813 return NULL;
814 }
815
816 mbedtls_ssl_conf_ca_chain(&conf->conf, conf->ca, NULL);
817 }
818 return conf;
819 }
820
821 struct altcp_tls_config *
altcp_tls_create_config_client(const u8_t * ca,size_t ca_len)822 altcp_tls_create_config_client(const u8_t *ca, size_t ca_len)
823 {
824 return altcp_tls_create_config_client_common(ca, ca_len, 0);
825 }
826
827 struct altcp_tls_config *
altcp_tls_create_config_client_2wayauth(const u8_t * ca,size_t ca_len,const u8_t * privkey,size_t privkey_len,const u8_t * privkey_pass,size_t privkey_pass_len,const u8_t * cert,size_t cert_len)828 altcp_tls_create_config_client_2wayauth(const u8_t *ca, size_t ca_len, const u8_t *privkey, size_t privkey_len,
829 const u8_t *privkey_pass, size_t privkey_pass_len,
830 const u8_t *cert, size_t cert_len)
831 {
832 int ret;
833 struct altcp_tls_config *conf;
834
835 if (!cert || !privkey) {
836 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("altcp_tls_create_config_client_2wayauth: certificate and priv key required"));
837 return NULL;
838 }
839
840 conf = altcp_tls_create_config_client_common(ca, ca_len, 1);
841 if (conf == NULL) {
842 return NULL;
843 }
844
845 /* Initialize the client certificate and corresponding private key */
846 mbedtls_x509_crt_init(conf->cert);
847 ret = mbedtls_x509_crt_parse(conf->cert, cert, cert_len);
848 if (ret != 0) {
849 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse cert failed: %d 0x%x", ret, -1*ret));
850 altcp_mbedtls_free_config(conf->cert);
851 return NULL;
852 }
853
854 mbedtls_pk_init(conf->pkey);
855 ret = mbedtls_pk_parse_key(conf->pkey, privkey, privkey_len, privkey_pass, privkey_pass_len);
856 if (ret != 0) {
857 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_key failed: %d 0x%x", ret, -1*ret));
858 altcp_mbedtls_free_config(conf);
859 return NULL;
860 }
861
862 ret = mbedtls_ssl_conf_own_cert(&conf->conf, conf->cert, conf->pkey);
863 if (ret != 0) {
864 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d 0x%x", ret, -1*ret));
865 altcp_mbedtls_free_config(conf);
866 return NULL;
867 }
868
869 return conf;
870 }
871
872 void
altcp_tls_free_config(struct altcp_tls_config * conf)873 altcp_tls_free_config(struct altcp_tls_config *conf)
874 {
875 if (conf->pkey) {
876 mbedtls_pk_free(conf->pkey);
877 }
878 if (conf->cert) {
879 mbedtls_x509_crt_free(conf->cert);
880 }
881 if (conf->ca) {
882 mbedtls_x509_crt_free(conf->ca);
883 }
884 altcp_mbedtls_free_config(conf);
885 }
886
887 /* "virtual" functions */
888 static void
altcp_mbedtls_set_poll(struct altcp_pcb * conn,u8_t interval)889 altcp_mbedtls_set_poll(struct altcp_pcb *conn, u8_t interval)
890 {
891 if (conn != NULL) {
892 altcp_poll(conn->inner_conn, altcp_mbedtls_lower_poll, interval);
893 }
894 }
895
896 static void
altcp_mbedtls_recved(struct altcp_pcb * conn,u16_t len)897 altcp_mbedtls_recved(struct altcp_pcb *conn, u16_t len)
898 {
899 u16_t lower_recved;
900 altcp_mbedtls_state_t *state;
901 if (conn == NULL) {
902 return;
903 }
904 state = (altcp_mbedtls_state_t *)conn->state;
905 if (state == NULL) {
906 return;
907 }
908 if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
909 return;
910 }
911 lower_recved = len;
912 if (lower_recved > state->rx_passed_unrecved) {
913 LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("bogus recved count (len > state->rx_passed_unrecved / %d / %d)",
914 len, state->rx_passed_unrecved));
915 lower_recved = (u16_t)state->rx_passed_unrecved;
916 }
917 state->rx_passed_unrecved -= lower_recved;
918
919 altcp_recved(conn->inner_conn, lower_recved);
920 }
921
922 static err_t
altcp_mbedtls_connect(struct altcp_pcb * conn,const ip_addr_t * ipaddr,u16_t port,altcp_connected_fn connected)923 altcp_mbedtls_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
924 {
925 if (conn == NULL) {
926 return ERR_VAL;
927 }
928 conn->connected = connected;
929 return altcp_connect(conn->inner_conn, ipaddr, port, altcp_mbedtls_lower_connected);
930 }
931
932 static struct altcp_pcb *
altcp_mbedtls_listen(struct altcp_pcb * conn,u8_t backlog,err_t * err)933 altcp_mbedtls_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
934 {
935 struct altcp_pcb *lpcb;
936 if (conn == NULL) {
937 return NULL;
938 }
939 lpcb = altcp_listen_with_backlog_and_err(conn->inner_conn, backlog, err);
940 if (lpcb != NULL) {
941 conn->inner_conn = lpcb;
942 altcp_accept(lpcb, altcp_mbedtls_lower_accept);
943 return conn;
944 }
945 return NULL;
946 }
947
948 static void
altcp_mbedtls_abort(struct altcp_pcb * conn)949 altcp_mbedtls_abort(struct altcp_pcb *conn)
950 {
951 if (conn != NULL) {
952 altcp_abort(conn->inner_conn);
953 }
954 }
955
956 static err_t
altcp_mbedtls_close(struct altcp_pcb * conn)957 altcp_mbedtls_close(struct altcp_pcb *conn)
958 {
959 struct altcp_pcb *inner_conn;
960 if (conn == NULL) {
961 return ERR_VAL;
962 }
963 inner_conn = conn->inner_conn;
964 if (inner_conn) {
965 err_t err;
966 altcp_poll_fn oldpoll = inner_conn->poll;
967 altcp_mbedtls_remove_callbacks(conn->inner_conn);
968 err = altcp_close(conn->inner_conn);
969 if (err != ERR_OK) {
970 /* not closed, set up all callbacks again */
971 altcp_mbedtls_setup_callbacks(conn, inner_conn);
972 /* poll callback is not included in the above */
973 altcp_poll(inner_conn, oldpoll, inner_conn->pollinterval);
974 return err;
975 }
976 conn->inner_conn = NULL;
977 }
978 altcp_free(conn);
979 return ERR_OK;
980 }
981
982 /** Allow caller of altcp_write() to limit to negotiated chunk size
983 * or remaining sndbuf space of inner_conn.
984 */
985 static u16_t
altcp_mbedtls_sndbuf(struct altcp_pcb * conn)986 altcp_mbedtls_sndbuf(struct altcp_pcb *conn)
987 {
988 if (conn) {
989 altcp_mbedtls_state_t *state;
990 state = (altcp_mbedtls_state_t*)conn->state;
991 if (!state || !(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
992 return 0;
993 }
994 if (conn->inner_conn) {
995 u16_t sndbuf = altcp_sndbuf(conn->inner_conn);
996 /* Take care of record header, IV, AuthTag */
997 int ssl_expan = mbedtls_ssl_get_record_expansion(&state->ssl_context);
998 if (ssl_expan > 0) {
999 size_t ssl_added = (u16_t)LWIP_MIN(ssl_expan, 0xFFFF);
1000 /* internal sndbuf smaller than our offset */
1001 if (ssl_added < sndbuf) {
1002 size_t max_len = 0xFFFF;
1003 size_t ret;
1004 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
1005 /* @todo: adjust ssl_added to real value related to negociated cipher */
1006 size_t max_frag_len = mbedtls_ssl_get_max_frag_len(&state->ssl_context);
1007 max_len = LWIP_MIN(max_frag_len, max_len);
1008 #endif
1009 /* Adjust sndbuf of inner_conn with what added by SSL */
1010 ret = LWIP_MIN(sndbuf - ssl_added, max_len);
1011 LWIP_ASSERT("sndbuf overflow", ret <= 0xFFFF);
1012 return (u16_t)ret;
1013 }
1014 }
1015 }
1016 }
1017 /* fallback: use sendbuf of the inner connection */
1018 return altcp_default_sndbuf(conn);
1019 }
1020
1021 /** Write data to a TLS connection. Calls into mbedTLS, which in turn calls into
1022 * @ref altcp_mbedtls_bio_send() to send the encrypted data
1023 */
1024 static err_t
altcp_mbedtls_write(struct altcp_pcb * conn,const void * dataptr,u16_t len,u8_t apiflags)1025 altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
1026 {
1027 int ret;
1028 altcp_mbedtls_state_t *state;
1029
1030 LWIP_UNUSED_ARG(apiflags);
1031
1032 if (conn == NULL) {
1033 return ERR_VAL;
1034 }
1035
1036 state = (altcp_mbedtls_state_t *)conn->state;
1037 if (state == NULL) {
1038 /* @todo: which error? */
1039 return ERR_CLSD;
1040 }
1041 if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
1042 /* @todo: which error? */
1043 return ERR_VAL;
1044 }
1045
1046 /* HACK: if thre is something left to send, try to flush it and only
1047 allow sending more if this succeeded (this is a hack because neither
1048 returning 0 nor MBEDTLS_ERR_SSL_WANT_WRITE worked for me) */
1049 if (state->ssl_context.out_left) {
1050 mbedtls_ssl_flush_output(&state->ssl_context);
1051 if (state->ssl_context.out_left) {
1052 return ERR_MEM;
1053 }
1054 }
1055 ret = mbedtls_ssl_write(&state->ssl_context, (const unsigned char *)dataptr, len);
1056 /* try to send data... */
1057 altcp_output(conn->inner_conn);
1058 if (ret >= 0) {
1059 if (ret == len) {
1060 state->flags |= ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT;
1061 return ERR_OK;
1062 } else {
1063 /* @todo/@fixme: assumption: either everything sent or error */
1064 LWIP_ASSERT("ret <= 0", 0);
1065 return ERR_MEM;
1066 }
1067 } else {
1068 if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
1069 /* @todo: convert error to err_t */
1070 return ERR_MEM;
1071 }
1072 LWIP_ASSERT("unhandled error", 0);
1073 return ERR_VAL;
1074 }
1075 }
1076
1077 /** Send callback function called from mbedtls (set via mbedtls_ssl_set_bio)
1078 * This function is either called during handshake or when sending application
1079 * data via @ref altcp_mbedtls_write (or altcp_write)
1080 */
1081 static int
altcp_mbedtls_bio_send(void * ctx,const unsigned char * dataptr,size_t size)1082 altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size)
1083 {
1084 struct altcp_pcb *conn = (struct altcp_pcb *) ctx;
1085 int written = 0;
1086 size_t size_left = size;
1087 u8_t apiflags = TCP_WRITE_FLAG_COPY;
1088
1089 LWIP_ASSERT("conn != NULL", conn != NULL);
1090 if ((conn == NULL) || (conn->inner_conn == NULL)) {
1091 return MBEDTLS_ERR_NET_INVALID_CONTEXT;
1092 }
1093
1094 while (size_left) {
1095 u16_t write_len = (u16_t)LWIP_MIN(size_left, 0xFFFF);
1096 err_t err = altcp_write(conn->inner_conn, (const void *)dataptr, write_len, apiflags);
1097 if (err == ERR_OK) {
1098 written += write_len;
1099 size_left -= write_len;
1100 } else if (err == ERR_MEM) {
1101 if (written) {
1102 return written;
1103 }
1104 return 0; /* MBEDTLS_ERR_SSL_WANT_WRITE; */
1105 } else {
1106 LWIP_ASSERT("tls_write, tcp_write: err != ERR MEM", 0);
1107 /* @todo: return MBEDTLS_ERR_NET_CONN_RESET or MBEDTLS_ERR_NET_SEND_FAILED */
1108 return MBEDTLS_ERR_NET_SEND_FAILED;
1109 }
1110 }
1111 return written;
1112 }
1113
1114 static u16_t
altcp_mbedtls_mss(struct altcp_pcb * conn)1115 altcp_mbedtls_mss(struct altcp_pcb *conn)
1116 {
1117 if (conn == NULL) {
1118 return 0;
1119 }
1120 /* @todo: LWIP_MIN(mss, mbedtls_ssl_get_max_frag_len()) ? */
1121 return altcp_mss(conn->inner_conn);
1122 }
1123
1124 static void
altcp_mbedtls_dealloc(struct altcp_pcb * conn)1125 altcp_mbedtls_dealloc(struct altcp_pcb *conn)
1126 {
1127 /* clean up and free tls state */
1128 if (conn) {
1129 altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
1130 if (state) {
1131 mbedtls_ssl_free(&state->ssl_context);
1132 state->flags = 0;
1133 if (state->rx) {
1134 /* free leftover (unhandled) rx pbufs */
1135 pbuf_free(state->rx);
1136 state->rx = NULL;
1137 }
1138 altcp_mbedtls_free(state->conf, state);
1139 conn->state = NULL;
1140 }
1141 }
1142 }
1143
1144 const struct altcp_functions altcp_mbedtls_functions = {
1145 altcp_mbedtls_set_poll,
1146 altcp_mbedtls_recved,
1147 altcp_default_bind,
1148 altcp_mbedtls_connect,
1149 altcp_mbedtls_listen,
1150 altcp_mbedtls_abort,
1151 altcp_mbedtls_close,
1152 altcp_default_shutdown,
1153 altcp_mbedtls_write,
1154 altcp_default_output,
1155 altcp_mbedtls_mss,
1156 altcp_mbedtls_sndbuf,
1157 altcp_default_sndqueuelen,
1158 altcp_default_nagle_disable,
1159 altcp_default_nagle_enable,
1160 altcp_default_nagle_disabled,
1161 altcp_default_setprio,
1162 altcp_mbedtls_dealloc,
1163 altcp_default_get_tcp_addrinfo,
1164 altcp_default_get_ip,
1165 altcp_default_get_port
1166 #ifdef LWIP_DEBUG
1167 , altcp_default_dbg_get_tcp_state
1168 #endif
1169 };
1170
1171 #endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
1172 #endif /* LWIP_ALTCP */
1173