Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers altcp_tls_mbedtls.c Source File

altcp_tls_mbedtls.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Application layered TCP/TLS connection API (to be used from TCPIP thread)
00004  *
00005  * This file provides a TLS layer using mbedTLS
00006  */
00007 
00008 /*
00009  * Copyright (c) 2017 Simon Goldschmidt
00010  * All rights reserved.
00011  *
00012  * Redistribution and use in source and binary forms, with or without modification,
00013  * are permitted provided that the following conditions are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright notice,
00016  *    this list of conditions and the following disclaimer.
00017  * 2. Redistributions in binary form must reproduce the above copyright notice,
00018  *    this list of conditions and the following disclaimer in the documentation
00019  *    and/or other materials provided with the distribution.
00020  * 3. The name of the author may not be used to endorse or promote products
00021  *    derived from this software without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00024  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00025  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00026  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00028  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00031  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00032  * OF SUCH DAMAGE.
00033  *
00034  * This file is part of the lwIP TCP/IP stack.
00035  *
00036  * Author: Simon Goldschmidt <goldsimon@gmx.de>
00037  *
00038  * Watch out:
00039  * - 'sent' is always called with len==0 to the upper layer. This is because keeping
00040  *   track of the ratio of application data and TLS overhead would be too much.
00041  *
00042  * Mandatory security-related configuration:
00043  * - define ALTCP_MBEDTLS_RNG_FN to mbedtls_entropy_func to use the standard mbedTLS
00044  *   entropy and ensure to add at least one strong entropy source to your mbedtls port
00045  *   (implement mbedtls_platform_entropy_poll or mbedtls_hardware_poll providing strong
00046  *   entropy)
00047  * - define ALTCP_MBEDTLS_ENTROPY_PTR and ALTCP_MBEDTLS_ENTROPY_LEN to something providing
00048  *   GOOD custom entropy
00049  *
00050  * Missing things / @todo:
00051  * - some unhandled/untested things migh be caught by LWIP_ASSERTs...
00052  */
00053 
00054 #include "lwip/opt.h"
00055 
00056 #if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
00057 
00058 #include "lwip/apps/altcp_tls_mbedtls_opts.h"
00059 
00060 #if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS
00061 
00062 #include "lwip/altcp.h"
00063 #include "lwip/altcp_tls.h"
00064 #include "lwip/priv/altcp_priv.h"
00065 
00066 #include "altcp_tls_mbedtls_structs.h"
00067 #include "altcp_tls_mbedtls_mem.h"
00068 
00069 /* @todo: which includes are really needed? */
00070 #include "mbedtls/entropy.h"
00071 #include "mbedtls/ctr_drbg.h"
00072 #include "mbedtls/certs.h"
00073 #include "mbedtls/x509.h"
00074 #include "mbedtls/ssl.h"
00075 #include "mbedtls/net.h"
00076 #include "mbedtls/error.h"
00077 #include "mbedtls/debug.h"
00078 #include "mbedtls/platform.h"
00079 #include "mbedtls/memory_buffer_alloc.h"
00080 #include "mbedtls/ssl_cache.h"
00081 
00082 #include "mbedtls/ssl_internal.h" /* to call mbedtls_flush_output after ERR_MEM */
00083 
00084 #include <string.h>
00085 
00086 #ifndef ALTCP_MBEDTLS_ENTROPY_PTR
00087 #define ALTCP_MBEDTLS_ENTROPY_PTR   NULL
00088 #endif
00089 #ifndef ALTCP_MBEDTLS_ENTROPY_LEN
00090 #define ALTCP_MBEDTLS_ENTROPY_LEN   0
00091 #endif
00092 
00093 /* Variable prototype, the actual declaration is at the end of this file
00094    since it contains pointers to static functions declared here */
00095 extern const struct altcp_functions altcp_mbedtls_functions;
00096 
00097 /** Our global mbedTLS configuration (server-specific, not connection-specific) */
00098 struct altcp_tls_config {
00099   mbedtls_ssl_config conf;
00100   mbedtls_entropy_context entropy;
00101   mbedtls_ctr_drbg_context ctr_drbg;
00102   mbedtls_x509_crt *cert;
00103   mbedtls_pk_context *pkey;
00104   mbedtls_x509_crt *ca;
00105 #if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS
00106   /** Inter-connection cache for fast connection startup */
00107   struct mbedtls_ssl_cache_context cache;
00108 #endif
00109 };
00110 
00111 static err_t altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err);
00112 static err_t altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn);
00113 static err_t altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state);
00114 static err_t altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state);
00115 static int altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size);
00116 
00117 
00118 /* callback functions from inner/lower connection: */
00119 
00120 /** Accept callback from lower connection (i.e. TCP)
00121  * Allocate one of our structures, assign it to the new connection's 'state' and
00122  * call the new connection's 'accepted' callback. If that succeeds, we wait
00123  * to receive connection setup handshake bytes from the client.
00124  */
00125 static err_t
00126 altcp_mbedtls_lower_accept(void *arg, struct altcp_pcb *accepted_conn, err_t err)
00127 {
00128   struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg;
00129   if (listen_conn && listen_conn->state && listen_conn->accept) {
00130     err_t setup_err;
00131     altcp_mbedtls_state_t *listen_state = (altcp_mbedtls_state_t *)listen_conn->state;
00132     /* create a new altcp_conn to pass to the next 'accept' callback */
00133     struct altcp_pcb *new_conn = altcp_alloc();
00134     if (new_conn == NULL) {
00135       return ERR_MEM;
00136     }
00137     setup_err = altcp_mbedtls_setup(listen_state->conf, new_conn, accepted_conn);
00138     if (setup_err != ERR_OK) {
00139       altcp_free(new_conn);
00140       return setup_err;
00141     }
00142     return listen_conn->accept(listen_conn->arg, new_conn, err);
00143   }
00144   return ERR_ARG;
00145 }
00146 
00147 /** Connected callback from lower connection (i.e. TCP).
00148  * Not really implemented/tested yet...
00149  */
00150 static err_t
00151 altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err)
00152 {
00153   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00154   LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
00155   if (conn && conn->state) {
00156     LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
00157     /* upper connected is called when handshake is done */
00158     if (err != ERR_OK) {
00159       if (conn->connected) {
00160         return conn->connected(conn->arg, conn, err);
00161       }
00162     }
00163     return altcp_mbedtls_lower_recv_process(conn, (altcp_mbedtls_state_t *)conn->state);
00164   }
00165   return ERR_VAL;
00166 }
00167 
00168 /* Call recved for possibly more than an u16_t */
00169 static void
00170 altcp_mbedtls_lower_recved(struct altcp_pcb *inner_conn, int recvd_cnt)
00171 {
00172   while (recvd_cnt > 0) {
00173     u16_t recvd_part = (u16_t)LWIP_MIN(recvd_cnt, 0xFFFF);
00174     altcp_recved (inner_conn, recvd_part);
00175     recvd_cnt -= recvd_part;
00176   }
00177 }
00178 
00179 /** Recv callback from lower connection (i.e. TCP)
00180  * This one mainly differs between connection setup/handshake (data is fed into mbedTLS only)
00181  * and application phase (data is decoded by mbedTLS and passed on to the application).
00182  */
00183 static err_t
00184 altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err)
00185 {
00186   altcp_mbedtls_state_t *state;
00187   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00188 
00189   LWIP_ASSERT("no err expected", err == ERR_OK);
00190   LWIP_UNUSED_ARG(err);
00191 
00192   if (!conn) {
00193     /* no connection given as arg? should not happen, but prevent pbuf/conn leaks */
00194     if (p != NULL) {
00195       pbuf_free(p);
00196     }
00197     altcp_close (inner_conn);
00198     return ERR_CLSD;
00199   }
00200   state = (altcp_mbedtls_state_t *)conn->state;
00201   LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
00202   if (!state) {
00203     /* already closed */
00204     if (p != NULL) {
00205       pbuf_free(p);
00206     }
00207     altcp_close (inner_conn);
00208     return ERR_CLSD;
00209   }
00210 
00211   /* handle NULL pbuf (inner connection closed) */
00212   if (p == NULL) {
00213     /* remote host sent FIN, remember this (SSL state is destroyed
00214         when both sides are closed only!) */
00215     if ((state->flags & (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) ==
00216         (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) {
00217       /* need to notify upper layer (e.g. 'accept' called or 'connect' succeeded) */
00218       if ((state->rx != NULL) || (state->rx_app != NULL)) {
00219         state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED;
00220         /* this is a normal close (FIN) but we have unprocessed data, so delay the FIN */
00221         altcp_mbedtls_handle_rx_appldata(conn, state);
00222         return ERR_OK;
00223       }
00224       state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED;
00225       if (conn->recv) {
00226         return conn->recv(conn->arg, conn, NULL, ERR_OK);
00227       }
00228     } else {
00229       /* before connection setup is done: call 'err' */
00230       if (conn->err) {
00231         conn->err(conn->arg, ERR_CLSD);
00232       }
00233       altcp_close (conn);
00234     }
00235     return ERR_OK;
00236   }
00237 
00238   /* If we come here, the connection is in good state (handshake phase or application data phase).
00239      Queue up the pbuf for processing as handshake data or application data. */
00240   if (state->rx == NULL) {
00241     state->rx = p;
00242   } else {
00243     LWIP_ASSERT("rx pbuf overflow", (int)p->tot_len + (int)p->len <= 0xFFFF);
00244     pbuf_cat(state->rx, p);
00245   }
00246   return altcp_mbedtls_lower_recv_process(conn, state);
00247 }
00248 
00249 static err_t
00250 altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
00251 {
00252   if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
00253     /* handle connection setup (handshake not done) */
00254     int ret = mbedtls_ssl_handshake(&state->ssl_context);
00255     /* try to send data... */
00256     altcp_output (conn->inner_conn);
00257     if (state->bio_bytes_read) {
00258       /* acknowledge all bytes read */
00259       altcp_mbedtls_lower_recved(conn->inner_conn, state->bio_bytes_read);
00260       state->bio_bytes_read = 0;
00261     }
00262 
00263     if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
00264       /* handshake not done, wait for more recv calls */
00265       LWIP_ASSERT("in this state, the rx chain should be empty", state->rx == NULL);
00266       return ERR_OK;
00267     }
00268     if (ret != 0) {
00269       LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_handshake failed: %d\n", ret));
00270       /* handshake failed, connection has to be closed */
00271       if (conn->err) {
00272         conn->err(conn->arg, ERR_CLSD);
00273       }
00274 
00275       if (altcp_close (conn) != ERR_OK) {
00276         altcp_abort (conn);
00277       }
00278       return ERR_OK;
00279     }
00280     /* If we come here, handshake succeeded. */
00281     LWIP_ASSERT("state", state->bio_bytes_read == 0);
00282     LWIP_ASSERT("state", state->bio_bytes_appl == 0);
00283     state->flags |= ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE;
00284     /* issue "connect" callback" to upper connection (this can only happen for active open) */
00285     if (conn->connected) {
00286       err_t err;
00287       err = conn->connected(conn->arg, conn, ERR_OK);
00288       if (err != ERR_OK) {
00289         return err;
00290       }
00291     }
00292     if (state->rx == NULL) {
00293       return ERR_OK;
00294     }
00295   }
00296   /* handle application data */
00297   return altcp_mbedtls_handle_rx_appldata(conn, state);
00298 }
00299 
00300 /* Pass queued decoded rx data to application */
00301 static err_t
00302 altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
00303 {
00304   err_t err;
00305   struct pbuf *buf;
00306   LWIP_ASSERT("conn != NULL", conn != NULL);
00307   LWIP_ASSERT("state != NULL", state != NULL);
00308   buf = state->rx_app;
00309   if (buf) {
00310     state->rx_app = NULL;
00311     if (conn->recv) {
00312       u16_t tot_len = buf->tot_len;
00313       /* this needs to be increased first because the 'recved' call may come nested */
00314       state->rx_passed_unrecved += tot_len;
00315       state->flags |= ALTCP_MBEDTLS_FLAGS_UPPER_CALLED;
00316       err = conn->recv(conn->arg, conn, buf, ERR_OK);
00317       if (err != ERR_OK) {
00318         if (err == ERR_ABRT) {
00319           return ERR_ABRT;
00320         }
00321         /* not received, leave the pbuf(s) queued (and decrease 'unrecved' again) */
00322         LWIP_ASSERT("state == conn->state", state == conn->state);
00323         state->rx_app = buf;
00324         state->rx_passed_unrecved -= tot_len;
00325         LWIP_ASSERT("state->rx_passed_unrecved >= 0", state->rx_passed_unrecved >= 0);
00326         if (state->rx_passed_unrecved < 0) {
00327           state->rx_passed_unrecved = 0;
00328         }
00329         return err;
00330       }
00331     } else {
00332       pbuf_free(buf);
00333     }
00334   } else if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) ==
00335              ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) {
00336     state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED;
00337     if (conn->recv) {
00338       return conn->recv(conn->arg, conn, NULL, ERR_OK);
00339     }
00340   }
00341 
00342   /* application may have close the connection */
00343   if (conn->state != state) {
00344     /* return error code to ensure altcp_mbedtls_handle_rx_appldata() exits the loop */
00345     return ERR_CLSD;
00346   }
00347   return ERR_OK;
00348 }
00349 
00350 /* Helper function that processes rx application data stored in rx pbuf chain */
00351 static err_t
00352 altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
00353 {
00354   int ret;
00355   LWIP_ASSERT("state != NULL", state != NULL);
00356   if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
00357     /* handshake not done yet */
00358     return ERR_VAL;
00359   }
00360   do {
00361     /* allocate a full-sized unchained PBUF_POOL: this is for RX! */
00362     struct pbuf *buf = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
00363     if (buf == NULL) {
00364       /* We're short on pbufs, try again later from 'poll' or 'recv' callbacks.
00365          @todo: close on excessive allocation failures or leave this up to upper conn? */
00366       return ERR_OK;
00367     }
00368 
00369     /* decrypt application data, this pulls encrypted RX data off state->rx pbuf chain */
00370     ret = mbedtls_ssl_read(&state->ssl_context, (unsigned char *)buf->payload, PBUF_POOL_BUFSIZE);
00371     if (ret < 0) {
00372       if (ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT) {
00373         /* client is initiating a new connection using the same source port -> close connection or make handshake */
00374         LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("new connection on same source port\n"));
00375         LWIP_ASSERT("TODO: new connection on same source port, close this connection", 0);
00376       } else if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) {
00377         if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
00378           LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was closed gracefully\n"));
00379         } else if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
00380           LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was reset by peer\n"));
00381         }
00382         pbuf_free(buf);
00383         return ERR_OK;
00384       } else {
00385         pbuf_free(buf);
00386         return ERR_OK;
00387       }
00388       pbuf_free(buf);
00389       altcp_abort (conn);
00390       return ERR_ABRT;
00391     } else {
00392       err_t err;
00393       if (ret) {
00394         LWIP_ASSERT("bogus receive length", ret <= PBUF_POOL_BUFSIZE);
00395         /* trim pool pbuf to actually decoded length */
00396         pbuf_realloc(buf, (u16_t)ret);
00397 
00398         state->bio_bytes_appl += ret;
00399         if (mbedtls_ssl_get_bytes_avail(&state->ssl_context) == 0) {
00400           /* Record is done, now we know the share between application and protocol bytes
00401              and can adjust the RX window by the protocol bytes.
00402              The rest is 'recved' by the application calling our 'recved' fn. */
00403           int overhead_bytes;
00404           LWIP_ASSERT("bogus byte counts", state->bio_bytes_read > state->bio_bytes_appl);
00405           overhead_bytes = state->bio_bytes_read - state->bio_bytes_appl;
00406           altcp_mbedtls_lower_recved(conn->inner_conn, overhead_bytes);
00407           state->bio_bytes_read = 0;
00408           state->bio_bytes_appl = 0;
00409         }
00410 
00411         if (state->rx_app == NULL) {
00412           state->rx_app = buf;
00413         } else {
00414           pbuf_cat(state->rx_app, buf);
00415         }
00416       } else {
00417         pbuf_free(buf);
00418         buf = NULL;
00419       }
00420       err = altcp_mbedtls_pass_rx_data(conn, state);
00421       if (err != ERR_OK) {
00422         if (err == ERR_ABRT) {
00423           /* recv callback needs to return this as the pcb is deallocated */
00424           return ERR_ABRT;
00425         }
00426         /* we hide all other errors as we retry feeding the pbuf to the app later */
00427         return ERR_OK;
00428       }
00429     }
00430   } while (ret > 0);
00431   return ERR_OK;
00432 }
00433 
00434 /** Receive callback function called from mbedtls (set via mbedtls_ssl_set_bio)
00435  * This function mainly copies data from pbufs and frees the pbufs after copying.
00436  */
00437 static int
00438 altcp_mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len)
00439 {
00440   struct altcp_pcb *conn = (struct altcp_pcb *)ctx;
00441   altcp_mbedtls_state_t *state;
00442   struct pbuf *p;
00443   u16_t ret;
00444   u16_t copy_len;
00445   err_t err;
00446 
00447   LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
00448   if ((conn == NULL) || (conn->state == NULL)) {
00449     return MBEDTLS_ERR_NET_INVALID_CONTEXT;
00450   }
00451   state = (altcp_mbedtls_state_t *)conn->state;
00452   p = state->rx;
00453 
00454   /* @todo: return MBEDTLS_ERR_NET_CONN_RESET/MBEDTLS_ERR_NET_RECV_FAILED? */
00455 
00456   if ((p == NULL) || ((p->len == 0) && (p->next == NULL))) {
00457     if (p) {
00458       pbuf_free(p);
00459     }
00460     state->rx = NULL;
00461     if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) ==
00462         ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) {
00463       /* close queued but not passed up yet */
00464       return 0;
00465     }
00466     return MBEDTLS_ERR_SSL_WANT_READ;
00467   }
00468   /* limit number of bytes again to copy from first pbuf in a chain only */
00469   copy_len = (u16_t)LWIP_MIN(len, p->len);
00470   /* copy the data */
00471   ret = pbuf_copy_partial(p, buf, copy_len, 0);
00472   LWIP_ASSERT("ret == copy_len", ret == copy_len);
00473   /* hide the copied bytes from the pbuf */
00474   err = pbuf_remove_header(p, ret);
00475   LWIP_ASSERT("error", err == ERR_OK);
00476   if (p->len == 0) {
00477     /* the first pbuf has been fully read, free it */
00478     state->rx = p->next;
00479     p->next = NULL;
00480     pbuf_free(p);
00481   }
00482 
00483   state->bio_bytes_read += (int)ret;
00484   return ret;
00485 }
00486 
00487 /** Sent callback from lower connection (i.e. TCP)
00488  * This only informs the upper layer to try to send more, not about
00489  * the number of ACKed bytes.
00490  */
00491 static err_t
00492 altcp_mbedtls_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len)
00493 {
00494   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00495   LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
00496   LWIP_UNUSED_ARG(len);
00497   if (conn) {
00498     altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
00499     LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
00500     if (!state || !(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
00501       /* @todo: do something here? */
00502       return ERR_OK;
00503     }
00504     /* try to send more if we failed before */
00505     mbedtls_ssl_flush_output(&state->ssl_context);
00506     /* call upper sent with len==0 if the application already sent data */
00507     if ((state->flags & ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT) && conn->sent) {
00508       return conn->sent(conn->arg, conn, 0);
00509     }
00510   }
00511   return ERR_OK;
00512 }
00513 
00514 /** Poll callback from lower connection (i.e. TCP)
00515  * Just pass this on to the application.
00516  * @todo: retry sending?
00517  */
00518 static err_t
00519 altcp_mbedtls_lower_poll(void *arg, struct altcp_pcb *inner_conn)
00520 {
00521   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00522   LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
00523   if (conn) {
00524     LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
00525     /* check if there's unreceived rx data */
00526     if (conn->state) {
00527       altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
00528       /* try to send more if we failed before */
00529       mbedtls_ssl_flush_output(&state->ssl_context);
00530       if (altcp_mbedtls_handle_rx_appldata(conn, state) == ERR_ABRT) {
00531         return ERR_ABRT;
00532       }
00533     }
00534     if (conn->poll) {
00535       return conn->poll(conn->arg, conn);
00536     }
00537   }
00538   return ERR_OK;
00539 }
00540 
00541 static void
00542 altcp_mbedtls_lower_err(void *arg, err_t err)
00543 {
00544   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00545   if (conn) {
00546     conn->inner_conn = NULL; /* already freed */
00547     if (conn->err) {
00548       conn->err(conn->arg, err);
00549     }
00550     altcp_free(conn);
00551   }
00552 }
00553 
00554 /* setup functions */
00555 
00556 static void
00557 altcp_mbedtls_remove_callbacks(struct altcp_pcb *inner_conn)
00558 {
00559   altcp_arg (inner_conn, NULL);
00560   altcp_recv (inner_conn, NULL);
00561   altcp_sent (inner_conn, NULL);
00562   altcp_err (inner_conn, NULL);
00563   altcp_poll (inner_conn, NULL, inner_conn->pollinterval);
00564 }
00565 
00566 static void
00567 altcp_mbedtls_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
00568 {
00569   altcp_arg (inner_conn, conn);
00570   altcp_recv (inner_conn, altcp_mbedtls_lower_recv);
00571   altcp_sent (inner_conn, altcp_mbedtls_lower_sent);
00572   altcp_err (inner_conn, altcp_mbedtls_lower_err);
00573   /* tcp_poll is set when interval is set by application */
00574   /* listen is set totally different :-) */
00575 }
00576 
00577 static err_t
00578 altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
00579 {
00580   int ret;
00581   struct altcp_tls_config *config = (struct altcp_tls_config *)conf;
00582   altcp_mbedtls_state_t *state;
00583   if (!conf) {
00584     return ERR_ARG;
00585   }
00586   LWIP_ASSERT("invalid inner_conn", conn != inner_conn);
00587 
00588   /* allocate mbedtls context */
00589   state = altcp_mbedtls_alloc(conf);
00590   if (state == NULL) {
00591     return ERR_MEM;
00592   }
00593   /* initialize mbedtls context: */
00594   mbedtls_ssl_init(&state->ssl_context);
00595   ret = mbedtls_ssl_setup(&state->ssl_context, &config->conf);
00596   if (ret != 0) {
00597     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_setup failed\n"));
00598     /* @todo: convert 'ret' to err_t */
00599     altcp_mbedtls_free(conf, state);
00600     return ERR_MEM;
00601   }
00602   /* tell mbedtls about our I/O functions */
00603   mbedtls_ssl_set_bio(&state->ssl_context, conn, altcp_mbedtls_bio_send, altcp_mbedtls_bio_recv, NULL);
00604 
00605   altcp_mbedtls_setup_callbacks(conn, inner_conn);
00606   conn->inner_conn = inner_conn;
00607   conn->fns = &altcp_mbedtls_functions;
00608   conn->state = state;
00609   return ERR_OK;
00610 }
00611 
00612 struct altcp_pcb *
00613 altcp_tls_wrap(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb)
00614 {
00615   struct altcp_pcb *ret;
00616   if (inner_pcb == NULL) {
00617     return NULL;
00618   }
00619   ret = altcp_alloc();
00620   if (ret != NULL) {
00621     if (altcp_mbedtls_setup(config, ret, inner_pcb) != ERR_OK) {
00622       altcp_free(ret);
00623       return NULL;
00624     }
00625   }
00626   return ret;
00627 }
00628 
00629 void *
00630 altcp_tls_context(struct altcp_pcb *conn)
00631 {
00632   if (conn && conn->state) {
00633     altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
00634     return &state->ssl_context;
00635   }
00636   return NULL;
00637 }
00638 
00639 #if ALTCP_MBEDTLS_DEBUG != LWIP_DBG_OFF
00640 static void
00641 altcp_mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str)
00642 {
00643   LWIP_UNUSED_ARG(ctx);
00644   LWIP_UNUSED_ARG(level);
00645   LWIP_UNUSED_ARG(file);
00646   LWIP_UNUSED_ARG(line);
00647   LWIP_UNUSED_ARG(str);
00648 
00649   LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("%s:%04d: %s", file, line, str));
00650 }
00651 #endif
00652 
00653 #ifndef ALTCP_MBEDTLS_RNG_FN
00654 /** ATTENTION: It is *really* important to *NOT* use this dummy RNG in production code!!!! */
00655 static int
00656 dummy_rng(void *ctx, unsigned char *buffer, size_t len)
00657 {
00658   static size_t ctr;
00659   size_t i;
00660   LWIP_UNUSED_ARG(ctx);
00661   for (i = 0; i < len; i++) {
00662     buffer[i] = (unsigned char)++ctr;
00663   }
00664   return 0;
00665 }
00666 #define ALTCP_MBEDTLS_RNG_FN dummy_rng
00667 #endif /* ALTCP_MBEDTLS_RNG_FN */
00668 
00669 /** Create new TLS configuration
00670  * ATTENTION: Server certificate and private key have to be added outside this function!
00671  */
00672 static struct altcp_tls_config *
00673 altcp_tls_create_config(int is_server, int have_cert, int have_pkey, int have_ca)
00674 {
00675   size_t sz;
00676   int ret;
00677   struct altcp_tls_config *conf;
00678   mbedtls_x509_crt *mem;
00679 
00680   if (TCP_WND < MBEDTLS_SSL_MAX_CONTENT_LEN) {
00681     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG|LWIP_DBG_LEVEL_SERIOUS,
00682       ("altcp_tls: TCP_WND is smaller than the RX decryption buffer, connection RX might stall!\n"));
00683   }
00684 
00685   altcp_mbedtls_mem_init();
00686 
00687   sz = sizeof(struct altcp_tls_config);
00688   if (have_cert) {
00689     sz += sizeof(mbedtls_x509_crt);
00690   }
00691   if (have_ca) {
00692     sz += sizeof(mbedtls_x509_crt);
00693   }
00694   if (have_pkey) {
00695     sz += sizeof(mbedtls_pk_context);
00696   }
00697 
00698   conf = (struct altcp_tls_config *)altcp_mbedtls_alloc_config(sz);
00699   if (conf == NULL) {
00700     return NULL;
00701   }
00702   mem = (mbedtls_x509_crt *)(conf + 1);
00703   if (have_cert) {
00704     conf->cert = mem;
00705     mem++;
00706   }
00707   if (have_ca) {
00708     conf->ca = mem;
00709     mem++;
00710   }
00711   if (have_pkey) {
00712     conf->pkey = (mbedtls_pk_context *)mem;
00713   }
00714 
00715   mbedtls_ssl_config_init(&conf->conf);
00716   mbedtls_entropy_init(&conf->entropy);
00717   mbedtls_ctr_drbg_init(&conf->ctr_drbg);
00718 
00719   /* Seed the RNG */
00720   ret = mbedtls_ctr_drbg_seed(&conf->ctr_drbg, ALTCP_MBEDTLS_RNG_FN, &conf->entropy, ALTCP_MBEDTLS_ENTROPY_PTR, ALTCP_MBEDTLS_ENTROPY_LEN);
00721   if (ret != 0) {
00722     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ctr_drbg_seed failed: %d\n", ret));
00723     altcp_mbedtls_free_config(conf);
00724     return NULL;
00725   }
00726 
00727   /* Setup ssl context (@todo: what's different for a client here? -> might better be done on listen/connect) */
00728   ret = mbedtls_ssl_config_defaults(&conf->conf, is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
00729                                     MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
00730   if (ret != 0) {
00731     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_config_defaults failed: %d\n", ret));
00732     altcp_mbedtls_free_config(conf);
00733     return NULL;
00734   }
00735   mbedtls_ssl_conf_authmode(&conf->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
00736 
00737   mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &conf->ctr_drbg);
00738 #if ALTCP_MBEDTLS_DEBUG != LWIP_DBG_OFF
00739   mbedtls_ssl_conf_dbg(&conf->conf, altcp_mbedtls_debug, stdout);
00740 #endif
00741 #if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS
00742   mbedtls_ssl_conf_session_cache(&conf->conf, &conf->cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set);
00743   mbedtls_ssl_cache_set_timeout(&conf->cache, 30);
00744   mbedtls_ssl_cache_set_max_entries(&conf->cache, 30);
00745 #endif
00746 
00747   return conf;
00748 }
00749 
00750 /** Create new TLS configuration
00751  * This is a suboptimal version that gets the encrypted private key and its password,
00752  * as well as the server certificate.
00753  */
00754 struct altcp_tls_config *
00755 altcp_tls_create_config_server_privkey_cert(const u8_t *privkey, size_t privkey_len,
00756     const u8_t *privkey_pass, size_t privkey_pass_len,
00757     const u8_t *cert, size_t cert_len)
00758 {
00759   int ret;
00760   mbedtls_x509_crt *srvcert;
00761   mbedtls_pk_context *pkey;
00762   struct altcp_tls_config *conf = altcp_tls_create_config(1, 1, 1, 0);
00763   if (conf == NULL) {
00764     return NULL;
00765   }
00766 
00767   srvcert = conf->cert;
00768   mbedtls_x509_crt_init(srvcert);
00769 
00770   pkey = conf->pkey;
00771   mbedtls_pk_init(pkey);
00772 
00773   /* Load the certificates and private key */
00774   ret = mbedtls_x509_crt_parse(srvcert, cert, cert_len);
00775   if (ret != 0) {
00776     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse failed: %d\n", ret));
00777     altcp_mbedtls_free_config(conf);
00778     return NULL;
00779   }
00780 
00781   ret = mbedtls_pk_parse_key(pkey, (const unsigned char *) privkey, privkey_len, privkey_pass, privkey_pass_len);
00782   if (ret != 0) {
00783     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_public_key failed: %d\n", ret));
00784     mbedtls_x509_crt_free(srvcert);
00785     altcp_mbedtls_free_config(conf);
00786     return NULL;
00787   }
00788 
00789   mbedtls_ssl_conf_ca_chain(&conf->conf, srvcert->next, NULL);
00790   ret = mbedtls_ssl_conf_own_cert(&conf->conf, srvcert, pkey);
00791   if (ret != 0) {
00792     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d\n", ret));
00793     mbedtls_x509_crt_free(srvcert);
00794     mbedtls_pk_free(pkey);
00795     altcp_mbedtls_free_config(conf);
00796     return NULL;
00797   }
00798   return conf;
00799 }
00800 
00801 static struct altcp_tls_config *
00802 altcp_tls_create_config_client_common(const u8_t *ca, size_t ca_len, int is_2wayauth)
00803 {
00804   int ret;
00805   struct altcp_tls_config *conf = altcp_tls_create_config(0, is_2wayauth, is_2wayauth, ca != NULL);
00806   if (conf == NULL) {
00807     return NULL;
00808   }
00809 
00810   /* Initialize the CA certificate if provided
00811    * CA certificate is optional (to save memory) but recommended for production environment
00812    * Without CA certificate, connection will be prone to man-in-the-middle attacks */
00813   if (ca) {
00814     mbedtls_x509_crt_init(conf->ca);
00815     ret = mbedtls_x509_crt_parse(conf->ca, ca, ca_len);
00816     if (ret != 0) {
00817       LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse ca failed: %d 0x%x", ret, -1*ret));
00818       altcp_mbedtls_free_config(conf);
00819       return NULL;
00820     }
00821 
00822     mbedtls_ssl_conf_ca_chain(&conf->conf, conf->ca, NULL);
00823   }
00824   return conf;
00825 }
00826 
00827 struct altcp_tls_config *
00828 altcp_tls_create_config_client(const u8_t *ca, size_t ca_len)
00829 {
00830   return altcp_tls_create_config_client_common(ca, ca_len, 0);
00831 }
00832 
00833 struct altcp_tls_config *
00834 altcp_tls_create_config_client_2wayauth(const u8_t *ca, size_t ca_len, const u8_t *privkey, size_t privkey_len,
00835                                         const u8_t *privkey_pass, size_t privkey_pass_len,
00836                                         const u8_t *cert, size_t cert_len)
00837 {
00838   int ret;
00839   struct altcp_tls_config *conf;
00840 
00841   if (!cert || !privkey) {
00842     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("altcp_tls_create_config_client_2wayauth: certificate and priv key required"));
00843     return NULL;
00844   }
00845 
00846   conf = altcp_tls_create_config_client_common(ca, ca_len, 1);
00847   if (conf == NULL) {
00848     return NULL;
00849   }
00850 
00851   /* Initialize the client certificate and corresponding private key */
00852   mbedtls_x509_crt_init(conf->cert);
00853   ret = mbedtls_x509_crt_parse(conf->cert, cert, cert_len);
00854   if (ret != 0) {
00855     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse cert failed: %d 0x%x", ret, -1*ret));
00856     altcp_mbedtls_free_config(conf->cert);
00857     return NULL;
00858   }
00859 
00860   mbedtls_pk_init(conf->pkey);
00861   ret = mbedtls_pk_parse_key(conf->pkey, privkey, privkey_len, privkey_pass, privkey_pass_len);
00862   if (ret != 0) {
00863     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_key failed: %d 0x%x", ret, -1*ret));
00864     altcp_mbedtls_free_config(conf);
00865     return NULL;
00866   }
00867 
00868   ret = mbedtls_ssl_conf_own_cert(&conf->conf, conf->cert, conf->pkey);
00869   if (ret != 0) {
00870     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d 0x%x", ret, -1*ret));
00871     altcp_mbedtls_free_config(conf);
00872     return NULL;
00873   }
00874 
00875   return conf;
00876 }
00877 
00878 void
00879 altcp_tls_free_config(struct altcp_tls_config *conf)
00880 {
00881   if (conf->pkey) {
00882     mbedtls_pk_free(conf->pkey);
00883   }
00884   if (conf->cert) {
00885     mbedtls_x509_crt_free(conf->cert);
00886   }
00887   if (conf->ca) {
00888     mbedtls_x509_crt_free(conf->ca);
00889   }  
00890   altcp_mbedtls_free_config(conf);
00891 }
00892 
00893 /* "virtual" functions */
00894 static void
00895 altcp_mbedtls_set_poll(struct altcp_pcb *conn, u8_t interval)
00896 {
00897   if (conn != NULL) {
00898     altcp_poll (conn->inner_conn, altcp_mbedtls_lower_poll, interval);
00899   }
00900 }
00901 
00902 static void
00903 altcp_mbedtls_recved(struct altcp_pcb *conn, u16_t len)
00904 {
00905   u16_t lower_recved;
00906   altcp_mbedtls_state_t *state;
00907   if (conn == NULL) {
00908     return;
00909   }
00910   state = (altcp_mbedtls_state_t *)conn->state;
00911   if (state == NULL) {
00912     return;
00913   }
00914   if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
00915     return;
00916   }
00917   lower_recved = len;
00918   if (lower_recved > state->rx_passed_unrecved) {
00919     LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("bogus recved count (len > state->rx_passed_unrecved / %d / %d)",
00920                                       len, state->rx_passed_unrecved));
00921     lower_recved = (u16_t)state->rx_passed_unrecved;
00922   }
00923   state->rx_passed_unrecved -= lower_recved;
00924 
00925   altcp_recved (conn->inner_conn, lower_recved);
00926 }
00927 
00928 static err_t
00929 altcp_mbedtls_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
00930 {
00931   if (conn == NULL) {
00932     return ERR_VAL;
00933   }
00934   conn->connected = connected;
00935   return altcp_connect (conn->inner_conn, ipaddr, port, altcp_mbedtls_lower_connected);
00936 }
00937 
00938 static struct altcp_pcb *
00939 altcp_mbedtls_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
00940 {
00941   struct altcp_pcb *lpcb;
00942   if (conn == NULL) {
00943     return NULL;
00944   }
00945   lpcb = altcp_listen_with_backlog_and_err (conn->inner_conn, backlog, err);
00946   if (lpcb != NULL) {
00947     conn->inner_conn = lpcb;
00948     altcp_accept (lpcb, altcp_mbedtls_lower_accept);
00949     return conn;
00950   }
00951   return NULL;
00952 }
00953 
00954 static void
00955 altcp_mbedtls_abort(struct altcp_pcb *conn)
00956 {
00957   if (conn != NULL) {
00958     altcp_abort (conn->inner_conn);
00959   }
00960 }
00961 
00962 static err_t
00963 altcp_mbedtls_close(struct altcp_pcb *conn)
00964 {
00965   struct altcp_pcb *inner_conn;
00966   if (conn == NULL) {
00967     return ERR_VAL;
00968   }
00969   inner_conn = conn->inner_conn;
00970   if (inner_conn) {
00971     err_t err;
00972     altcp_poll_fn oldpoll = inner_conn->poll;
00973     altcp_mbedtls_remove_callbacks(conn->inner_conn);
00974     err = altcp_close (conn->inner_conn);
00975     if (err != ERR_OK) {
00976       /* not closed, set up all callbacks again */
00977       altcp_mbedtls_setup_callbacks(conn, inner_conn);
00978       /* poll callback is not included in the above */
00979       altcp_poll (inner_conn, oldpoll, inner_conn->pollinterval);
00980       return err;
00981     }
00982     conn->inner_conn = NULL;
00983   }
00984   altcp_free(conn);
00985   return ERR_OK;
00986 }
00987 
00988 /** Allow caller of altcp_write() to limit to negotiated chunk size
00989  *  or remaining sndbuf space of inner_conn.
00990  */
00991 static u16_t
00992 altcp_mbedtls_sndbuf(struct altcp_pcb *conn)
00993 {
00994   if (conn) {
00995     altcp_mbedtls_state_t *state;
00996     state = (altcp_mbedtls_state_t*)conn->state;
00997     if (!state || !(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
00998       return 0;
00999     }
01000     if (conn->inner_conn) {
01001       u16_t sndbuf = altcp_sndbuf (conn->inner_conn);
01002       /* Take care of record header, IV, AuthTag */
01003       int ssl_expan = mbedtls_ssl_get_record_expansion(&state->ssl_context);
01004       if (ssl_expan > 0) {
01005         size_t ssl_added = (u16_t)LWIP_MIN(ssl_expan, 0xFFFF);
01006         /* internal sndbuf smaller than our offset */
01007         if (ssl_added < sndbuf) {
01008           size_t max_len = 0xFFFF;
01009           size_t ret;
01010 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
01011           /* @todo: adjust ssl_added to real value related to negociated cipher */
01012           size_t max_frag_len = mbedtls_ssl_get_max_frag_len(&state->ssl_context);
01013           max_len = LWIP_MIN(max_frag_len, max_len);
01014 #endif
01015           /* Adjust sndbuf of inner_conn with what added by SSL */
01016           ret = LWIP_MIN(sndbuf - ssl_added, max_len);
01017           LWIP_ASSERT("sndbuf overflow", ret <= 0xFFFF);
01018           return (u16_t)ret;
01019         }
01020       }
01021     }
01022   }
01023   /* fallback: use sendbuf of the inner connection */
01024   return altcp_default_sndbuf(conn);
01025 }
01026 
01027 /** Write data to a TLS connection. Calls into mbedTLS, which in turn calls into
01028  * @ref altcp_mbedtls_bio_send() to send the encrypted data
01029  */
01030 static err_t
01031 altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
01032 {
01033   int ret;
01034   altcp_mbedtls_state_t *state;
01035 
01036   LWIP_UNUSED_ARG(apiflags);
01037 
01038   if (conn == NULL) {
01039     return ERR_VAL;
01040   }
01041 
01042   state = (altcp_mbedtls_state_t *)conn->state;
01043   if (state == NULL) {
01044     /* @todo: which error? */
01045     return ERR_CLSD;
01046   }
01047   if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
01048     /* @todo: which error? */
01049     return ERR_VAL;
01050   }
01051 
01052   /* HACK: if thre is something left to send, try to flush it and only
01053      allow sending more if this succeeded (this is a hack because neither
01054      returning 0 nor MBEDTLS_ERR_SSL_WANT_WRITE worked for me) */
01055   if (state->ssl_context.out_left) {
01056     mbedtls_ssl_flush_output(&state->ssl_context);
01057     if (state->ssl_context.out_left) {
01058       return ERR_MEM;
01059     }
01060   }
01061   ret = mbedtls_ssl_write(&state->ssl_context, (const unsigned char *)dataptr, len);
01062   /* try to send data... */
01063   altcp_output (conn->inner_conn);
01064   if (ret >= 0) {
01065     if (ret == len) {
01066       state->flags |= ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT;
01067       return ERR_OK;
01068     } else {
01069       /* @todo/@fixme: assumption: either everything sent or error */
01070       LWIP_ASSERT("ret <= 0", 0);
01071       return ERR_MEM;
01072     }
01073   } else {
01074     if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
01075       /* @todo: convert error to err_t */
01076       return ERR_MEM;
01077     }
01078     LWIP_ASSERT("unhandled error", 0);
01079     return ERR_VAL;
01080   }
01081 }
01082 
01083 /** Send callback function called from mbedtls (set via mbedtls_ssl_set_bio)
01084  * This function is either called during handshake or when sending application
01085  * data via @ref altcp_mbedtls_write (or altcp_write)
01086  */
01087 static int
01088 altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size)
01089 {
01090   struct altcp_pcb *conn = (struct altcp_pcb *) ctx;
01091   int written = 0;
01092   size_t size_left = size;
01093   u8_t apiflags = TCP_WRITE_FLAG_COPY;
01094 
01095   LWIP_ASSERT("conn != NULL", conn != NULL);
01096   if ((conn == NULL) || (conn->inner_conn == NULL)) {
01097     return MBEDTLS_ERR_NET_INVALID_CONTEXT;
01098   }
01099 
01100   while (size_left) {
01101     u16_t write_len = (u16_t)LWIP_MIN(size_left, 0xFFFF);
01102     err_t err = altcp_write (conn->inner_conn, (const void *)dataptr, write_len, apiflags);
01103     if (err == ERR_OK) {
01104       written += write_len;
01105       size_left -= write_len;
01106     } else if (err == ERR_MEM) {
01107       if (written) {
01108         return written;
01109       }
01110       return 0; /* MBEDTLS_ERR_SSL_WANT_WRITE; */
01111     } else {
01112       LWIP_ASSERT("tls_write, tcp_write: err != ERR MEM", 0);
01113       /* @todo: return MBEDTLS_ERR_NET_CONN_RESET or MBEDTLS_ERR_NET_SEND_FAILED */
01114       return MBEDTLS_ERR_NET_SEND_FAILED;
01115     }
01116   }
01117   return written;
01118 }
01119 
01120 static u16_t
01121 altcp_mbedtls_mss(struct altcp_pcb *conn)
01122 {
01123   if (conn == NULL) {
01124     return 0;
01125   }
01126   /* @todo: LWIP_MIN(mss, mbedtls_ssl_get_max_frag_len()) ? */
01127   return altcp_mss (conn->inner_conn);
01128 }
01129 
01130 static void
01131 altcp_mbedtls_dealloc(struct altcp_pcb *conn)
01132 {
01133   /* clean up and free tls state */
01134   if (conn) {
01135     altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state;
01136     if (state) {
01137       mbedtls_ssl_free(&state->ssl_context);
01138       state->flags = 0;
01139       if (state->rx) {
01140         /* free leftover (unhandled) rx pbufs */
01141         pbuf_free(state->rx);
01142         state->rx = NULL;
01143       }
01144       altcp_mbedtls_free(state->conf, state);
01145       conn->state = NULL;
01146     }
01147   }
01148 }
01149 
01150 const struct altcp_functions altcp_mbedtls_functions = {
01151   altcp_mbedtls_set_poll,
01152   altcp_mbedtls_recved,
01153   altcp_default_bind,
01154   altcp_mbedtls_connect,
01155   altcp_mbedtls_listen,
01156   altcp_mbedtls_abort,
01157   altcp_mbedtls_close,
01158   altcp_default_shutdown,
01159   altcp_mbedtls_write,
01160   altcp_default_output,
01161   altcp_mbedtls_mss,
01162   altcp_mbedtls_sndbuf,
01163   altcp_default_sndqueuelen,
01164   altcp_default_nagle_disable,
01165   altcp_default_nagle_enable,
01166   altcp_default_nagle_disabled,
01167   altcp_default_setprio,
01168   altcp_mbedtls_dealloc,
01169   altcp_default_get_tcp_addrinfo,
01170   altcp_default_get_ip,
01171   altcp_default_get_port
01172 #ifdef LWIP_DEBUG
01173   , altcp_default_dbg_get_tcp_state
01174 #endif
01175 };
01176 
01177 #endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */
01178 #endif /* LWIP_ALTCP */