From 141c345b75bb69973a2fb756edb87cfd727d9457 Mon Sep 17 00:00:00 2001 From: Flander Bojan Date: Mon, 24 Oct 2022 10:52:03 +0000 Subject: [PATCH] Add TLS support --- lib/sbi/client.c | 3 + lib/sbi/client.h | 1 + lib/sbi/context.c | 1 + lib/sbi/conv.c | 2 + lib/sbi/meson.build | 6 ++ lib/sbi/nghttp2-server.c | 119 ++++++++++++++++++++++++++++++++++++++- lib/sbi/server.h | 5 ++ 7 files changed, 135 insertions(+), 2 deletions(-) diff --git a/lib/sbi/client.c b/lib/sbi/client.c index 8c45a097b..d51703170 100644 --- a/lib/sbi/client.c +++ b/lib/sbi/client.c @@ -372,6 +372,9 @@ static connection_t *connection_add( request->h.uri = uri; } + curl_easy_setopt(conn->easy, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(conn->easy, CURLOPT_SSL_VERIFYHOST, 0); + /* HTTP Method */ if (strcmp(request->h.method, OGS_SBI_HTTP_METHOD_PUT) == 0 || strcmp(request->h.method, OGS_SBI_HTTP_METHOD_PATCH) == 0 || diff --git a/lib/sbi/client.h b/lib/sbi/client.h index a49da977c..889d50bb3 100644 --- a/lib/sbi/client.h +++ b/lib/sbi/client.h @@ -56,6 +56,7 @@ typedef int (*ogs_sbi_client_cb_f)( typedef struct ogs_sbi_client_s { ogs_socknode_t node; + OpenAPI_uri_scheme_e scheme; struct { const char *key; diff --git a/lib/sbi/context.c b/lib/sbi/context.c index 6213c01a7..e3553b99e 100644 --- a/lib/sbi/context.c +++ b/lib/sbi/context.c @@ -1473,6 +1473,7 @@ static void nf_service_associate_client(ogs_sbi_nf_service_t *nf_service) client = ogs_sbi_client_find(addr); if (!client) { client = ogs_sbi_client_add(addr); + client->scheme = nf_service->scheme; ogs_assert(client); } } diff --git a/lib/sbi/conv.c b/lib/sbi/conv.c index 64fac328a..eb54cf829 100644 --- a/lib/sbi/conv.c +++ b/lib/sbi/conv.c @@ -103,6 +103,8 @@ char *ogs_sbi_client_uri(ogs_sbi_client_t *client, ogs_sbi_header_t *h) if (client->tls.key && client->tls.pem) https = true; + else if (client->scheme == OpenAPI_uri_scheme_https) + https = true; return ogs_uridup(https, client->node.addr, h); } diff --git a/lib/sbi/meson.build b/lib/sbi/meson.build index 3b160dab2..d8e2239f7 100644 --- a/lib/sbi/meson.build +++ b/lib/sbi/meson.build @@ -52,6 +52,8 @@ libsbi_inc = include_directories('.') sbi_cc_flags = ['-DOGS_SBI_COMPILATION'] libgnutls_dep = cc.find_library('gnutls', required : true) +libssl_dep = cc.find_library('ssl', required : true) +libcrypto_dep = cc.find_library('crypto', required : true) libnghttp2_dep = dependency('libnghttp2', version: '>=1.18.1') libmicrohttpd_dep = dependency('libmicrohttpd', version: '>=0.9.40') libcurl_dep = dependency('libcurl', version: '>=7.52.1') @@ -65,6 +67,8 @@ libsbi = library('ogssbi', libapp_dep, libsbi_openapi_dep, libgnutls_dep, + libssl_dep, + libcrypto_dep, libnghttp2_dep, libmicrohttpd_dep, libcurl_dep], @@ -78,6 +82,8 @@ libsbi_dep = declare_dependency( libapp_dep, libsbi_openapi_dep, libgnutls_dep, + libssl_dep, + libcrypto_dep, libnghttp2_dep, libmicrohttpd_dep, libcurl_dep]) diff --git a/lib/sbi/nghttp2-server.c b/lib/sbi/nghttp2-server.c index 9c6fc4248..895d31bd6 100644 --- a/lib/sbi/nghttp2-server.c +++ b/lib/sbi/nghttp2-server.c @@ -75,6 +75,7 @@ typedef struct ogs_sbi_session_s { int32_t last_stream_id; struct h2_settings settings; + SSL* ssl; } ogs_sbi_session_t; typedef struct ogs_sbi_stream_s { @@ -116,6 +117,78 @@ static void server_final(void) ogs_pool_final(&session_pool); } +#ifndef OPENSSL_NO_NEXTPROTONEG +static int next_proto_cb(SSL *ssl, const unsigned char **data, + unsigned int *len, void *arg) { + static unsigned char next_proto_list[256]; + (void)ssl; + (void)arg; + + next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN; + memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN); + + *data = next_proto_list; + *len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN; + return SSL_TLSEXT_ERR_OK; +} +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) { + int rv; + (void)ssl; + (void)arg; + + rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen); + if (rv != 1) { + return SSL_TLSEXT_ERR_NOACK; + } + + return SSL_TLSEXT_ERR_OK; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ + +static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) { + SSL_CTX *ssl_ctx; + + ssl_ctx = SSL_CTX_new(TLS_server_method()); + if (!ssl_ctx) { + ogs_error("Could not create SSL/TLS context: %s", ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } + SSL_CTX_set_options(ssl_ctx, + SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_NO_COMPRESSION | + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) { + ogs_error("SSL_CTX_set1_curves_list failed: %s", ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } +#endif /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */ + + if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { + ogs_error("Could not read private key file - key_file=%s", key_file); + return NULL; + } + if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) { + ogs_error("Could not read certificate file - cert_file=%s ", cert_file); + return NULL; + } + +#ifndef OPENSSL_NO_NEXTPROTONEG + SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL); +#endif /* !OPENSSL_NO_NEXTPROTONEG */ + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL); +#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ + + return ssl_ctx; +} + static int server_start(ogs_sbi_server_t *server, int (*cb)(ogs_sbi_request_t *request, void *data)) { @@ -127,6 +200,15 @@ static int server_start(ogs_sbi_server_t *server, addr = server->node.addr; ogs_assert(addr); + /* Create SSL CTX */ + if (server->tls.key && server->tls.pem) { + server->ssl_ctx = create_ssl_ctx(server->tls.key, server->tls.pem); + if (!server->ssl_ctx) { + ogs_error("Cannot create SSL CTX"); + return OGS_ERROR; + } + } + sock = ogs_tcp_server(addr, server->node.option); if (!sock) { ogs_error("Cannot start SBI server"); @@ -157,6 +239,10 @@ static void server_stop(ogs_sbi_server_t *server) { ogs_assert(server); + /* Free SSL CTX */ + if (server->ssl_ctx) + SSL_CTX_free(server->ssl_ctx); + if (server->node.poll) ogs_pollset_remove(server->node.poll); @@ -485,6 +571,11 @@ static ogs_sbi_session_t *session_add( ogs_expect_or_return_val(sbi_sess->addr, NULL); memcpy(sbi_sess->addr, &sock->remote_addr, sizeof(ogs_sockaddr_t)); + if (server->ssl_ctx) { + sbi_sess->ssl = SSL_new(server->ssl_ctx); + ogs_expect_or_return_val(sbi_sess->ssl, NULL); + } + ogs_list_add(&server->session_list, sbi_sess); return sbi_sess; @@ -501,6 +592,9 @@ static void session_remove(ogs_sbi_session_t *sbi_sess) ogs_list_remove(&server->session_list, sbi_sess); + if (sbi_sess->ssl) + SSL_free(sbi_sess->ssl); + stream_remove_all(sbi_sess); nghttp2_session_del(sbi_sess->session); @@ -566,6 +660,19 @@ static void accept_handler(short when, ogs_socket_t fd, void *data) sbi_sess = session_add(server, new); ogs_assert(sbi_sess); + if (sbi_sess->ssl) { + int err ; + SSL_set_fd(sbi_sess->ssl, new->fd); + SSL_set_accept_state(sbi_sess->ssl); + err = SSL_accept(sbi_sess->ssl); + if (err <= 0) { + ogs_error("SSL_accept failed: %s", ERR_error_string(ERR_get_error(), NULL)); + ogs_sock_destroy(new); + session_remove(sbi_sess); + return; + } + } + sbi_sess->poll.read = ogs_pollset_add(ogs_app()->pollset, OGS_POLLIN, new->fd, recv_handler, sbi_sess); ogs_assert(sbi_sess->poll.read); @@ -595,7 +702,11 @@ static void recv_handler(short when, ogs_socket_t fd, void *data) pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); ogs_assert(pkbuf); - n = ogs_recv(fd, pkbuf->data, OGS_MAX_SDU_LEN, 0); + if (sbi_sess->ssl) + n = SSL_read(sbi_sess->ssl, pkbuf->data, OGS_MAX_SDU_LEN); + else + n = ogs_recv(fd, pkbuf->data, OGS_MAX_SDU_LEN, 0); + if (n > 0) { ogs_pkbuf_put(pkbuf, n); @@ -1294,7 +1405,11 @@ static void session_write_callback(short when, ogs_socket_t fd, void *data) ogs_assert(pkbuf); ogs_list_remove(&sbi_sess->write_queue, pkbuf); - ogs_send(fd, pkbuf->data, pkbuf->len, 0); + if (sbi_sess->ssl) + SSL_write(sbi_sess->ssl, pkbuf->data, pkbuf->len); + else + ogs_send(fd, pkbuf->data, pkbuf->len, 0); + ogs_log_hexdump(OGS_LOG_DEBUG, pkbuf->data, pkbuf->len); ogs_pkbuf_free(pkbuf); diff --git a/lib/sbi/server.h b/lib/sbi/server.h index 4820b2cad..45a4efccb 100644 --- a/lib/sbi/server.h +++ b/lib/sbi/server.h @@ -28,6 +28,9 @@ extern "C" { #endif +#include +#include + typedef struct ogs_sbi_stream_s ogs_sbi_stream_t; typedef struct ogs_sbi_server_s { @@ -39,6 +42,8 @@ typedef struct ogs_sbi_server_s { const char *pem; } tls; + SSL_CTX *ssl_ctx; + int (*cb)(ogs_sbi_request_t *request, void *data); ogs_list_t session_list;