xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/apps/altcp_tls/altcp_tls_mbedtls.c (revision 104654410c56c573564690304ae786df310c91fc)
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