mirror of
https://github.com/3proxy/3proxy.git
synced 2026-08-05 17:20:11 +08:00
fix wolfSSL, switch minimal/busybox to musl+wolfssl
This commit is contained in:
parent
3bfabb29f8
commit
c370635fc4
73
.dockerignore
Normal file
73
.dockerignore
Normal file
@ -0,0 +1,73 @@
|
||||
# Exclude top-level dirs not needed for build
|
||||
/bin/
|
||||
/bin64/
|
||||
/build/
|
||||
/cfg/
|
||||
/cmake/
|
||||
/CMakeFiles/
|
||||
/debian/
|
||||
/doc/
|
||||
/man/
|
||||
|
||||
# Build artifacts
|
||||
**/*.o
|
||||
**/*.obj
|
||||
**/*.so
|
||||
**/*.dll
|
||||
**/*.exe
|
||||
**/*.exp
|
||||
**/*.lib
|
||||
**/*.pdb
|
||||
**/*.ilk
|
||||
**/*.idb
|
||||
**/*.err
|
||||
**/*.ld.so
|
||||
**/*.dSYM
|
||||
**/*.var
|
||||
build*/
|
||||
buildlinux.sh
|
||||
tmp/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Editor / IDE
|
||||
**/*.swp
|
||||
**/*.swo
|
||||
**/*~
|
||||
**/*.bak
|
||||
**/*.tmp
|
||||
**/*.log
|
||||
.project
|
||||
.cproject
|
||||
.classpath
|
||||
.settings/
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Claude / docs
|
||||
CLAUDE.md
|
||||
.claude/
|
||||
|
||||
# Generated version files
|
||||
version
|
||||
version.c
|
||||
version.sh
|
||||
verfile.sh
|
||||
|
||||
# Local config / keys
|
||||
**/*.key
|
||||
**/*.pem
|
||||
**/*.pfx
|
||||
3proxy.cfg
|
||||
3proxy-ssl.cfg
|
||||
3proxy-pcre.cfg
|
||||
|
||||
# Misc
|
||||
res
|
||||
3proxy.res
|
||||
copytgz.sh
|
||||
35
.github/workflows/docker-test.yml
vendored
Normal file
35
.github/workflows/docker-test.yml
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
name: Build Docker images (test, no publish)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ matrix.file }} (${{ matrix.platform }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
file: [Dockerfile.minimal, Dockerfile.busybox, Dockerfile.full]
|
||||
platform: [linux/amd64, linux/arm64]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Build image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.file }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
push: false
|
||||
load: ${{ matrix.platform == 'linux/amd64' }}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -271,3 +271,4 @@ bin/3proxy_tcppm
|
||||
bin/3proxy_tlspr
|
||||
bin/3proxy_udppm
|
||||
build*/*
|
||||
testcerts/
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
# 3proxy.full is fully functional 3proxy build based on busybox:glibc
|
||||
# 3proxy.busybox is fully functional 3proxy build based on busybox:musl
|
||||
# built against wolfSSL and PCRE2.
|
||||
#
|
||||
# Examples are for podman, for docker change 'podman' to 'docker'
|
||||
#
|
||||
@ -19,11 +20,27 @@
|
||||
# configuration is supported for compatibility only.
|
||||
|
||||
|
||||
FROM docker.io/gcc AS buildenv
|
||||
FROM docker.io/alpine:latest AS wolfssl
|
||||
RUN apk add --no-cache build-base curl autoconf automake libtool
|
||||
RUN TAG=$(curl -s https://api.github.com/repos/wolfSSL/wolfssl/releases/latest \
|
||||
| sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p') && \
|
||||
echo "wolfssl tag: $TAG" && \
|
||||
curl -sL https://api.github.com/repos/wolfSSL/wolfssl/tarball/$TAG -o /tmp/w.tar.gz && \
|
||||
mkdir /src && tar -xzf /tmp/w.tar.gz -C /src --strip-components=1 && \
|
||||
cd /src && \
|
||||
autoreconf -i && \
|
||||
./configure --enable-opensslextra --enable-opensslall --enable-certgen \
|
||||
--enable-tls13 --enable-sni --enable-session-ticket \
|
||||
--enable-static --disable-shared --prefix=/usr/local && \
|
||||
make -j$(nproc) && make install
|
||||
|
||||
FROM docker.io/alpine:latest AS buildenv
|
||||
RUN apk add --no-cache gcc make musl-dev pcre2-dev
|
||||
COPY --from=wolfssl /usr/local /usr/local
|
||||
COPY . 3proxy
|
||||
RUN cd 3proxy &&\
|
||||
apt --assume-yes update && apt --assume-yes install libssl-dev libpcre2-dev &&\
|
||||
make -f Makefile.Linux LIBSTATIC=true PAM_CHECK=false &&\
|
||||
RUN cd 3proxy && mkdir -p bin &&\
|
||||
make -f Makefile.Linux LIBSTATIC=true PAM_CHECK=false WOLFSSL_CHECK=true \
|
||||
LDFLAGS="-L/usr/local/lib" &&\
|
||||
strip bin/3proxy &&\
|
||||
strip bin/*so &&\
|
||||
mkdir /dist &&\
|
||||
@ -42,11 +59,9 @@ RUN cd /dist &&\
|
||||
ln -s /lib lib64 &&\
|
||||
ln -s /lib usr/lib &&\
|
||||
ln -s /lib usr/lib64
|
||||
RUN cp /lib/ld-*.so.* /dist/usr/local/3proxy/libexec || true
|
||||
RUN cp /lib64/ld-*.so.* /dist/usr/local/3proxy/libexec || true
|
||||
RUN cp "/lib/`gcc -dumpmachine`"/libdl.so.* /dist/usr/local/3proxy/libexec
|
||||
RUN cp /lib/ld-musl-*.so.* /dist/usr/local/3proxy/libexec || true
|
||||
|
||||
FROM docker.io/busybox:glibc
|
||||
FROM docker.io/busybox:musl
|
||||
COPY --from=buildenv /dist /
|
||||
RUN ln -sf /usr/local/3proxy/libexec/* /lib/ && cd /usr/local/3proxy/ && ln -s libexec lib && ln -s libexec lib64 && mkdir usr && ln -s libexec usr/lib && ln -s libexec usr//lib64
|
||||
RUN mkdir -p /lib /lib64 && ln -sf /usr/local/3proxy/libexec/* /lib/ && cd /usr/local/3proxy/ && ln -s libexec lib && ln -s libexec lib64 && mkdir usr && ln -s libexec usr/lib && ln -s libexec usr/lib64
|
||||
CMD ["/bin/3proxy", "/etc/3proxy/3proxy.cfg"]
|
||||
|
||||
@ -23,6 +23,7 @@ FROM docker.io/gcc AS buildenv
|
||||
COPY . 3proxy
|
||||
RUN cd 3proxy &&\
|
||||
apt --assume-yes update && apt --assume-yes install libssl-dev libpcre2-dev &&\
|
||||
mkdir -p bin &&\
|
||||
make -f Makefile.Linux LIBSTATIC=true PAM_CHECK=false &&\
|
||||
strip bin/3proxy &&\
|
||||
mkdir /dist &&\
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
#
|
||||
# Examples are for podman. For docker change 'podman' to 'docker'.
|
||||
#
|
||||
# This is busybox based docker with only 3proxy static executable.
|
||||
# This is a scratch-based docker with statically linked 3proxy executable
|
||||
# built against musl and wolfSSL.
|
||||
#
|
||||
# Limitations for minimal version:
|
||||
# no support for plugins and system resolver.
|
||||
@ -25,10 +26,27 @@
|
||||
#<end
|
||||
#
|
||||
|
||||
FROM docker.io/gcc AS buildenv
|
||||
FROM docker.io/alpine:latest AS wolfssl
|
||||
RUN apk add --no-cache build-base curl autoconf automake libtool
|
||||
RUN TAG=$(curl -s https://api.github.com/repos/wolfSSL/wolfssl/releases/latest \
|
||||
| sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p') && \
|
||||
echo "wolfssl tag: $TAG" && \
|
||||
curl -sL https://api.github.com/repos/wolfSSL/wolfssl/tarball/$TAG -o /tmp/w.tar.gz && \
|
||||
mkdir /src && tar -xzf /tmp/w.tar.gz -C /src --strip-components=1 && \
|
||||
cd /src && \
|
||||
autoreconf -i && \
|
||||
./configure --enable-opensslextra --enable-opensslall --enable-certgen \
|
||||
--enable-tls13 --enable-sni --enable-session-ticket \
|
||||
--enable-static --disable-shared --prefix=/usr/local && \
|
||||
make -j$(nproc) && make install
|
||||
|
||||
FROM docker.io/alpine:latest AS buildenv
|
||||
RUN apk add --no-cache gcc make musl-dev
|
||||
COPY --from=wolfssl /usr/local /usr/local
|
||||
COPY . 3proxy
|
||||
RUN cd 3proxy &&\
|
||||
make -f Makefile.Linux STATIC=true &&\
|
||||
RUN cd 3proxy && mkdir -p bin &&\
|
||||
make -f Makefile.Linux STATIC=true WOLFSSL_CHECK=true \
|
||||
LDFLAGS="-static -L/usr/local/lib" &&\
|
||||
strip bin/3proxy
|
||||
|
||||
FROM scratch
|
||||
|
||||
@ -48,6 +48,13 @@ typedef struct {
|
||||
#endif
|
||||
} MD4_CTX;
|
||||
|
||||
/* Remap public symbols to a 3proxy-private namespace so the bundled
|
||||
implementation does not collide with OpenSSL/libcrypto's MD4 symbols
|
||||
when statically linked. Callers keep using the MD4_* names. */
|
||||
#define MD4_Init _3proxy_MD4_Init
|
||||
#define MD4_Update _3proxy_MD4_Update
|
||||
#define MD4_Final _3proxy_MD4_Final
|
||||
|
||||
extern void MD4_Init(MD4_CTX *ctx);
|
||||
extern void MD4_Update(MD4_CTX *ctx, const void *data, size_t size);
|
||||
extern void MD4_Final(unsigned char *result, MD4_CTX *ctx);
|
||||
|
||||
@ -44,6 +44,13 @@ typedef struct {
|
||||
MD5_u32plus block[16];
|
||||
} MD5_CTX;
|
||||
|
||||
/* Remap public symbols to a 3proxy-private namespace so the bundled
|
||||
implementation does not collide with OpenSSL/libcrypto's MD5 symbols
|
||||
when statically linked. Callers keep using the MD5_* names. */
|
||||
#define MD5_Init _3proxy_MD5_Init
|
||||
#define MD5_Update _3proxy_MD5_Update
|
||||
#define MD5_Final _3proxy_MD5_Final
|
||||
|
||||
extern void MD5_Init(MD5_CTX *ctx);
|
||||
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
|
||||
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
|
||||
|
||||
50
src/ssl.c
50
src/ssl.c
@ -490,6 +490,24 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx){
|
||||
return preverify_ok;
|
||||
}
|
||||
|
||||
#ifdef WITH_WOLFSSL
|
||||
/* wolfSSL's SSL_CTX_use_PrivateKey(EVP_PKEY*) compat is unreliable: it
|
||||
* silently fails (returns 0, no error queued) for keys loaded via
|
||||
* PEM_read_bio_PrivateKey. Export the key to DER and load via the
|
||||
* native buffer API instead. */
|
||||
static int ssl_ctx_use_pkey(SSL_CTX *ctx, EVP_PKEY *key){
|
||||
unsigned char *der = NULL;
|
||||
int len, rc;
|
||||
len = i2d_PrivateKey(key, &der);
|
||||
if(len <= 0 || !der) return 0;
|
||||
rc = wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, (long)len, SSL_FILETYPE_ASN1);
|
||||
OPENSSL_free(der);
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
#define ssl_ctx_use_pkey(ctx, key) SSL_CTX_use_PrivateKey((ctx), (key))
|
||||
#endif
|
||||
|
||||
|
||||
SSL_CTX * ssl_cli_ctx(SSL_CONFIG *config, X509 *server_cert, EVP_PKEY *server_key, char** errSSL){
|
||||
SSL_CTX *ctx;
|
||||
@ -516,11 +534,18 @@ SSL_CTX * ssl_cli_ctx(SSL_CONFIG *config, X509 *server_cert, EVP_PKEY *server_ke
|
||||
}
|
||||
}
|
||||
|
||||
err = SSL_CTX_use_PrivateKey(ctx, server_key);
|
||||
if ( err <= 0 ) {
|
||||
*errSSL = getSSLErr();
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
/* Load the private key only when a cert is already loaded into ctx.
|
||||
* wolfSSL validates the key against the cert and requires the cert
|
||||
* to be present first; OpenSSL tolerates either order but is happy
|
||||
* with cert-first too. When server_cert is NULL (serv path), the
|
||||
* caller loads the cert chain and the key itself after this call. */
|
||||
if(server_cert) {
|
||||
err = ssl_ctx_use_pkey(ctx, server_key);
|
||||
if ( err <= 0 ) {
|
||||
*errSSL = getSSLErr();
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
SSL_CTX_set_session_id_context(ctx, (const unsigned char *)"3proxy", 6);
|
||||
if(config->server_min_proto_version)SSL_CTX_set_min_proto_version(ctx, config->server_min_proto_version);
|
||||
@ -655,6 +680,10 @@ static void* ssl_filter_open(void * idata, struct srvparam * srv){
|
||||
fprintf(stderr, "failed to read server cert: %s\n", srvcert);
|
||||
return sc;
|
||||
}
|
||||
if(ssl_ctx_use_pkey(sc->cli_ctx, sc->server_key) <= 0){
|
||||
fprintf(stderr, "failed to use server key\n");
|
||||
return sc;
|
||||
}
|
||||
sc->serv = 1;
|
||||
}
|
||||
if(mitm || cli || serv){
|
||||
@ -678,7 +707,7 @@ static void* ssl_filter_open(void * idata, struct srvparam * srv){
|
||||
}
|
||||
if(sc->client_cert){
|
||||
SSL_CTX_use_certificate(sc->srv_ctx, (X509 *) sc->client_cert);
|
||||
SSL_CTX_use_PrivateKey(sc->srv_ctx, sc->client_key);
|
||||
ssl_ctx_use_pkey(sc->srv_ctx, sc->client_key);
|
||||
}
|
||||
if(sc->client_min_proto_version)SSL_CTX_set_min_proto_version(sc->srv_ctx, sc->client_min_proto_version);
|
||||
if(sc->client_max_proto_version)SSL_CTX_set_max_proto_version(sc->srv_ctx, sc->client_max_proto_version);
|
||||
@ -705,6 +734,15 @@ static void* ssl_filter_open(void * idata, struct srvparam * srv){
|
||||
SSL_CTX_set_default_verify_paths(sc->srv_ctx);
|
||||
SSL_CTX_set_verify(sc->srv_ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
|
||||
}
|
||||
#ifdef WITH_WOLFSSL
|
||||
else {
|
||||
/* wolfSSL defaults to peer verification; OpenSSL defaults to
|
||||
* SSL_VERIFY_NONE. Make the no-verify intent explicit so the
|
||||
* upstream handshake (ssl_cli / ssl_mitm) succeeds without a
|
||||
* trusted CA store. */
|
||||
SSL_CTX_set_verify(sc->srv_ctx, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef WITHSPLICE
|
||||
srv->usesplice = 0;
|
||||
|
||||
73
src/ssllib.c
73
src/ssllib.c
@ -45,8 +45,6 @@ static char hexMap[] = {
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
static BIO *bio_err=NULL;
|
||||
|
||||
|
||||
|
||||
char * getSSLErr(){
|
||||
@ -94,26 +92,14 @@ static int add_ext(X509 *cert, int nid, char *value)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void del_ext(X509 *dst_cert, int nid, int where){
|
||||
int ex;
|
||||
|
||||
ex = X509_get_ext_by_NID(dst_cert, nid, where);
|
||||
if(ex>=0){
|
||||
X509_EXTENSION *ext;
|
||||
if((ext = X509_delete_ext(dst_cert, ex))) X509_EXTENSION_free(ext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
||||
{
|
||||
int err = -1;
|
||||
int san_idx;
|
||||
BIO *fcache;
|
||||
X509 *src_cert = (X509 *) cert;
|
||||
X509 *dst_cert = NULL;
|
||||
|
||||
EVP_PKEY *pk = NULL;
|
||||
|
||||
unsigned char hash_sha256[32];
|
||||
char hash_name_sha256[(16*2) + 1];
|
||||
char cache_name[256];
|
||||
@ -142,27 +128,35 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* proceed if certificate is not cached */
|
||||
dst_cert = X509_dup(src_cert);
|
||||
/* Build a fresh certificate instead of duplicating the source: only
|
||||
* the fields required for a usable server cert are copied (version,
|
||||
* serial, subject, validity, SAN). This avoids inheriting upstream
|
||||
* extensions (AKI, CRL dist points, certificate policies, ...) that
|
||||
* break chain validation, and works around wolfSSL's no-op
|
||||
* X509_delete_ext compat shim. */
|
||||
dst_cert = X509_new();
|
||||
if ( dst_cert == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
del_ext(dst_cert, NID_crl_distribution_points, -1);
|
||||
del_ext(dst_cert, NID_info_access, -1);
|
||||
del_ext(dst_cert, NID_authority_key_identifier, -1);
|
||||
del_ext(dst_cert, NID_certificate_policies, 0);
|
||||
|
||||
X509_set_version(dst_cert, X509_get_version(src_cert));
|
||||
X509_set_serialNumber(dst_cert, X509_get_serialNumber(src_cert));
|
||||
if(!X509_set_subject_name(dst_cert, X509_get_subject_name(src_cert))
|
||||
|| !X509_set_issuer_name(dst_cert, X509_get_subject_name(config->CA_cert))){
|
||||
X509_free(dst_cert);
|
||||
return NULL;
|
||||
}
|
||||
err = X509_set_pubkey(dst_cert, config->server_key?config->server_key:config->CA_key);
|
||||
if ( err == 0 ) {
|
||||
X509_free(dst_cert);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
err = X509_set_issuer_name(dst_cert, X509_get_subject_name(config->CA_cert));
|
||||
if(!err){
|
||||
X509_free(dst_cert);
|
||||
return NULL;
|
||||
X509_set_notBefore(dst_cert, X509_get_notBefore(src_cert));
|
||||
X509_set_notAfter(dst_cert, X509_get_notAfter(src_cert));
|
||||
san_idx = X509_get_ext_by_NID(src_cert, NID_subject_alt_name, -1);
|
||||
if(san_idx >= 0){
|
||||
X509_EXTENSION *san;
|
||||
san = X509_get_ext(src_cert, san_idx);
|
||||
if(san) X509_add_ext(dst_cert, san, -1);
|
||||
}
|
||||
err = X509_sign(dst_cert, config->CA_key, EVP_sha256());
|
||||
if(!err){
|
||||
@ -229,6 +223,14 @@ void _ssl_cert_free(SSL_CERT cert)
|
||||
|
||||
|
||||
|
||||
/* OpenSSL before 1.1.0 requires the application to install threading
|
||||
callbacks; OpenSSL >= 1.1.0 and wolfSSL handle locking internally. */
|
||||
#if !defined(WITH_WOLFSSL) && defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#define LEGACY_SSL_THREADING 1
|
||||
#else
|
||||
#define LEGACY_SSL_THREADING 0
|
||||
#endif
|
||||
|
||||
/* This array will store all of the mutexes available to OpenSSL. */
|
||||
static _3proxy_mutex_t *mutex_buf= NULL;
|
||||
|
||||
@ -252,6 +254,7 @@ static unsigned long id_function(void)
|
||||
|
||||
int thread_setup(void)
|
||||
{
|
||||
#if LEGACY_SSL_THREADING
|
||||
int i;
|
||||
|
||||
mutex_buf = malloc(CRYPTO_num_locks( ) * sizeof(_3proxy_mutex_t));
|
||||
@ -262,10 +265,14 @@ int thread_setup(void)
|
||||
CRYPTO_set_id_callback(id_function);
|
||||
CRYPTO_set_locking_callback(locking_function);
|
||||
return 1;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int thread_cleanup(void)
|
||||
{
|
||||
#if LEGACY_SSL_THREADING
|
||||
int i;
|
||||
|
||||
if (!mutex_buf)
|
||||
@ -277,6 +284,9 @@ int thread_cleanup(void)
|
||||
free(mutex_buf);
|
||||
mutex_buf = NULL;
|
||||
return 1;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -291,9 +301,14 @@ void ssl_init()
|
||||
|
||||
ssl_init_done = 1;
|
||||
thread_setup();
|
||||
#ifdef WITH_WOLFSSL
|
||||
wolfSSL_Init();
|
||||
#elif defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
#else
|
||||
SSLeay_add_ssl_algorithms();
|
||||
SSL_load_error_strings();
|
||||
#endif
|
||||
_3proxy_mutex_init(&ssl_file_mutex);
|
||||
bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user