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