diff --git a/include/fluent-bit/tls/flb_tls.h b/include/fluent-bit/tls/flb_tls.h index d463361ce12..70a865f15cf 100644 --- a/include/fluent-bit/tls/flb_tls.h +++ b/include/fluent-bit/tls/flb_tls.h @@ -72,6 +72,9 @@ struct flb_tls_backend { /* destroy backend context */ void (*context_destroy) (void *); + /* Additional settings */ + int (*context_alpn_set) (void *, const char *); + /* Session management */ void *(*session_create) (struct flb_tls *, int); int (*session_destroy) (void *); @@ -106,6 +109,9 @@ struct flb_tls *flb_tls_create(int mode, const char *key_file, const char *key_passwd); int flb_tls_destroy(struct flb_tls *tls); + +int flb_tls_set_alpn(struct flb_tls *tls, const char *alpn); + int flb_tls_load_system_certificates(struct flb_tls *tls); struct mk_list *flb_tls_get_config_map(struct flb_config *config); diff --git a/src/tls/flb_tls.c b/src/tls/flb_tls.c index 8fc711ab389..8510381a850 100644 --- a/src/tls/flb_tls.c +++ b/src/tls/flb_tls.c @@ -222,6 +222,16 @@ int flb_tls_destroy(struct flb_tls *tls) return 0; } +int flb_tls_set_alpn(struct flb_tls *tls, const char *alpn) +{ + if (tls->ctx) { + return tls->api->context_alpn_set(tls->ctx, alpn); + } + + return 0; +} + + int flb_tls_net_read(struct flb_tls_session *session, void *buf, size_t len) { time_t timeout_timestamp; diff --git a/src/tls/openssl.c b/src/tls/openssl.c index 341cf698bbf..f53f7201a86 100644 --- a/src/tls/openssl.c +++ b/src/tls/openssl.c @@ -39,6 +39,7 @@ struct tls_context { int debug_level; SSL_CTX *ctx; int mode; + char *alpn; pthread_mutex_t mutex; }; @@ -122,11 +123,113 @@ static void tls_context_destroy(void *ctx_backend) pthread_mutex_lock(&ctx->mutex); SSL_CTX_free(ctx->ctx); + if (ctx->alpn != NULL) { + flb_free(ctx->alpn); + } pthread_mutex_unlock(&ctx->mutex); flb_free(ctx); } +int tls_context_alpn_set(void *ctx_backend, const char *alpn) +{ + size_t wire_format_alpn_index; + char *alpn_token_context; + char *alpn_working_copy; + char *wire_format_alpn; + char *alpn_token; + int result; + struct tls_context *ctx; + + ctx = (struct tls_context *) ctx_backend; + + result = 0; + + if (alpn != NULL) { + wire_format_alpn = flb_calloc(strlen(alpn), + sizeof(char) + 1); + + if (wire_format_alpn == NULL) { + return -1; + } + + alpn_working_copy = strdup(alpn); + + if (alpn_working_copy == NULL) { + flb_free(wire_format_alpn); + + return -1; + } + + wire_format_alpn_index = 1; + alpn_token_context = NULL; + + alpn_token = strtok_r(alpn_working_copy, + ",", + &alpn_token_context); + + while (alpn_token != NULL) { + wire_format_alpn[wire_format_alpn_index] = \ + (char) strlen(alpn_token); + + strcpy(&wire_format_alpn[wire_format_alpn_index + 1], + alpn_token); + + wire_format_alpn_index += strlen(alpn_token) + 1; + + alpn_token = strtok_r(NULL, + ",", + &alpn_token_context); + } + + if (wire_format_alpn_index > 1) { + wire_format_alpn[0] = (char) wire_format_alpn_index - 1; + ctx->alpn = wire_format_alpn; + } + + free(alpn_working_copy); + } + + if (result != 0) { + result = -1; + } + + return result; +} + +static int tls_context_server_alpn_select_callback(SSL *ssl, + unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg) +{ + int result; + struct tls_context *ctx; + + ctx = (struct tls_context *) arg; + + result = SSL_TLSEXT_ERR_NOACK; + + if (ctx->alpn != NULL) { + result = SSL_select_next_proto(out, + outlen, + &ctx->alpn[1], + (unsigned int) ctx->alpn[0], + in, + inlen); + + if (result == OPENSSL_NPN_NEGOTIATED) { + result = SSL_TLSEXT_ERR_OK; + } + else if (result == OPENSSL_NPN_NO_OVERLAP) { + result = SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + + return result; +} + #ifdef _MSC_VER static int windows_load_system_certificates(struct tls_context *ctx) { @@ -196,7 +299,7 @@ static int load_system_certificates(struct tls_context *ctx) } return 0; } - + static void *tls_context_create(int verify, int debug, int mode, @@ -242,6 +345,7 @@ static void *tls_context_create(int verify, ssl_ctx = SSL_CTX_new(TLS_client_method()); } #endif + if (!ssl_ctx) { flb_error("[openssl] could not create context"); return NULL; @@ -254,9 +358,16 @@ static void *tls_context_create(int verify, } ctx->ctx = ssl_ctx; ctx->mode = mode; + ctx->alpn = NULL; ctx->debug_level = debug; pthread_mutex_init(&ctx->mutex, NULL); + if (mode == FLB_TLS_SERVER_MODE) { + SSL_CTX_set_alpn_select_cb(ssl_ctx, + tls_context_server_alpn_select_callback, + ctx); + } + /* Verify peer: by default OpenSSL always verify peer */ if (verify == FLB_FALSE) { SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL); @@ -388,6 +499,7 @@ static int tls_session_destroy(void *session) if (flb_socket_error(ptr->fd) == 0) { SSL_shutdown(ptr->ssl); } + SSL_free(ptr->ssl); flb_free(ptr); @@ -608,6 +720,7 @@ static struct flb_tls_backend tls_openssl = { .name = "openssl", .context_create = tls_context_create, .context_destroy = tls_context_destroy, + .context_alpn_set = tls_context_alpn_set, .session_create = tls_session_create, .session_destroy = tls_session_destroy, .net_read = tls_net_read,