+typedef struct
+{
+ mbedtls_x509_crt crt;
+ mbedtls_pk_context key;
+ mbedtls_dhm_context dhp;
+ mbedtls_ssl_config server_cfg;
+ mbedtls_ssl_config client_cfg;
+ size_t refcount;
+} rb_mbedtls_cfg_context;
+
+typedef struct
+{
+ rb_mbedtls_cfg_context *cfg;
+ mbedtls_ssl_context ssl;
+} rb_mbedtls_ssl_context;
+
+#define SSL_C(x) ((rb_mbedtls_ssl_context *) (x)->ssl)->cfg
+#define SSL_P(x) &((rb_mbedtls_ssl_context *) (x)->ssl)->ssl
+
+static mbedtls_ctr_drbg_context ctr_drbg_ctx;
+static mbedtls_entropy_context entropy_ctx;
+
+static mbedtls_x509_crt dummy_ca_ctx;
+static rb_mbedtls_cfg_context *rb_mbedtls_cfg = NULL;
+
+static const char *
+rb_get_ssl_strerror_internal(int err)
+{
+ static char errbuf[512];
+
+#ifdef MBEDTLS_ERROR_C
+ char mbed_errbuf[512];
+ mbedtls_strerror(err, mbed_errbuf, sizeof mbed_errbuf);
+ snprintf(errbuf, sizeof errbuf, "(-0x%x) %s", -err, mbed_errbuf);
+#else
+ snprintf(errbuf, sizeof errbuf, "-0x%x", -err);
+#endif
+
+ return errbuf;
+}
+
+const char *
+rb_get_ssl_strerror(rb_fde_t *F)
+{
+ return rb_get_ssl_strerror_internal(F->ssl_errno);
+}
+
+static void rb_mbedtls_cfg_incref(rb_mbedtls_cfg_context *cfg)
+{
+ lrb_assert(cfg->refcount > 0);
+
+ cfg->refcount++;
+}
+
+static void rb_mbedtls_cfg_decref(rb_mbedtls_cfg_context *cfg)
+{
+ if(cfg == NULL)
+ return;
+
+ lrb_assert(cfg->refcount > 0);
+
+ if((--cfg->refcount) > 0)
+ return;
+
+ mbedtls_ssl_config_free(&cfg->client_cfg);
+ mbedtls_ssl_config_free(&cfg->server_cfg);
+ mbedtls_dhm_free(&cfg->dhp);
+ mbedtls_pk_free(&cfg->key);
+ mbedtls_x509_crt_free(&cfg->crt);
+
+ rb_free(cfg);
+}
+
+static rb_mbedtls_cfg_context *rb_mbedtls_cfg_new(void)
+{
+ rb_mbedtls_cfg_context *cfg;
+ int ret;
+
+ if((cfg = rb_malloc(sizeof(rb_mbedtls_cfg_context))) == NULL)
+ return NULL;
+
+ mbedtls_x509_crt_init(&cfg->crt);
+ mbedtls_pk_init(&cfg->key);
+ mbedtls_dhm_init(&cfg->dhp);
+ mbedtls_ssl_config_init(&cfg->server_cfg);
+ mbedtls_ssl_config_init(&cfg->client_cfg);
+
+ cfg->refcount = 1;
+
+ if((ret = mbedtls_ssl_config_defaults(&cfg->server_cfg,
+ MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
+ {
+ rb_lib_log("rb_mbedtls_cfg_new: ssl_config_defaults (server): %s",
+ rb_get_ssl_strerror_internal(ret));
+ rb_mbedtls_cfg_decref(cfg);
+ return NULL;
+ }
+
+ if((ret = mbedtls_ssl_config_defaults(&cfg->client_cfg,
+ MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
+ {
+ rb_lib_log("rb_mbedtls_cfg_new: ssl_config_defaults (client): %s",
+ rb_get_ssl_strerror_internal(ret));
+ rb_mbedtls_cfg_decref(cfg);
+ return NULL;
+ }
+
+ mbedtls_ssl_conf_rng(&cfg->server_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx);
+ mbedtls_ssl_conf_rng(&cfg->client_cfg, mbedtls_ctr_drbg_random, &ctr_drbg_ctx);
+
+ mbedtls_ssl_conf_ca_chain(&cfg->server_cfg, &dummy_ca_ctx, NULL);
+ mbedtls_ssl_conf_ca_chain(&cfg->client_cfg, &dummy_ca_ctx, NULL);
+
+ mbedtls_ssl_conf_authmode(&cfg->server_cfg, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ mbedtls_ssl_conf_authmode(&cfg->client_cfg, MBEDTLS_SSL_VERIFY_NONE);
+
+ return cfg;
+}