-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit acb1cfc
Showing
9 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "mbedtls"] | ||
path = mbedtls | ||
url = https://github.com/ARMmbed/mbedtls.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
os: linux | ||
dist: bionic | ||
addons: | ||
apt: | ||
update: true | ||
packages: | ||
- linux-headers-5.0.0-37-generic | ||
|
||
language: c | ||
compiler: gcc | ||
|
||
before_script: | ||
- sudo ln -sf /usr/src/linux-headers-5.0.0-37-generic/include/uapi/linux/tls.h /usr/include/linux/ | ||
- mkdir -p build | ||
- cd build | ||
- cmake -DCMAKE_BUILD_TYPE=RELEASE .. | ||
|
||
script: make -j $(nproc) | ||
|
||
deploy: | ||
provider: releases | ||
token: $GITHUB_TOKEN | ||
file: libktlswrapper.so | ||
skip_cleanup: true | ||
on: | ||
tags: true | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
cmake_minimum_required(VERSION 3.10) | ||
|
||
project(ktlswrapper C) | ||
|
||
option(ENABLE_PROGRAMS "Build mbed TLS programs." OFF) | ||
option(ENABLE_TESTING "Build mbed TLS tests." OFF) | ||
set(CMAKE_POSITION_INDEPENDENT_CODE ON) | ||
add_subdirectory(mbedtls) | ||
|
||
add_library(ktlswrapper SHARED ktlswrapper.c) | ||
|
||
include_directories(mbedtls/include) | ||
target_compile_definitions(ktlswrapper PRIVATE _GNU_SOURCE) | ||
|
||
if (CMAKE_BUILD_TYPE STREQUAL RELEASE) | ||
target_compile_options(ktlswrapper PRIVATE -ffunction-sections -fdata-sections) | ||
endif () | ||
|
||
set_target_properties(ktlswrapper PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/ktlswrapper.version") | ||
set_target_properties(ktlswrapper PROPERTIES LINK_FLAGS_RELEASE "-Wl,--gc-sections -s") | ||
|
||
target_link_libraries(ktlswrapper mbedtls dl) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
BSD 2-Clause License | ||
|
||
Copyright (c) 2020, Z. Liu | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this | ||
list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, | ||
this list of conditions and the following disclaimer in the documentation | ||
and/or other materials provided with the distribution. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# KTLS Wrapper [![Build Status](https://travis-ci.com/zliuva/ktlswrapper.svg?token=3u2VrXJmVG2X8YDf7p67&branch=master)](https://travis-ci.com/zliuva/ktlswrapper) | ||
|
||
A wrapper that enables TLS support (TLS 1.2 with AES 128 GCM) for existing applications without code change. | ||
|
||
## Requirements | ||
|
||
Kernel `4.17` or above, module `tls` loaded. | ||
|
||
## Usage | ||
|
||
```bash | ||
LD_PRELOAD=</full/path/to/libktlswrapper.so> \ | ||
KTLS_WRAPPER_CERT=</full/path/to/tls/cert (PEM format)> \ | ||
KTLS_WRAPPER_KEY=</full/path/to/tls/private-key (PEM format)> \ | ||
KTLS_WRAPPER_PORT=<port existing application listens on> \ | ||
<existing application> | ||
``` | ||
|
||
or any other ways to specify environment variables such as systemd unit files; be aware of `LD_PRELOAD` limitations on setuid executables. | ||
|
||
## How does it work? | ||
|
||
The wrapper hooks into `accept`/`accept4`. Before returning the client socket, the wrapper initiates an SSL handshake using [mbedtls](https://github.com/ARMmbed/mbedtls) and enables [Kernel TLS](https://www.kernel.org/doc/html/latest/networking/tls.html) on the socket for both sending and receiving, using the established secrets from mbedtls. Any subsequent `read`s/`write`s to the socket would have decryption and encryption working transparently. | ||
|
||
## Why? | ||
|
||
Why not? | ||
|
||
## Is this safe to use on production? | ||
|
||
~Definitely not.~ ~Maybe.~ Worse things have happened. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
#include <assert.h> | ||
#include <errno.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
#include <sys/types.h> | ||
#include <sys/socket.h> | ||
|
||
#include <linux/tls.h> | ||
#include <netinet/tcp.h> | ||
#include <arpa/inet.h> | ||
|
||
#include <dlfcn.h> | ||
|
||
#include <mbedtls/aes.h> | ||
#include <mbedtls/ctr_drbg.h> | ||
#include <mbedtls/entropy.h> | ||
#include <mbedtls/error.h> | ||
#include <mbedtls/gcm.h> | ||
#include <mbedtls/net_sockets.h> | ||
#include <mbedtls/ssl.h> | ||
#include <mbedtls/ssl_internal.h> | ||
|
||
static const char *cert, *key; | ||
static in_port_t port; | ||
static int target_sockfd = -1; | ||
|
||
static mbedtls_entropy_context entropy; | ||
static mbedtls_ctr_drbg_context ctr_drbg; | ||
static mbedtls_ssl_config conf; | ||
static mbedtls_x509_crt srvcert; | ||
static mbedtls_pk_context srvkey; | ||
|
||
static const int AES_128_CIPHERS[] = { | ||
MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | ||
MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, | ||
0x0 | ||
}; | ||
|
||
static int (*real_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); | ||
static int (*real_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); | ||
static int (*real_accept4)(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); | ||
|
||
#define PRINT_MBEDTLS_ERROR(errno) \ | ||
{ \ | ||
char buf[256]; \ | ||
mbedtls_strerror((errno), buf, sizeof(buf)); \ | ||
fprintf(stderr, "[%s:%d] mbedtls error: %s\n", __FILE__, __LINE__, buf); \ | ||
} | ||
|
||
#define ENSURE(x) \ | ||
{ \ | ||
int ret = (x); \ | ||
if (ret != 0) { \ | ||
PRINT_MBEDTLS_ERROR(ret); \ | ||
assert(false); \ | ||
} \ | ||
} | ||
|
||
static void init_ssl_conf(void) { | ||
mbedtls_ssl_config_init(&conf); | ||
mbedtls_x509_crt_init(&srvcert); | ||
mbedtls_pk_init(&srvkey); | ||
mbedtls_entropy_init(&entropy); | ||
mbedtls_ctr_drbg_init(&ctr_drbg); | ||
|
||
ENSURE(mbedtls_x509_crt_parse_file(&srvcert, cert)); | ||
ENSURE(mbedtls_pk_parse_keyfile(&srvkey, key, NULL)); | ||
|
||
mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL); | ||
ENSURE(mbedtls_ssl_conf_own_cert(&conf, &srvcert, &srvkey)); | ||
|
||
ENSURE(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)); | ||
ENSURE(mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)); | ||
|
||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); | ||
} | ||
|
||
bool set_crypto_info(int client, mbedtls_ssl_context *ssl, bool read) { | ||
struct tls12_crypto_info_aes_gcm_128 crypto_info = { | ||
.info = { | ||
.version = TLS_1_2_VERSION, | ||
.cipher_type = TLS_CIPHER_AES_GCM_128 | ||
} | ||
}; | ||
|
||
unsigned char *salt = read ? ssl->transform->iv_dec : ssl->transform->iv_enc; | ||
unsigned char *iv = salt + 4; | ||
unsigned char *rec_seq = read ? ssl->in_ctr : ssl->cur_out_ctr; | ||
|
||
mbedtls_gcm_context *gcm_context = read ? ssl->transform->cipher_ctx_dec.cipher_ctx : ssl->transform->cipher_ctx_enc.cipher_ctx; | ||
mbedtls_aes_context *aes_context = gcm_context->cipher_ctx.cipher_ctx; | ||
|
||
memcpy(crypto_info.iv, iv, TLS_CIPHER_AES_GCM_128_IV_SIZE); | ||
memcpy(crypto_info.rec_seq, rec_seq, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); | ||
memcpy(crypto_info.key, aes_context->rk, TLS_CIPHER_AES_GCM_128_KEY_SIZE); | ||
memcpy(crypto_info.salt, salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE); | ||
|
||
if (setsockopt(client, SOL_TLS, read ? TLS_RX : TLS_TX, &crypto_info, sizeof(crypto_info)) < 0) { | ||
perror("setsockopt"); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool setup_ktls(int client) { | ||
bool success = false; | ||
|
||
mbedtls_ctr_drbg_reseed(&ctr_drbg, NULL, 0); | ||
|
||
mbedtls_ssl_context ssl; | ||
mbedtls_ssl_init(&ssl); | ||
|
||
mbedtls_ssl_conf_ciphersuites(&conf, AES_128_CIPHERS); | ||
ENSURE(mbedtls_ssl_setup(&ssl, &conf)); | ||
|
||
mbedtls_ssl_set_bio(&ssl, &client, mbedtls_net_send, mbedtls_net_recv, NULL); | ||
|
||
int ret; | ||
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { | ||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { | ||
PRINT_MBEDTLS_ERROR(ret); | ||
goto cleanup; | ||
} | ||
} | ||
|
||
if (setsockopt(client, SOL_TCP, TCP_ULP, "tls", sizeof("tls")) < 0) { | ||
perror("setsockopt"); | ||
goto cleanup; | ||
} | ||
|
||
success = set_crypto_info(client, &ssl, true) && | ||
set_crypto_info(client, &ssl, false); | ||
|
||
cleanup: | ||
mbedtls_ssl_free(&ssl); | ||
return success; | ||
} | ||
|
||
__attribute__((constructor)) | ||
static void init(void) { | ||
real_bind = dlsym(RTLD_NEXT, "bind"); | ||
real_accept = dlsym(RTLD_NEXT, "accept"); | ||
real_accept4 = dlsym(RTLD_NEXT, "accept4"); | ||
|
||
cert = getenv("KTLS_WRAPPER_CERT"); | ||
key = getenv("KTLS_WRAPPER_KEY"); | ||
char *port_str = getenv("KTLS_WRAPPER_PORT"); | ||
|
||
if (!port_str || !cert || !key) { | ||
fprintf(stderr, "KTLS_WRAPPER_CERT, KTLS_WRAPPER_KEY or KTLS_WRAPPER_PORT missing.\n"); | ||
return; | ||
} | ||
|
||
port = htons(atoi(port_str)); | ||
|
||
init_ssl_conf(); | ||
} | ||
|
||
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { | ||
int ret = real_bind(sockfd, addr, addrlen); | ||
if (ret == 0 && | ||
addr->sa_family == AF_INET && | ||
((const struct sockaddr_in *) addr)->sin_port == port) { | ||
target_sockfd = sockfd; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
#define SETUP_TLS(client) \ | ||
{ \ | ||
if ((client) >= 0 && sockfd == target_sockfd) { \ | ||
if (!setup_ktls((client))) { \ | ||
close((client)); \ | ||
return -ECONNABORTED; \ | ||
} \ | ||
} \ | ||
return client; \ | ||
} | ||
|
||
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { | ||
int client = real_accept(sockfd, addr, addrlen); | ||
SETUP_TLS(client); | ||
} | ||
|
||
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { | ||
int client = real_accept4(sockfd, addr, addrlen, flags); | ||
SETUP_TLS(client); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
global: | ||
bind; | ||
accept; | ||
accept4; | ||
|
||
local: | ||
*; | ||
}; | ||
|