support ssl_serv / ssl_noserv commands

example:
plugin /path/to/SSLPlugin.so ssl_plugin
ssl_srvcert path_to_cert
ssl_srvkey path_to_key
ssl_serv
proxy -p33128
ssl_noserv
proxy -p3128
This commit is contained in:
Vladimir Dubrovin 2024-02-18 23:42:09 +03:00
parent d77e528847
commit 067fdd7f95
3 changed files with 156 additions and 60 deletions

View File

@ -146,7 +146,7 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
del_ext(dst_cert, NID_authority_key_identifier, -1);
del_ext(dst_cert, NID_certificate_policies, 0);
err = X509_set_pubkey(dst_cert, config->server_key);
err = X509_set_pubkey(dst_cert, config->server_key?config->server_key:config->CA_key);
if ( err == 0 ) {
X509_free(dst_cert);
return NULL;
@ -193,7 +193,6 @@ SSL_CONN ssl_handshake_to_server(SOCKET s, char * hostname, SSL_CERT *server_cer
if ( conn == NULL ){
return NULL;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
conn->ctx = SSL_CTX_new(SSLv23_client_method());
#else
@ -213,6 +212,7 @@ SSL_CONN ssl_handshake_to_server(SOCKET s, char * hostname, SSL_CERT *server_cer
if(!SSL_set_fd(conn->ssl, s)){
ssl_conn_free(conn);
*errSSL = ERR_error_string(ERR_get_error(), errbuf);
return NULL;
}
if(hostname && *hostname)SSL_set_tlsext_host_name(conn->ssl, hostname);
@ -254,12 +254,14 @@ SSL_CONN ssl_handshake_to_client(SOCKET s, SSL_CERT server_cert, EVP_PKEY *serve
conn->ctx = SSL_CTX_new(TLS_server_method());
#endif
if ( conn->ctx == NULL ) {
*errSSL = ERR_error_string(ERR_get_error(), errbuf);
free(conn);
return NULL;
}
err = SSL_CTX_use_certificate(conn->ctx, (X509 *) server_cert);
if ( err <= 0 ) {
*errSSL = ERR_error_string(ERR_get_error(), errbuf);
SSL_CTX_free(conn->ctx);
free(conn);
return NULL;
@ -267,6 +269,7 @@ SSL_CONN ssl_handshake_to_client(SOCKET s, SSL_CERT server_cert, EVP_PKEY *serve
err = SSL_CTX_use_PrivateKey(conn->ctx, server_key);
if ( err <= 0 ) {
*errSSL = ERR_error_string(ERR_get_error(), errbuf);
SSL_CTX_free(conn->ctx);
free(conn);
return NULL;
@ -283,12 +286,13 @@ SSL_CONN ssl_handshake_to_client(SOCKET s, SSL_CERT server_cert, EVP_PKEY *serve
conn->ssl = SSL_new(conn->ctx);
if ( conn->ssl == NULL ) {
*errSSL = ERR_error_string(ERR_get_error(), errbuf);
SSL_CTX_free(conn->ctx);
free(conn);
return NULL;
}
SSL_set_fd(conn->ssl, (int)s);
SSL_set_fd(conn->ssl, s);
err = SSL_accept(conn->ssl);
if ( err <= 0 ) {
*errSSL = ERR_error_string(ERR_get_error(), errbuf);

View File

@ -12,8 +12,10 @@ typedef void *SSL_CERT;
struct ssl_config {
int mitm;
int serv;
char *certcache;
X509 *CA_cert;
X509 *server_cert;
EVP_PKEY *CA_key;
EVP_PKEY *server_key;
};

View File

@ -34,7 +34,10 @@ static struct pluginlink * pl;
static int ssl_loaded = 0;
static int ssl_connect_timeout = 0;
char *certcache = NULL;
char *srvcert;
char *srvkey;
int mitm = 0;
int serv = 0;
int ssl_inited = 0;
typedef struct _ssl_conn {
@ -213,7 +216,7 @@ static int WINAPI ssl_poll(void *state, struct pollfd *fds, unsigned int nfds, i
#define PCONF (((struct SSLstate *)param->sostate)->config)
int dossl(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConnp){
int domitm(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConnp){
SSL_CERT ServerCert=NULL, FakeCert=NULL;
SSL_CONN ServerConn, ClientConn;
char *errSSL=NULL;
@ -253,7 +256,7 @@ int dossl(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConn
return 2;
}
ClientConn = ssl_handshake_to_client(param->clisock, FakeCert, PCONF->server_key, &errSSL);
ClientConn = ssl_handshake_to_client(param->clisock, FakeCert, PCONF->server_key?PCONF->server_key:PCONF->CA_key, &errSSL);
_ssl_cert_free(FakeCert);
if ( ClientConn == NULL ) {
@ -286,70 +289,54 @@ int dossl(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConn
return 0;
}
X509 * getCert (const char *fname){
BIO *f;
X509 *CA_cert;
f = BIO_new_file(fname, "r");
if(!f) return NULL;
CA_cert=PEM_read_bio_X509(f, NULL, NULL, NULL);
BIO_free(f);
return CA_cert;
}
EVP_PKEY * getKey(const char *fname){
BIO *f;
EVP_PKEY *key;
f = BIO_new_file(fname, "r");
if(!f) return NULL;
key = PEM_read_bio_PrivateKey(f, NULL, NULL, NULL);
BIO_free(f);
return key;
}
static void* ssl_filter_open(void * idata, struct srvparam * srv){
char fname[256];
struct ssl_config *sc;
sc = malloc(sizeof(struct ssl_config));
if(!sc) return NULL;
memset(sc, 0, sizeof(struct ssl_config));
if(certcache) sc->certcache = strdup(certcache);
if(mitm){
BIO *f;
char fname[256];
if(!certcache) {
return sc;
}
sprintf(fname, "%.240s3proxy.pem", certcache);
f = BIO_new_file(fname, "r");
if ( f != NULL ) {
sc->CA_cert=PEM_read_bio_X509(f, NULL, NULL, NULL);
BIO_free(f);
sc->CA_cert = getCert(fname);
if(!sc->CA_cert){
unsigned long err;
err=ERR_get_error();
fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL));
return sc;
}
}
else {
fprintf(stderr, "failed to open: %s\n", fname);
fprintf(stderr, "failed to read: %s\n", fname);
return sc;
}
sprintf(fname, "%.240s3proxy.key", sc->certcache);
f = BIO_new_file(fname, "rb");
if ( f != NULL ) {
sc->CA_key = PEM_read_bio_PrivateKey(f, NULL, NULL, NULL);
BIO_free(f);
sc->CA_key = getKey(fname);
if(!sc->CA_key){
unsigned long err;
err=ERR_get_error();
fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL));
fprintf(stderr, "failed to read: %s\n", fname);
return sc;
}
}
else {
fprintf(stderr, "failed to open: %s\n", fname);
return sc;
}
sprintf(fname, "%.128sserver.key", sc->certcache);
f = BIO_new_file(fname, "rb");
if ( f != NULL ) {
sc->server_key = PEM_read_bio_PrivateKey(f, &sc->server_key, NULL, NULL);
BIO_free(f);
if(!sc->server_key){
unsigned long err;
err=ERR_get_error();
fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL));
return NULL;
}
}
else {
fprintf(stderr, "failed to open: %s\n", fname);
}
sc->server_key = getKey(fname);
sc->mitm = 1;
srv->so._send = ssl_send;
srv->so._recv = ssl_recv;
@ -359,6 +346,29 @@ static void* ssl_filter_open(void * idata, struct srvparam * srv){
srv->so._poll = ssl_poll;
#ifdef WIWHSPLICE
srv->usesplice = 0;
#endif
}
if(serv){
if(!srvcert || !srvkey) return sc;
sc->server_cert = getCert(srvcert);
if(!sc->server_cert){
fprintf(stderr, "failed to read: %s\n", srvcert);
return sc;
}
sc->server_key = getKey(srvkey);
if(!sc->server_key){
fprintf(stderr, "failed to read: %s\n", srvkey);
return sc;
}
sc->serv = 1;
srv->so._send = ssl_send;
srv->so._recv = ssl_recv;
srv->so._sendto = ssl_sendto;
srv->so._recvfrom = ssl_recvfrom;
srv->so._closesocket = ssl_closesocket;
srv->so._poll = ssl_poll;
#ifdef WIWHSPLICE
srv->usesplice = 0;
#endif
}
return sc;
@ -375,13 +385,43 @@ static FILTER_ACTION ssl_filter_client(void *fo, struct clientparam * param, voi
ssls->param = param;
param->sostate = ssls;
*fc = ssls;
if(ssls->config->serv){
SSL_CONN ClientConn;
char *err;
#ifdef _WIN32
ul = 0;
ioctlsocket(param->clisock, FIONBIO, &ul);
#else
fcntl(param->clisock,F_SETFL,0);
#endif
ClientConn = ssl_handshake_to_client(param->clisock, ssls->config->server_cert, ssls->config->server_key, &err);
if ( ClientConn == NULL ) {
param->res = 8013;
param->srv->logfunc(param, (unsigned char *)"Handshake to client failed");
if(err)param->srv->logfunc(param, (unsigned char *)err);
return REJECT;
}
#ifdef _WIN32
ul = 1;
ioctlsocket(param->clisock, FIONBIO, &ul);
#else
fcntl(param->clisock,F_SETFL,O_NONBLOCK);
#endif
SSL_set_mode((SSL *)((ssl_conn *)ClientConn)->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_AUTO_RETRY);
SSL_set_read_ahead((SSL *)((ssl_conn *)ClientConn)->ssl, 0);
addSSL(param->clisock, ClientConn, INVALID_SOCKET, NULL, param);
}
return CONTINUE;
}
static FILTER_ACTION ssl_filter_predata(void *fc, struct clientparam * param){
if(param->operation != HTTP_CONNECT && param->operation != CONNECT) return PASS;
if(!PCONF->mitm) return PASS;
if(dossl(param, NULL, NULL)) {
if(domitm(param, NULL, NULL)) {
return REJECT;
}
if(!param->redirectfunc) param->redirectfunc = proxyfunc;
@ -399,17 +439,15 @@ static void ssl_filter_close(void *fo){
free(CONFIG->certcache);
if ( CONFIG->CA_cert != NULL ) {
X509_free(CONFIG->CA_cert);
CONFIG->CA_cert = NULL;
}
if ( CONFIG->server_cert != NULL ) {
X509_free(CONFIG->server_cert);
}
if ( CONFIG->CA_key != NULL ) {
EVP_PKEY_free(CONFIG->CA_key);
CONFIG->CA_key = NULL;
}
if ( CONFIG->server_key != NULL ) {
EVP_PKEY_free(CONFIG->server_key);
CONFIG->server_key = NULL;
}
free(fo);
}
@ -427,8 +465,8 @@ static struct filter ssl_filter_mitm = {
static int h_mitm(int argc, unsigned char **argv){
if((mitm&1)) return 1;
if(mitm) usleep(100*SLEEPTIME);
if(mitm) return 1;
if(serv) return 2;
ssl_filter_mitm.next = pl->conf->filters;
pl->conf->filters = &ssl_filter_mitm;
sso = *pl->so;
@ -450,6 +488,42 @@ static int h_nomitm(int argc, unsigned char **argv){
return 0;
}
static struct filter ssl_filter_serv = {
NULL,
"ssl filter",
"serv",
ssl_filter_open,
ssl_filter_client,
NULL, NULL, NULL, NULL, NULL, NULL,
ssl_filter_clear,
ssl_filter_close
};
static int h_serv(int argc, unsigned char **argv){
if(serv) return 1;
if(mitm) return 2;
ssl_filter_serv.next = pl->conf->filters;
pl->conf->filters = &ssl_filter_serv;
sso = *pl->so;
serv = 1;
return 0;
}
static int h_noserv(int argc, unsigned char **argv){
struct filter * sf;
if(!mitm) return 1;
if(pl->conf->filters == &ssl_filter_serv) pl->conf->filters = ssl_filter_serv.next;
else for(sf = pl->conf->filters; sf && sf->next; sf=sf->next){
if(sf->next == &ssl_filter_serv) {
sf->next = ssl_filter_serv.next;
break;
}
}
serv = 0;
return 0;
}
static int h_certcache(int argc, unsigned char **argv){
size_t len;
len = strlen((char *)argv[1]);
@ -459,9 +533,25 @@ static int h_certcache(int argc, unsigned char **argv){
return 0;
}
static int h_srvcert(int argc, unsigned char **argv){
free(srvcert);
srvcert = strdup((char *)argv[1]);
return 0;
}
static int h_srvkey(int argc, unsigned char **argv){
free(srvkey);
srvkey = strdup((char *)argv[1]);
return 0;
}
static struct commands ssl_commandhandlers[] = {
{ssl_commandhandlers+1, "ssl_mitm", h_mitm, 1, 1},
{ssl_commandhandlers+2, "ssl_nomitm", h_nomitm, 1, 1},
{ssl_commandhandlers+3, "ssl_serv", h_serv, 1, 1},
{ssl_commandhandlers+4, "ssl_noserv", h_serv, 1, 1},
{ssl_commandhandlers+5, "ssl_srvcert", h_srvcert, 2, 2},
{ssl_commandhandlers+6, "ssl_srvkey", h_srvkey, 2, 2},
{NULL, "ssl_certcache", h_certcache, 2, 2},
};
@ -479,7 +569,7 @@ PLUGINAPI int PLUGINCALL ssl_plugin (struct pluginlink * pluginlink,
if(!ssl_loaded){
ssl_loaded = 1;
ssl_init();
ssl_commandhandlers[2].next = pl->commandhandlers->next;
ssl_commandhandlers[6].next = pl->commandhandlers->next;
pl->commandhandlers->next = ssl_commandhandlers;
}