aboutsummaryrefslogtreecommitdiff
path: root/lib/vtls/bearssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vtls/bearssl.c')
-rw-r--r--lib/vtls/bearssl.c286
1 files changed, 166 insertions, 120 deletions
diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c
index 44e7406e8..9b772d064 100644
--- a/lib/vtls/bearssl.c
+++ b/lib/vtls/bearssl.c
@@ -5,11 +5,11 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2019 - 2020, Michael Forney, <mforney@mforney.org>
+ * Copyright (C) 2019 - 2021, Michael Forney, <mforney@mforney.org>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
- * are also available at https://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
@@ -68,6 +68,14 @@ struct cafile_parser {
size_t dn_len;
};
+#define CAFILE_SOURCE_PATH 1
+#define CAFILE_SOURCE_BLOB 2
+struct cafile_source {
+ const int type;
+ const char * const data;
+ const size_t len;
+};
+
static void append_dn(void *ctx, const void *buf, size_t len)
{
struct cafile_parser *ca = ctx;
@@ -90,7 +98,8 @@ static void x509_push(void *ctx, const void *buf, size_t len)
br_x509_decoder_push(&ca->xc, buf, len);
}
-static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
+static CURLcode load_cafile(struct cafile_source *source,
+ br_x509_trust_anchor **anchors,
size_t *anchors_len)
{
struct cafile_parser ca;
@@ -100,13 +109,22 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
br_x509_trust_anchor *new_anchors;
size_t new_anchors_len;
br_x509_pkey *pkey;
- FILE *fp;
- unsigned char buf[BUFSIZ], *p;
+ FILE *fp = 0;
+ unsigned char buf[BUFSIZ];
+ const unsigned char *p;
const char *name;
size_t n, i, pushed;
- fp = fopen(path, "rb");
- if(!fp)
+ DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
+ || source->type == CAFILE_SOURCE_BLOB);
+
+ if(source->type == CAFILE_SOURCE_PATH) {
+ fp = fopen(source->data, "rb");
+ if(!fp)
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX)
return CURLE_SSL_CACERT_BADFILE;
ca.err = CURLE_OK;
@@ -115,11 +133,17 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
ca.anchors_len = 0;
br_pem_decoder_init(&pc);
br_pem_decoder_setdest(&pc, x509_push, &ca);
- for(;;) {
- n = fread(buf, 1, sizeof(buf), fp);
- if(n == 0)
- break;
- p = buf;
+ do {
+ if(source->type == CAFILE_SOURCE_PATH) {
+ n = fread(buf, 1, sizeof(buf), fp);
+ if(n == 0)
+ break;
+ p = buf;
+ }
+ else if(source->type == CAFILE_SOURCE_BLOB) {
+ n = source->len;
+ p = (unsigned char *) source->data;
+ }
while(n) {
pushed = br_pem_decoder_push(&pc, p, n);
if(ca.err)
@@ -211,12 +235,13 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
goto fail;
}
}
- }
- if(ferror(fp))
+ } while(source->type != CAFILE_SOURCE_BLOB);
+ if(fp && ferror(fp))
ca.err = CURLE_READ_ERROR;
fail:
- fclose(fp);
+ if(fp)
+ fclose(fp);
if(ca.err == CURLE_OK) {
*anchors = ca.anchors;
*anchors_len = ca.anchors_len;
@@ -294,18 +319,16 @@ static const br_x509_class x509_vtable = {
x509_get_pkey
};
-static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step1(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex)
{
- struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
- const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
-#ifndef CURL_DISABLE_PROXY
- const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- const char *hostname = conn->host.name;
-#endif
+ const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
+ const char *hostname = SSL_HOST_NAME();
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
CURLcode ret;
@@ -345,16 +368,38 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}
+ if(ca_info_blob) {
+ struct cafile_source source = {
+ CAFILE_SOURCE_BLOB,
+ ca_info_blob->data,
+ ca_info_blob->len,
+ };
+ ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
+ if(ret != CURLE_OK) {
+ if(verifypeer) {
+ failf(data, "error importing CA certificate blob");
+ return ret;
+ }
+ /* Only warn if no certificate verification is required. */
+ infof(data, "error importing CA certificate blob, continuing anyway");
+ }
+ }
+
if(ssl_cafile) {
- ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len);
+ struct cafile_source source = {
+ CAFILE_SOURCE_PATH,
+ ssl_cafile,
+ 0,
+ };
+ ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
if(ret != CURLE_OK) {
if(verifypeer) {
- failf(data, "error setting certificate verify locations:\n"
- " CAfile: %s\n", ssl_cafile);
+ failf(data, "error setting certificate verify locations."
+ " CAfile: %s", ssl_cafile);
return ret;
}
infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
+ " continuing anyway:");
}
}
@@ -374,12 +419,13 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
if(SSL_SET_OPTION(primary.sessionid)) {
void *session;
- Curl_ssl_sessionid_lock(conn);
- if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) {
+ Curl_ssl_sessionid_lock(data);
+ if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
+ &session, NULL, sockindex)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
- infof(data, "BearSSL: re-using session ID\n");
+ infof(data, "BearSSL: re-using session ID");
}
- Curl_ssl_sessionid_unlock(conn);
+ Curl_ssl_sessionid_unlock(data);
}
if(conn->bits.tls_enable_alpn) {
@@ -389,19 +435,19 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
* protocols array in `struct ssl_backend_data`.
*/
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif
) {
- backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ backend->protocols[cur++] = ALPN_H2;
+ infof(data, "ALPN, offering %s", ALPN_H2);
}
#endif
backend->protocols[cur++] = ALPN_HTTP_1_1;
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
br_ssl_engine_set_protocol_names(&backend->ctx.eng,
backend->protocols, cur);
@@ -429,10 +475,10 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_OK;
}
-static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex,
+static CURLcode bearssl_run_until(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex,
unsigned target)
{
- struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
curl_socket_t sockfd = conn->sock[sockindex];
@@ -507,14 +553,15 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex,
}
}
-static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step2(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex)
{
- struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
CURLcode ret;
- ret = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+ ret = bearssl_run_until(data, conn, sockindex,
+ BR_SSL_SENDAPP | BR_SSL_RECVAPP);
if(ret == CURLE_AGAIN)
return CURLE_OK;
if(ret == CURLE_OK) {
@@ -527,9 +574,9 @@ static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex)
return ret;
}
-static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step3(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex)
{
- struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
CURLcode ret;
@@ -541,26 +588,27 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
if(protocol) {
- infof(data, "ALPN, server accepted to use %s\n", protocol);
+ infof(data, "ALPN, server accepted to use %s", protocol);
-#ifdef USE_NGHTTP2
- if(!strcmp(protocol, NGHTTP2_PROTO_VERSION_ID))
+#ifdef USE_HTTP2
+ if(!strcmp(protocol, ALPN_H2))
conn->negnpn = CURL_HTTP_VERSION_2;
else
#endif
if(!strcmp(protocol, ALPN_HTTP_1_1))
conn->negnpn = CURL_HTTP_VERSION_1_1;
else
- infof(data, "ALPN, unrecognized protocol %s\n", protocol);
- Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+ infof(data, "ALPN, unrecognized protocol %s", protocol);
+ Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
}
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
+ bool added = FALSE;
void *oldsession;
br_ssl_session_parameters *session;
@@ -568,14 +616,19 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
if(!session)
return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
- Curl_ssl_sessionid_lock(conn);
- incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex));
+ Curl_ssl_sessionid_lock(data);
+ incache = !(Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ &oldsession, NULL, sockindex));
if(incache)
- Curl_ssl_delsessionid(conn, oldsession);
- ret = Curl_ssl_addsessionid(conn, session, 0, sockindex);
- Curl_ssl_sessionid_unlock(conn);
- if(ret) {
+ Curl_ssl_delsessionid(data, oldsession);
+ ret = Curl_ssl_addsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ session, 0, sockindex, &added);
+ Curl_ssl_sessionid_unlock(data);
+ if(!added)
free(session);
+ if(ret) {
return CURLE_OUT_OF_MEMORY;
}
}
@@ -585,17 +638,17 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
return CURLE_OK;
}
-static ssize_t bearssl_send(struct connectdata *conn, int sockindex,
+static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t len, CURLcode *err)
{
- struct Curl_easy *data = conn->data;
+ struct connectdata *conn = data->conn;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
unsigned char *app;
size_t applen;
for(;;) {
- *err = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP);
+ *err = bearssl_run_until(data, conn, sockindex, BR_SSL_SENDAPP);
if (*err != CURLE_OK)
return -1;
app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
@@ -618,15 +671,16 @@ static ssize_t bearssl_send(struct connectdata *conn, int sockindex,
}
}
-static ssize_t bearssl_recv(struct connectdata *conn, int sockindex,
+static ssize_t bearssl_recv(struct Curl_easy *data, int sockindex,
char *buf, size_t len, CURLcode *err)
{
+ struct connectdata *conn = data->conn;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
unsigned char *app;
size_t applen;
- *err = bearssl_run_until(conn, sockindex, BR_SSL_RECVAPP);
+ *err = bearssl_run_until(data, conn, sockindex, BR_SSL_RECVAPP);
if(*err != CURLE_OK)
return -1;
app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
@@ -640,13 +694,13 @@ static ssize_t bearssl_recv(struct connectdata *conn, int sockindex,
return applen;
}
-static CURLcode bearssl_connect_common(struct connectdata *conn,
+static CURLcode bearssl_connect_common(struct Curl_easy *data,
+ struct connectdata *conn,
int sockindex,
bool nonblocking,
bool *done)
{
CURLcode ret;
- struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
timediff_t timeout_ms;
@@ -659,7 +713,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
}
if(ssl_connect_1 == connssl->connecting_state) {
- ret = bearssl_connect_step1(conn, sockindex);
+ ret = bearssl_connect_step1(data, conn, sockindex);
if(ret)
return ret;
}
@@ -712,7 +766,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- ret = bearssl_connect_step2(conn, sockindex);
+ ret = bearssl_connect_step2(data, conn, sockindex);
if(ret || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -721,7 +775,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
}
if(ssl_connect_3 == connssl->connecting_state) {
- ret = bearssl_connect_step3(conn, sockindex);
+ ret = bearssl_connect_step3(data, conn, sockindex);
if(ret)
return ret;
}
@@ -741,21 +795,21 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
-static size_t Curl_bearssl_version(char *buffer, size_t size)
+static size_t bearssl_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "BearSSL");
}
-static bool Curl_bearssl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool bearssl_data_pending(const struct connectdata *conn,
+ int connindex)
{
const struct ssl_connect_data *connssl = &conn->ssl[connindex];
struct ssl_backend_data *backend = connssl->backend;
return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
}
-static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM,
- unsigned char *entropy, size_t length)
+static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
+ unsigned char *entropy, size_t length)
{
static br_hmac_drbg_context ctx;
static bool seeded = FALSE;
@@ -774,12 +828,13 @@ static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM,
return CURLE_OK;
}
-static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex)
{
CURLcode ret;
bool done = FALSE;
- ret = bearssl_connect_common(conn, sockindex, FALSE, &done);
+ ret = bearssl_connect_common(data, conn, sockindex, FALSE, &done);
if(ret)
return ret;
@@ -788,20 +843,22 @@ static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex)
return CURLE_OK;
}
-static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode bearssl_connect_nonblocking(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex, bool *done)
{
- return bearssl_connect_common(conn, sockindex, TRUE, done);
+ return bearssl_connect_common(data, conn, sockindex, TRUE, done);
}
-static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
+static void *bearssl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
{
struct ssl_backend_data *backend = connssl->backend;
return &backend->ctx;
}
-static void Curl_bearssl_close(struct connectdata *conn, int sockindex)
+static void bearssl_close(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
@@ -809,35 +866,22 @@ static void Curl_bearssl_close(struct connectdata *conn, int sockindex)
if(backend->active) {
br_ssl_engine_close(&backend->ctx.eng);
- (void)bearssl_run_until(conn, sockindex, BR_SSL_CLOSED);
+ (void)bearssl_run_until(data, conn, sockindex, BR_SSL_CLOSED);
}
for(i = 0; i < backend->anchors_len; ++i)
free(backend->anchors[i].dn.data);
free(backend->anchors);
}
-static void Curl_bearssl_session_free(void *ptr)
+static void bearssl_session_free(void *ptr)
{
free(ptr);
}
-static CURLcode Curl_bearssl_md5sum(unsigned char *input,
- size_t inputlen,
- unsigned char *md5sum,
- size_t md5len UNUSED_PARAM)
-{
- br_md5_context ctx;
-
- br_md5_init(&ctx);
- br_md5_update(&ctx, input, inputlen);
- br_md5_out(&ctx, md5sum);
- return CURLE_OK;
-}
-
-static CURLcode Curl_bearssl_sha256sum(const unsigned char *input,
- size_t inputlen,
- unsigned char *sha256sum,
- size_t sha256len UNUSED_PARAM)
+static CURLcode bearssl_sha256sum(const unsigned char *input,
+ size_t inputlen,
+ unsigned char *sha256sum,
+ size_t sha256len UNUSED_PARAM)
{
br_sha256_context ctx;
@@ -848,30 +892,32 @@ static CURLcode Curl_bearssl_sha256sum(const unsigned char *input,
}
const struct Curl_ssl Curl_ssl_bearssl = {
- { CURLSSLBACKEND_BEARSSL, "bearssl" },
- 0,
+ { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
+ SSLSUPP_CAINFO_BLOB,
sizeof(struct ssl_backend_data),
- Curl_none_init,
- Curl_none_cleanup,
- Curl_bearssl_version,
- Curl_none_check_cxn,
- Curl_none_shutdown,
- Curl_bearssl_data_pending,
- Curl_bearssl_random,
- Curl_none_cert_status_request,
- Curl_bearssl_connect,
- Curl_bearssl_connect_nonblocking,
- Curl_bearssl_get_internals,
- Curl_bearssl_close,
- Curl_none_close_all,
- Curl_bearssl_session_free,
- Curl_none_set_engine,
- Curl_none_set_engine_default,
- Curl_none_engines_list,
- Curl_none_false_start,
- Curl_bearssl_md5sum,
- Curl_bearssl_sha256sum
+ Curl_none_init, /* init */
+ Curl_none_cleanup, /* cleanup */
+ bearssl_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_none_shutdown, /* shutdown */
+ bearssl_data_pending, /* data_pending */
+ bearssl_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ bearssl_connect, /* connect */
+ bearssl_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
+ bearssl_get_internals, /* get_internals */
+ bearssl_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ bearssl_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ bearssl_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_BEARSSL */