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