tuyau

Client/server for transfering files (like cp)
git clone https://noulin.net/git/tuyau.git
Log | Files | Refs | README

commit 66046d1bf1b0b4c2f421389510bed001e142993a
parent db981a13c3bc35f7114644bbc785a9b62a68f762
Author: Remy Noulin <loader2x@gmail.com>
Date:   Fri, 19 Aug 2022 02:51:10 -0400

use tls encryption when transfering data

genCert.sh        |   2 +-
netFrame.c        |  50 +++++++++-----------------
netFrame.h        |   9 ++---
package.yml       |   6 ++--
sclient.c         |  54 ++++++++++++++++++++--------
serverPackage.yml |   6 ++--
sserver.c         | 103 ++++++++++++++++++++++++++++++++++++++++++++++--------
7 files changed, 156 insertions(+), 74 deletions(-)

Diffstat:
MgenCert.sh | 2+-
MnetFrame.c | 50++++++++++++++++----------------------------------
MnetFrame.h | 9+++++----
Mpackage.yml | 6+++---
Msclient.c | 54++++++++++++++++++++++++++++++++++++++++--------------
MserverPackage.yml | 6+++---
Msserver.c | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
7 files changed, 156 insertions(+), 74 deletions(-)

diff --git a/genCert.sh b/genCert.sh @@ -1 +1 @@ -LD_LIBRARY_PATH=/usr/local/lib64/ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj '/CN=localhost' +openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj '/CN=localhost' diff --git a/netFrame.c b/netFrame.c @@ -2,7 +2,6 @@ /* Libsheepy documentation: https://spartatek.se/libsheepy/ */ -#include "libsheepyObject.h" #include "netFrame.h" #include "netFrameInternal.h" @@ -23,10 +22,10 @@ local void smashNetFrame(netFramet **self); local void finishNetFrame(netFramet **self); local const char* helpNetFrame(netFramet *self); local void setCallbackNetFrame(netFramet *self, callBackNetFramet callback, void* context); -local bool sendNetFrame(netFramet *self, int sock, void* buf, size_t size); -local bool receiveNetFrame(netFramet *self, int sock); -local bool receiveOneNetFrame(netFramet *self, int sock); -local bool endNetFrame(netFramet *self, int sock); +local bool sendNetFrame(netFramet *self, SSL *ssl, void* buf, size_t size); +local bool receiveNetFrame(netFramet *self, SSL *ssl); +local bool receiveOneNetFrame(netFramet *self, SSL *ssl); +local bool endNetFrame(netFramet *self, SSL *ssl); /* enable/disable logging */ /* #undef pLog */ @@ -161,25 +160,15 @@ local void setCallbackNetFrame(netFramet *self, callBackNetFramet callback, void } -local bool sendNetFrame(netFramet *self UNUSED, int sock, void* buf, size_t size) { +local bool sendNetFrame(netFramet *self UNUSED, SSL *ssl, void* buf, size_t size) { ssize_t status; // for netsend #define netsend(B,SZ,FLGS) procbegin\ UNIQVAR(retry):\ - if ((status = send(sock, B, SZ, (FLGS) | MSG_NOSIGNAL)) < 0) {\ - if (errno == EAGAIN or errno == EINTR) {\ - /* TODO this happens when the socket is in nonblocking mode */\ - /* in my tests, there are data losses when size is larger than 1MBytes */\ - /* this is a simple solution equivalent to blocking */\ - /* a better solution is to keep running in the event loop */\ - /* for large transfers */\ - /* When EINTR is received, the send call was interrupted by a signal */\ - /* restart the send call when it happens */\ - goto UNIQVAR(retry);\ - }\ - shPrintError;\ - shperror("Netframe send socket error");\ + if ((status = SSL_write(ssl, B, SZ)) < 0) {\ + /* TODO SSL_get_error() */\ + shperror("Netframe send ssl error");\ ret no;\ }\ procend @@ -203,7 +192,7 @@ local bool sendNetFrame(netFramet *self UNUSED, int sock, void* buf, size_t size } -local bool receiveNetFrame(netFramet *self, int sock) { +local bool receiveNetFrame(netFramet *self, SSL *ssl) { if (!self->callback) ret no; size_t size; @@ -212,17 +201,8 @@ local bool receiveNetFrame(netFramet *self, int sock) { #define netrecv(B, SZ, FLGS, CHECK, ENOUGH, ERROR) procbegin\ UNIQVAR(retry):\ - if ((status = recv(sock, B, SZ, FLGS)) < 0) {\ - if (errno == EAGAIN or errno == EINTR) {\ - /* TODO this happens when the socket is in nonblocking mode */\ - /* this is a simple solution equivalent to blocking */\ - /* a better solution is to keep running in the event loop */\ - /* for large transfers */\ - /* When EINTR is received, the recv call was interrupted by a signal */\ - /* restart the recv call when it happens */\ - goto UNIQVAR(retry);\ - }\ - shPrintError;\ + if ((status = SSL_read(ssl, B, SZ)) < 0) {\ + /* TODO SSL_get_error() */\ shperror("Netframe recv socket error");\ ERROR;\ ret no;\ @@ -241,6 +221,7 @@ local bool receiveNetFrame(netFramet *self, int sock) { if (isFirstFrame) { /* the first frame has size 0, this is a request to close the connection */ logD("close socket"); + int sock = SSL_get_fd(ssl); close(sock); } break; @@ -268,7 +249,7 @@ local bool receiveNetFrame(netFramet *self, int sock) { ret yes; } -local bool receiveOneNetFrame(netFramet *self, int sock) { +local bool receiveOneNetFrame(netFramet *self, SSL *ssl) { if (!self->callback) ret no; size_t size; @@ -281,6 +262,7 @@ local bool receiveOneNetFrame(netFramet *self, int sock) { if (!size) { // a frame size 0 is a request to close the connection logD("close socket"); + int sock = SSL_get_fd(ssl); close(sock); ret yes; } @@ -302,8 +284,8 @@ local bool receiveOneNetFrame(netFramet *self, int sock) { ret yes; } -local bool endNetFrame(netFramet *self, int sock) { - ret sendNetFrame(self, sock, null, 0); +local bool endNetFrame(netFramet *self, SSL *ssl) { + ret sendNetFrame(self, ssl, null, 0); } diff --git a/netFrame.h b/netFrame.h @@ -42,6 +42,7 @@ * receive waits for frames until a frame size 0 is received */ +#include <openssl/ssl.h> #include "libsheepyObject.h" /* Class netFrame */ @@ -87,17 +88,17 @@ typ void (*setCallbackNetFrameFt)(netFramet *self, callBackNetFramet callback, v /** * send buf, size 0 means end of transaction */ -typ bool (*sendNetFrameFt)(netFramet *self, int sock, void* buf, size_t size); +typ bool (*sendNetFrameFt)(netFramet *self, SSL *ssl, void* buf, size_t size); /** * receive frames until the socket is closed by the client */ -typ bool (*receiveNetFrameFt)(netFramet *self, int sock); +typ bool (*receiveNetFrameFt)(netFramet *self, SSL *ssl); /** * receive one frame and return */ -typ bool (*receiveOneNetFrameFt)(netFramet *self, int sock); +typ bool (*receiveOneNetFrameFt)(netFramet *self, SSL *ssl); /** * end transaction or inform the server that the connection is going to be closed @@ -110,7 +111,7 @@ typ bool (*receiveOneNetFrameFt)(netFramet *self, int sock); * - when finished send a frame size 0 meaning end of transaction * - to close the connection, send a frame size 0 again */ -typ bool (*endNetFrameFt)(netFramet *self, int sock); +typ bool (*endNetFrameFt)(netFramet *self, SSL *ssl); /** * class functions diff --git a/package.yml b/package.yml @@ -1,10 +1,10 @@ --- name: tuyau - version: 0.0.3 + version: 0.0.4 description: "Client for copying files to tuyauServer" bin: ./tuyau.c #cflags: -DA -g3 -std=gnu11 -fPIC -pipe - #lflags: -lpcre + lflags: -L/usr/lib -lssl -lcrypto repository: type: git url: git+https://github.com/USER/tuyau.git @@ -16,7 +16,7 @@ bugs: url: https://github.com/USER/tuyau/issues homepage: https://github.com/USER/tuyau#readme - #compileHelp: # text displayed when there is a compilation error + compileHelp: libssl-dev has to be installed in the system dependencies: short: # Test configuration: diff --git a/sclient.c b/sclient.c @@ -22,7 +22,6 @@ Downdload files: */ -#include "libsheepyObject.h" #include <netdb.h> #include <netinet/in.h> #include <string.h> @@ -34,7 +33,16 @@ Downdload files: #include <sys/stat.h> #include <fcntl.h> +// basename +#include <libgen.h> + +#include <openssl/err.h> +//#include <openssl/pem.h> +#include <openssl/ssl.h> +//#include <openssl/x509v3.h> + #include "netFrame.h" +#include "libsheepyObject.h" #include "shpPackages/short/short.h" #include "makeHeader.h" @@ -158,6 +166,7 @@ int main(int ARGC, char** ARGV) { struct hostent *hp; int rval; + cleanAllocateNetFrame(netframe); @@ -184,6 +193,20 @@ int main(int ARGC, char** ARGV) { XFailure; } + SSL_CTX *ssl_ctx; + SSL *ssl; + ssl_ctx = SSL_CTX_new(TLS_method()); + BIO *sbio = BIO_new(BIO_f_ssl()); + ssl = SSL_new(ssl_ctx); + // attach the socket descriptor + SSL_set_fd(ssl, sock); + + // perform the connection + if (SSL_connect(ssl) == -1) { + logE("Couldn't establish the TLS connection"); + ret 1; + } + // buffer for network packets u8 buf[1024*1024] = init0Var; @@ -193,11 +216,11 @@ int main(int ARGC, char** ARGV) { u32 bufi = 0; makeHeader(buf, &bufi, 2 /* command */, svrInfo, null /*sendFile*/, destPath, null /*filesize*/); - o(netframe,send , sock, buf, bufi); + o(netframe,send , ssl, buf, bufi); o(netframe, setCallback, saveReceivedData, receivePath /*context*/); - var r = o(netframe,receive, sock); + var r = o(netframe,receive, ssl); logVarG(r); } @@ -235,7 +258,7 @@ int main(int ARGC, char** ARGV) { u64 *filesize = null; makeHeader(buf, &bufi, 1 /* command */, svrInfo, ssGet(p), dest, &filesize); - o(netframe,send , sock, buf, bufi); + o(netframe,send , ssl, buf, bufi); var dir = readDirAllG(rtSmallArrayt, p); //lv(dir); @@ -256,7 +279,7 @@ int main(int ARGC, char** ARGV) { if (*filesize < (sizeof(buf) - bufi)) { // the file is smaller than the network buffer, send all in one go pError0(bReadFile(sendFile, buf + bufi)); - o(netframe,send , sock, buf, bufi + *filesize); + o(netframe,send , ssl, buf, bufi + *filesize); } else { logD("big file"); @@ -268,16 +291,16 @@ int main(int ARGC, char** ARGV) { do { if (szToSend <= bSz) { read(fd, b, szToSend); - o(netframe,send , sock, b, szToSend); + o(netframe,send , ssl, b, szToSend); szToSend = 0; } else { read(fd, b, bSz); if (szToSend == *filesize) { - o(netframe,send , sock, buf, bufi + bSz); + o(netframe,send , ssl, buf, bufi + bSz); } else { - o(netframe,send , sock, b, bSz); + o(netframe,send , ssl, b, bSz); } szToSend -= bSz; } @@ -312,7 +335,7 @@ int main(int ARGC, char** ARGV) { u64 *filesize = null; makeHeader(buf, &bufi, 1 /* command */, svrInfo, localp, dest, &filesize); - o(netframe,send , sock, buf, bufi); + o(netframe,send , ssl, buf, bufi); var dir = readDirAllG(rtSmallArrayt, localp); lv(dir); @@ -335,7 +358,7 @@ int main(int ARGC, char** ARGV) { if (*filesize < (sizeof(buf) - bufi)) { // the file is smaller than the network buffer, send all in one go pError0(bReadFile(localp, buf + bufi)); - o(netframe,send , sock, buf, bufi + *filesize); + o(netframe,send , ssl, buf, bufi + *filesize); } else { logD("big file"); @@ -347,16 +370,16 @@ int main(int ARGC, char** ARGV) { do { if (szToSend <= bSz) { read(fd, b, szToSend); - o(netframe,send , sock, b, szToSend); + o(netframe,send , ssl, b, szToSend); szToSend = 0; } else { read(fd, b, bSz); if (szToSend == *filesize) { - o(netframe,send , sock, buf, bufi + bSz); + o(netframe,send , ssl, buf, bufi + bSz); } else { - o(netframe,send , sock, b, bSz); + o(netframe,send , ssl, b, bSz); } szToSend -= bSz; } @@ -369,11 +392,14 @@ int main(int ARGC, char** ARGV) { lv(recusive); // last frame size 0 - o(netframe,end, sock); + o(netframe,end, ssl); } // isReceive close(sock); + // release SSL state + SSL_free(ssl); + SSL_CTX_free(ssl_ctx); } diff --git a/serverPackage.yml b/serverPackage.yml @@ -1,10 +1,10 @@ --- name: tuyauServer - version: 0.0.2 + version: 0.0.3 description: "Server for copying files with tuyau" bin: ./tuyauServer.c #cflags: -DA -g3 -std=gnu11 -fPIC -pipe - #lflags: -lpcre + lflags: -L/usr/lib -lssl -lcrypto repository: type: git url: git+https://github.com/USER/tuyau.git @@ -16,7 +16,7 @@ bugs: url: https://github.com/USER/tuyau/issues homepage: https://github.com/USER/tuyau#readme - #compileHelp: # text displayed when there is a compilation error + compileHelp: libssl-dev has to be installed in the system dependencies: short: # Test configuration: diff --git a/sserver.c b/sserver.c @@ -2,7 +2,6 @@ /* or direct path to sheepy: #! /usr/local/bin/sheepy */ /* Libsheepy documentation: https://spartatek.se/libsheepy/ */ -#include "libsheepyObject.h" #include <netinet/in.h> #include <string.h> #include <stdlib.h> @@ -15,6 +14,20 @@ #include <glob.h> +#include <openssl/err.h> +//#include <openssl/pem.h> +#include <openssl/ssl.h> +//#include <openssl/x509v3.h> + +// inet_ntoa +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +// basename +#include <libgen.h> + +#include "libsheepyObject.h" #include "netFrame.h" #include "shpPackages/short/short.h" #include "makeHeader.h" @@ -26,6 +39,7 @@ int fd = -1; u64 transferSz = 0; // client socket int mysock = 0; +SSL *ssl; smallJsont *tokens = null; @@ -40,11 +54,53 @@ bool cb(void *buf, size_t size, void *context) { ret yes; } +void loadCertificates(SSL_CTX* ctx, char* certFilename, char* keyFilename) +{ + // set the local certificate + if (SSL_CTX_use_certificate_file(ctx, certFilename, SSL_FILETYPE_PEM) <= 0) { + logC("Error loadind cert file %s", certFilename); + XFailure; + } + // set the private key + if (SSL_CTX_use_PrivateKey_file(ctx, keyFilename, SSL_FILETYPE_PEM) <= 0) { + logC("Error loadind key file %s", keyFilename); + XFailure; + } + /* verify private key */ + if (!SSL_CTX_check_private_key(ctx)) { + logC("Private key does not match the public certificate", keyFilename); + XFailure; + } +} + int main(int ARGC, char** ARGV) { initLibsheepy(ARGV[0]); setLogMode(LOG_FUNC); + SSL_CTX *ctx; + ctx = SSL_CTX_new(TLS_server_method()); + int r = SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); + if (!SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION)) { + logE("Can't force minimum TLS 1.3"); + ret 1; + } + if (!SSL_CTX_set_cipher_list(ctx, + "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:" + "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:" + "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:" + "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:" + "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:" + "TLS_CHACHA20_POLY1305_SHA256")) { + logE("Can't set cipher list"); + ret 1; + } + + SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); + + loadCertificates(ctx, "cert.pem", "key.pem"); + + // Steps // load configuration // create tokens dict @@ -93,15 +149,32 @@ int main(int ARGC, char** ARGV) { // start event loop listen(sock, 5); forever { - mysock = accept(sock, (struct sockaddr *)0, 0); + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + mysock = accept(sock, (struct sockaddr *)&addr, &len); if (mysock == 1) perror("accept failed"); else { - var r = o(netframe,receive, mysock); - logVarG(r); + logI("Connection: %s:%d",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + // get new SSL state with context + ssl = SSL_new(ctx); + // set connection socket to SSL state + SSL_set_fd(ssl, mysock); + // do SSL-protocol accept + if (SSL_accept(ssl) == -1) { + logE("Accept SSL connection"); + } + else { + var r = o(netframe,receive, ssl); + logVarG(r); + } + // release SSL state + SSL_free(ssl); } } + SSL_CTX_free(ctx); + terminateG(tokens); } @@ -278,7 +351,7 @@ void saveReceivedData(void *receiveB, size_t sz) { u64 *filesize = null; makeHeader(buf, &bufi, 1 /* command */, null/*svrInfo no need to authenticate the client*/, ssGet(P), dirname/*dest*/, &filesize); - o(netframe,send , mysock, buf, bufi); + o(netframe,send , ssl, buf, bufi); var dir = readDirAllG(rtSmallArrayt, p); //lv(dir); @@ -299,7 +372,7 @@ void saveReceivedData(void *receiveB, size_t sz) { if (*filesize < (sizeof(buf) - bufi)) { // the file is smaller than the network buffer, send all in one go pError0(bReadFile(sendFile, buf + bufi)); - o(netframe,send , mysock, buf, bufi + *filesize); + o(netframe,send , ssl, buf, bufi + *filesize); } else { logD("big file"); @@ -311,16 +384,16 @@ void saveReceivedData(void *receiveB, size_t sz) { do { if (szToSend <= bSz) { read(fd, b, szToSend); - o(netframe,send , mysock, b, szToSend); + o(netframe,send , ssl, b, szToSend); szToSend = 0; } else { read(fd, b, bSz); if (szToSend == *filesize) { - o(netframe,send , mysock, buf, bufi + bSz); + o(netframe,send , ssl, buf, bufi + bSz); } else { - o(netframe,send , mysock, b, bSz); + o(netframe,send , ssl, b, bSz); } szToSend -= bSz; } @@ -353,7 +426,7 @@ void saveReceivedData(void *receiveB, size_t sz) { u64 *filesize = null; makeHeader(buf, &bufi, 1 /* command */, null/*svrInfo no need to authenticate the client*/, localp, dirname, &filesize); - o(netframe,send , mysock, buf, bufi); + o(netframe,send , ssl, buf, bufi); var dir = readDirAllG(rtSmallArrayt, localp); lv(dir); @@ -375,7 +448,7 @@ void saveReceivedData(void *receiveB, size_t sz) { if (*filesize < (sizeof(buf) - bufi)) { // the file is smaller than the network buffer, send all in one go pError0(bReadFile(localp, buf + bufi)); - o(netframe,send , mysock, buf, bufi + *filesize); + o(netframe,send , ssl, buf, bufi + *filesize); } else { logD("big file"); @@ -387,16 +460,16 @@ void saveReceivedData(void *receiveB, size_t sz) { do { if (szToSend <= bSz) { read(fd, b, szToSend); - o(netframe,send , mysock, b, szToSend); + o(netframe,send , ssl, b, szToSend); szToSend = 0; } else { read(fd, b, bSz); if (szToSend == *filesize) { - o(netframe,send , mysock, buf, bufi + bSz); + o(netframe,send , ssl, buf, bufi + bSz); } else { - o(netframe,send , mysock, b, bSz); + o(netframe,send , ssl, b, bSz); } szToSend -= bSz; } @@ -410,7 +483,7 @@ void saveReceivedData(void *receiveB, size_t sz) { // last frame size 0 // close connection - o(netframe,end, mysock); + o(netframe,end, ssl); } } else {