#if !defined(__MBEDTLS_SOCKET_TEMPLATE_H__) #define __MBEDTLS_SOCKET_TEMPLATE_H__ #include #include #include #include #include #include #include #include #include #include #include #if !defined(MBEDTLS_NET_POLL_READ) /* compat for older mbedtls */ #define MBEDTLS_NET_POLL_READ 1 #define MBEDTLS_NET_POLL_WRITE 1 int mbedtls_net_poll(mbedtls_net_context * ctx, uint32_t rw, uint32_t timeout) { /* XXX this is not ideal but good enough for an example */ usleep(300); return 1; } #endif struct mbedtls_context { mbedtls_net_context net_ctx; mbedtls_ssl_context ssl_ctx; mbedtls_ssl_config ssl_conf; mbedtls_x509_crt ca_crt; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; }; UA_StatusCode failed(const char *fn, int rv); UA_StatusCode cert_verify_failed(uint32_t rv); UA_StatusCode open_nb_socket(struct mbedtls_context *ctx, const char *hostname, const char *port, const char *ca_file); UA_StatusCode failed(const char *fn, int rv) { char buf[100]; mbedtls_strerror(rv, buf, sizeof(buf)); UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "MQTT PubSub: %s failed with %x %s", fn, -rv, buf); return UA_STATUSCODE_BADINTERNALERROR; } UA_StatusCode cert_verify_failed(uint32_t rv) { char buf[512]; mbedtls_x509_crt_verify_info(buf, sizeof(buf), "\t", rv); UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "MQTT PubSub: Certificate verification failed (%x) %s", rv, buf); return UA_STATUSCODE_BADINTERNALERROR; } /* A template for opening a non-blocking mbed TLS connection. */ UA_StatusCode open_nb_socket(struct mbedtls_context *ctx, const char *hostname, const char *port, const char *ca_file) { const unsigned char *additional = (const unsigned char *)"MQTT-C"; size_t additional_len = 6; int rv; mbedtls_net_context *net_ctx = &ctx->net_ctx; mbedtls_ssl_context *ssl_ctx = &ctx->ssl_ctx; mbedtls_ssl_config *ssl_conf = &ctx->ssl_conf; mbedtls_x509_crt *ca_crt = &ctx->ca_crt; mbedtls_entropy_context *entropy = &ctx->entropy; mbedtls_ctr_drbg_context *ctr_drbg = &ctx->ctr_drbg; mbedtls_entropy_init(entropy); mbedtls_ctr_drbg_init(ctr_drbg); rv = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, additional, additional_len); if (rv != 0) { return failed("mbedtls_ctr_drbg_seed", rv); } mbedtls_x509_crt_init(ca_crt); rv = mbedtls_x509_crt_parse_file(ca_crt, ca_file); if (rv != 0) { return failed("mbedtls_x509_crt_parse_file", rv); } mbedtls_ssl_config_init(ssl_conf); rv = mbedtls_ssl_config_defaults(ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (rv != 0) { return failed("mbedtls_ssl_config_defaults", rv); } mbedtls_ssl_conf_ca_chain(ssl_conf, ca_crt, NULL); mbedtls_ssl_conf_authmode(ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_rng(ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg); mbedtls_net_init(net_ctx); rv = mbedtls_net_connect(net_ctx, hostname, port, MBEDTLS_NET_PROTO_TCP); if (rv != 0) { return failed("mbedtls_net_connect", rv); } rv = mbedtls_net_set_nonblock(net_ctx); if (rv != 0) { return failed("mbedtls_net_set_nonblock", rv); } mbedtls_ssl_init(ssl_ctx); rv = mbedtls_ssl_setup(ssl_ctx, ssl_conf); if (rv != 0) { return failed("mbedtls_ssl_setup", rv); } rv = mbedtls_ssl_set_hostname(ssl_ctx, hostname); if (rv != 0) { return failed("mbedtls_ssl_set_hostname", rv); } mbedtls_ssl_set_bio(ssl_ctx, net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL); for (;;) { rv = mbedtls_ssl_handshake(ssl_ctx); uint32_t want = 0; if (rv == MBEDTLS_ERR_SSL_WANT_READ) { want |= MBEDTLS_NET_POLL_READ; } else if (rv == MBEDTLS_ERR_SSL_WANT_WRITE) { want |= MBEDTLS_NET_POLL_WRITE; } else { break; } rv = mbedtls_net_poll(net_ctx, want, (uint32_t)-1); if (rv < 0) { return failed("mbedtls_net_poll", rv); } } if (rv != 0) { return failed("mbedtls_ssl_handshake", rv); } uint32_t result = mbedtls_ssl_get_verify_result(ssl_ctx); if (result != 0) { if (result == (uint32_t)-1) { return failed("mbedtls_ssl_get_verify_result", (int)result); } else { cert_verify_failed(result); } } return UA_STATUSCODE_GOOD; } #endif