Prepare altcp_tls_mbedtls for TLS clients (not fully tested yet)

This commit is contained in:
goldsimon 2017-03-24 15:25:43 +01:00
parent 540b527cf4
commit 0581a77731
3 changed files with 120 additions and 50 deletions

View File

@ -106,9 +106,11 @@ struct altcp_tls_config
#endif
};
static err_t altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err);
static err_t altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn);
static void altcp_mbedtls_dealloc(struct altcp_pcb *conn);
static err_t altcp_mbedtls_handle_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state);
static err_t altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state);
static err_t altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state);
static int altcp_mbedtls_bio_send(void* ctx, const unsigned char* dataptr, size_t size);
@ -148,13 +150,19 @@ static err_t
altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err)
{
struct altcp_pcb *conn = (struct altcp_pcb *)arg;
if (conn) {
if (conn && conn->state) {
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
/* upper connected is called when handshake is done */
LWIP_UNUSED_ARG(err);
LWIP_ASSERT("TODO: implement active connect", 0);
if (err != ERR_OK) {
if (conn->connected) {
if (conn->connected(conn->arg, conn, err) == ERR_ABRT) {
return ERR_ABRT;
}
return ERR_OK;
}
}
return altcp_mbedtls_lower_recv_process(conn, (altcp_mbedtls_state_t*)conn->state);
}
return ERR_VAL;
}
@ -203,29 +211,34 @@ altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p
if (p == NULL) {
/* remote host sent FIN, remember this (SSL state is destroyed
when both sides are closed only!) */
state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED;
state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED;
}
if (state->flags & ALTCP_MBEDTLS_FLAGS_UPPER_CALLED) {
if ((state->flags & (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE|ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) ==
(ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE|ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) {
/* need to notify upper layer (e.g. 'accept' called or 'connect' succeeded) */
if ((err == ERR_OK) && ((state->rx != NULL) || (state->rx_app != NULL))) {
LWIP_ASSERT("p == NULL", p == NULL);
/* this is a normal close (FIN) but we have unprocessed data */
altcp_mbedtls_handle_rx_appldata(conn, state);
return ERR_OK;
}
if (conn->recv) {
local_err = conn->recv(conn->arg, conn, p, err);
} else {
/* no recv callback? close connection */
if (p) {
if ((local_err != ERR_OK) && (p != NULL)) {
pbuf_free(p);
}
altcp_close(conn);
p = NULL;
}
} else {
/* before connection setup is done: call 'err' */
if (p) {
pbuf_free(p);
}
if (conn->err) {
conn->err(conn->arg, ERR_CLSD);
}
altcp_close(conn);
}
if (p) {
pbuf_free(p);
}
altcp_close(conn);
if (conn->state && ((state->flags & ALTCP_MBEDTLS_FLAGS_CLOSED) == ALTCP_MBEDTLS_FLAGS_CLOSED)) {
altcp_mbedtls_dealloc(conn);
}
@ -240,7 +253,12 @@ altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p
LWIP_ASSERT("rx pbuf overflow", (int)p->tot_len + (int)p->len <= 0xFFFF);
pbuf_cat(state->rx, p);
}
return altcp_mbedtls_lower_recv_process(conn, state);
}
static err_t
altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
{
if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) {
/* handle connection setup (handshake not done) */
int ret = mbedtls_ssl_handshake(&state->ssl_context);
@ -248,7 +266,7 @@ altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p
altcp_output(conn->inner_conn);
if (state->bio_bytes_read) {
/* acknowledge all bytes read */
altcp_mbedtls_lower_recved(inner_conn, state->bio_bytes_read);
altcp_mbedtls_lower_recved(conn->inner_conn, state->bio_bytes_read);
state->bio_bytes_read = 0;
}
@ -276,7 +294,7 @@ altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p
return ERR_OK;
} else {
/* handle application data */
return altcp_mbedtls_handle_rx_data(conn, state);
return altcp_mbedtls_handle_rx_appldata(conn, state);
}
}
@ -284,6 +302,7 @@ altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p
static err_t
altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
{
err_t err;
struct pbuf *buf;
LWIP_ASSERT("conn != NULL", conn != NULL);
LWIP_ASSERT("state != NULL", state != NULL);
@ -291,9 +310,9 @@ altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
if (buf) {
if (conn->recv) {
u16_t tot_len = state->rx_app->tot_len;
err_t err;
/* this needs to be increased first because the 'recved' call may come nested */
state->rx_passed_unrecved += tot_len;
state->flags |= ALTCP_MBEDTLS_FLAGS_UPPER_CALLED;
err = conn->recv(conn->arg, conn, state->rx_app, ERR_OK);
if (err != ERR_OK) {
/* not received, leave the pbuf(s) queued (and decrease 'unrecved' again) */
@ -308,13 +327,23 @@ altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
pbuf_free(buf);
}
state->rx_app = NULL;
} else if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED|ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) ==
ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) {
state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED;
if (conn->recv) {
err = conn->recv(conn->arg, conn, NULL, ERR_OK);
if (err == ERR_ABRT) {
return ERR_ABRT;
}
}
}
return ERR_OK;
}
/* Helper function that processes rx application data stored in rx pbuf chain */
static err_t
altcp_mbedtls_handle_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state)
{
int ret;
LWIP_ASSERT("state != NULL", state != NULL);
@ -355,6 +384,7 @@ altcp_mbedtls_handle_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *stat
return ERR_ABRT;
} else {
err_t err;
if (ret) {
LWIP_ASSERT("bogus receive length", ret <= PBUF_POOL_BUFSIZE);
/* trim pool pbuf to actually decoded length */
pbuf_realloc(buf, (uint16_t)ret);
@ -377,6 +407,10 @@ altcp_mbedtls_handle_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *stat
} else {
pbuf_cat(state->rx_app, buf);
}
} else {
pbuf_free(buf);
buf = NULL;
}
err = altcp_mbedtls_pass_rx_data(conn, state);
if (err != ERR_OK) {
if (err == ERR_ABRT) {
@ -410,7 +444,16 @@ altcp_mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len)
}
p = state->rx;
if (p == NULL) {
if ((p == NULL) || ((p->len == 0) && (p->next == NULL))) {
if (p) {
pbuf_free(p);
}
state->rx = NULL;
if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED|ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) ==
ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) {
/* close queued but not passed up yet */
return 0;
}
return MBEDTLS_ERR_SSL_WANT_READ;
}
/* limit number of bytes to copy to fit into an s16_t for pbuf_header */
@ -470,7 +513,7 @@ altcp_mbedtls_lower_poll(void *arg, struct altcp_pcb *inner_conn)
LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
/* check if there's unreceived rx data */
if (conn->state) {
altcp_mbedtls_handle_rx_data(conn, (altcp_mbedtls_state_t *)conn->state);
altcp_mbedtls_handle_rx_appldata(conn, (altcp_mbedtls_state_t *)conn->state);
}
if (conn->poll) {
return conn->poll(conn->arg, conn);
@ -585,8 +628,8 @@ dummy_rng(void *ctx, unsigned char *buffer , size_t len)
/** Create new TLS configuration
* ATTENTION: Server certificate and private key have to be added outside this function!
*/
struct altcp_tls_config*
altcp_tls_create_config(void)
static struct altcp_tls_config *
altcp_tls_create_config(int is_server)
{
int ret;
struct altcp_tls_config *conf;
@ -611,13 +654,14 @@ altcp_tls_create_config(void)
}
/* Setup ssl context (@todo: what's different for a client here? -> might better be done on listen/connect) */
ret = mbedtls_ssl_config_defaults(&conf->conf, MBEDTLS_SSL_IS_SERVER,
ret = mbedtls_ssl_config_defaults(&conf->conf, is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret != 0) {
LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_config_defaults failed: %d", ret));
altcp_mbedtls_free_config(conf);
return NULL;
}
mbedtls_ssl_conf_authmode(&conf->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &conf->ctr_drbg);
#if ALTCP_MBEDTLS_DEBUG != LWIP_DBG_OFF
@ -636,15 +680,15 @@ altcp_tls_create_config(void)
* This is a suboptimal version that gets the encrypted private key and its password,
* as well as the server certificate.
*/
struct altcp_tls_config*
altcp_tls_create_config_privkey_cert(const u8_t *privkey, size_t privkey_len,
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)
{
int ret;
static mbedtls_x509_crt srvcert;
static mbedtls_pk_context pkey;
struct altcp_tls_config *conf = altcp_tls_create_config();
struct altcp_tls_config *conf = altcp_tls_create_config(1);
if (conf == NULL) {
return NULL;
}
@ -677,6 +721,30 @@ altcp_tls_create_config_privkey_cert(const u8_t *privkey, size_t privkey_len,
return conf;
}
struct altcp_tls_config *
altcp_tls_create_config_client(const u8_t *cert, size_t cert_len)
{
int ret;
static mbedtls_x509_crt acc_cert;
struct altcp_tls_config *conf = altcp_tls_create_config(0);
if (conf == NULL) {
return NULL;
}
mbedtls_x509_crt_init(&acc_cert);
/* Load the certificates */
ret = mbedtls_x509_crt_parse(&acc_cert, cert, cert_len);
if (ret != 0) {
LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse failed: %d", ret));
altcp_mbedtls_free_config(conf);
return NULL;
}
mbedtls_ssl_conf_ca_chain(&conf->conf, &acc_cert, NULL);
return conf;
}
/* "virtual" functions */
static void
altcp_mbedtls_set_poll(struct altcp_pcb *conn, u8_t interval)

View File

@ -54,10 +54,11 @@ extern "C" {
#define ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE 0x01
#define ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT 0x02
#define ALTCP_MBEDTLS_FLAGS_RX_CLOSED 0x04
#define ALTCP_MBEDTLS_FLAGS_TX_CLOSED 0x08
#define ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED 0x04
#define ALTCP_MBEDTLS_FLAGS_RX_CLOSED 0x08
#define ALTCP_MBEDTLS_FLAGS_TX_CLOSED 0x10
#define ALTCP_MBEDTLS_FLAGS_CLOSED (ALTCP_MBEDTLS_FLAGS_RX_CLOSED|ALTCP_MBEDTLS_FLAGS_TX_CLOSED)
#define ALTCP_MBEDTLS_FLAGS_UPPER_CALLED 0x10
#define ALTCP_MBEDTLS_FLAGS_UPPER_CALLED 0x20
typedef struct altcp_mbedtls_state_s {
void *conf;

View File

@ -55,10 +55,11 @@ extern "C" {
struct altcp_tls_config;
struct altcp_tls_config* altcp_tls_create_config(void);
struct altcp_tls_config* altcp_tls_create_config_privkey_cert(const u8_t *privkey, size_t privkey_len,
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);
struct altcp_tls_config *altcp_tls_create_config_client(const u8_t *cert, size_t cert_len);
struct altcp_pcb *altcp_tls_new(struct altcp_tls_config* config, struct altcp_pcb *inner_pcb);
#ifdef __cplusplus