386 lines
12 KiB
C
386 lines
12 KiB
C
/*
|
|
JS 2024-04-11 testovane s OpenSSL 3.3.0, liboqs 0.10.0 a oqs-provider 0.6.0
|
|
*/
|
|
/*
|
|
JS 2024-04-11 testovane s OpenSSL 3.3.0, liboqs 0.10.0 a oqs-provider 0.5.3
|
|
*/
|
|
/*
|
|
JS 2024-03-04 - doplnenie funkcii pre uvolnenie nacitanych providerov
|
|
*/
|
|
|
|
/*
|
|
JS 2024-02-24 - funkcia initSSLContext() rozsirena o nacitanie OQS-providera
|
|
pre plne funkcne PQ algoritmy na kazdej platforme
|
|
- doplnene priklady nastavenia premennej DEFAULT_GROUPS
|
|
- testovane s oqsprovider 0.5.3
|
|
*/
|
|
/*
|
|
JS 2024-02-18 - testovanie PQ algoritmov s pouzitim oqs-providera
|
|
- uprava vypisu o pripojeni klienta
|
|
- pridane vypisy s informaciami o pouzivanych algoritmoch
|
|
pre KEX a certifikaty
|
|
- oprava kontroly navratovej hodnoty funkcii
|
|
SSL_CTX_use_certificate_file() a SSL_CTX_use_PrivateKey_file
|
|
*/
|
|
|
|
/*
|
|
JS 2024-02-08 testovane s aktualnou najnovsou verziou OpenSSL 3.2.1
|
|
*/
|
|
|
|
/*
|
|
MJ 2023-05-18 - Uprava funkcie printHeader()
|
|
-> Zmazanie SSL metody
|
|
-> Upraveny vypis ako spustit program
|
|
- Uprava funkcie initSSLContext() aby realizovala fixne iba TLS spojenie
|
|
-> pridanie argumentov do funkcie na nacitanie client.key, client.pem
|
|
- Uprava hlavnej funkcie main() na zaklade predoslej upravy (nastavenie fixne TLS)
|
|
-> Zmazanie premennej ctxMethod
|
|
-> Uprava argumentov [argv] - zmazanie TLS metody, pridanie suborov s klucmi
|
|
-> Pridanie premennych na nacitanie klucov: client_key, client_pem
|
|
(vid. komentare MJ)
|
|
*/
|
|
|
|
/*
|
|
MD 2021-03-29 testovane s aktualne najnovsou verziou OpenSSL v 1.1.1k
|
|
MD 2018-11-06 upravene pre linkovanie s OpenSSL 1.1.1
|
|
(pouzita metoda TLS_client_method)
|
|
MD 2018-11-02 vlozene upravy na odstraneie varovania a autentizaciu servera
|
|
vlozene upravy na realizaciu autentizacie klienta (nacitanie potrebnych certifikatov
|
|
a kluca)
|
|
odstranenie varovania o poradi hlavickovych suborov
|
|
(vid. komentare // MD)
|
|
*/
|
|
|
|
/** SSL/TLS Client
|
|
* SSL/TLS client demonstration. This source code is cross-plateforme Windows and Linux.
|
|
*/
|
|
|
|
// __unix__ is usually defined by compilers targeting Unix systems
|
|
#ifdef __unix__
|
|
# include <unistd.h>
|
|
# include <sys/socket.h>
|
|
# include <resolv.h>
|
|
# include <netdb.h>
|
|
# define SOCKLEN_T socklen_t
|
|
# define CLOSESOCKET close
|
|
// _Win32 is usually defined by compilers targeting 32 or 64 bit Windows systems
|
|
#elif defined _WIN32
|
|
// MD odstrani varovanie o potrebe prehodit poradie hlavickovych suborov
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# include <windows.h>
|
|
# include <winsock2.h>
|
|
# define SOCKLEN_T int
|
|
# define CLOSESOCKET closesocket
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
|
|
#include <openssl/crypto.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/pem.h>
|
|
#include <openssl/ssl.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/provider.h>
|
|
|
|
#ifdef _WIN32
|
|
WSADATA wsa; // Winsock data
|
|
#endif
|
|
|
|
/* JS
|
|
Premenna na definovanie "exchange groups", algoritmov na vymenu klucov
|
|
Server moze podporovat viacero KEX/KEM algoritmov, v premennej musi byt kazdy
|
|
algoritmus oddeleny dvojbodkou, napr. "kyber512:bikel1"
|
|
Podporovane algoritmy je mozne ziskat prikazom "openssl list -kem-algorithms"
|
|
Prazdna premenna alebo naplnena neplatnymi protokolmi sposobi prerusenie aplikacie
|
|
|
|
Ak server a klient nenajdu spolocny KEX/KEM protokol, tak
|
|
SSL vyhodi chybu SSL routines:final_key_share:no suitable key share
|
|
|
|
Priklad pouzitia:
|
|
- klasicke algoritmy: "x25519:x448:prime256v1:secp521r1:secp384r1:ffdhe2048:ffdhe3072"
|
|
- PQ algoritmy: "kyber512:kyber768:kyber1024:bikel1:bikel3:bikel5:hqc128:hqc192:hqc256:frodo640aes:frodo640shake:frodo976aes:frodo976shake:frodo1344aes:frodo1344shake"
|
|
- hybrid algoritmy: "x25519_kyber768:x25519_frodo640aes:x25519_hqc128:x448_bikel3:x448_kyber768:p256_kyber768"
|
|
|
|
Podporovane algoritmy OQS-providerom: https://github.com/open-quantum-safe/oqs-provider/blob/0.6.0/ALGORITHMS.md
|
|
|
|
POZOR - BIKE protokol nefunguje na Windows platforme (liboqs 0.10.0, oqs-provider 0.6.0)
|
|
|
|
*/
|
|
#define DEFAULT_GROUPS "kyber512:X25519:kyber768"
|
|
|
|
#define DEFAULT_PORT 443
|
|
|
|
/**
|
|
* printUsage function who describe the utilisation of this script.
|
|
* @param char* bin : the name of the current binary.
|
|
*/
|
|
void printHeader(char* bin){
|
|
// JS update
|
|
printf("[?] Usage : %s <hostname> <port> <client_private_key> <client_public_key>\n", bin);
|
|
return;
|
|
}
|
|
|
|
/** JS update navratove hodnoty pri chybe
|
|
* makeClientSocket function who create a traditionnal client socket to the hostname throught the port.
|
|
* @param char* hostname : the target to connect to
|
|
* @param int port : the port to connect throught
|
|
* @return int socket ; the socket number created
|
|
*/
|
|
int makeClientSocket(const char *hostname, int port){
|
|
int sock;
|
|
struct hostent *host;
|
|
struct sockaddr_in addr;
|
|
#ifdef _WIN32
|
|
WSAStartup(MAKEWORD(2,0),&wsa);
|
|
#endif
|
|
if((host = gethostbyname(hostname)) == NULL ){
|
|
perror(hostname);
|
|
return -1;
|
|
}
|
|
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(port);
|
|
addr.sin_addr.s_addr = *(long*)(host->h_addr);
|
|
if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0){
|
|
CLOSESOCKET(sock);
|
|
perror(hostname);
|
|
return -1;
|
|
}
|
|
return sock;
|
|
}
|
|
|
|
/** JS update
|
|
* initSSLContext function who initialize the SSL/TLS engine with right method/protocol
|
|
* @param client_key name of file where is stored private key of client
|
|
* @param client_pem name of file where is stored public key of client
|
|
* @return SSL_CTX *ctx ; a pointer to the SSL context created
|
|
*/
|
|
SSL_CTX* initSSLContext(char* client_key, char* client_pem){
|
|
const SSL_METHOD *method;
|
|
SSL_CTX *ctx;
|
|
|
|
// initialize the SSL library
|
|
SSL_library_init();
|
|
SSL_load_error_strings();
|
|
OpenSSL_add_all_algorithms();
|
|
|
|
// MJ only TLS connection
|
|
method = TLS_client_method();
|
|
|
|
// create new context from selected method
|
|
ctx = SSL_CTX_new(method);
|
|
if(ctx == NULL){
|
|
ERR_print_errors_fp(stderr);
|
|
abort();
|
|
}
|
|
|
|
// MD zabezpecienie overenia certifikatu servera pomocou CA
|
|
if (SSL_CTX_load_verify_locations(ctx, "myCA.pem", 0)) {
|
|
printf("CA certificate loaded\n");
|
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
|
}
|
|
|
|
else {
|
|
printf("\nCA certificate not loaded! Abort ...\n");
|
|
abort();
|
|
}
|
|
|
|
// MD nacitanie dat pre autentizaciu klineta
|
|
// MJ Update [Define Macro]
|
|
#ifdef AUTHENTICATION
|
|
int res = 0;
|
|
|
|
res = SSL_CTX_use_certificate_file(ctx, client_pem, SSL_FILETYPE_PEM);
|
|
if (res <= 0) {
|
|
// handle error
|
|
printf("\nCLIENT certificate not loaded! Abort ...\n");
|
|
abort();
|
|
}
|
|
|
|
res = SSL_CTX_use_PrivateKey_file(ctx, client_key, SSL_FILETYPE_PEM);
|
|
if (res <= 0) {
|
|
// handle error
|
|
|
|
printf("\nCLIENT key not loaded! Abort ...\n");
|
|
abort();
|
|
}
|
|
|
|
/* verify private key */
|
|
if ( !SSL_CTX_check_private_key(ctx) )
|
|
{
|
|
fprintf(stderr, "Private key does not match the public certificate\n");
|
|
abort();
|
|
}
|
|
printf("Certificate attached\n");
|
|
printf("\n");
|
|
#endif
|
|
|
|
return ctx;
|
|
}
|
|
|
|
/**
|
|
* showCerts function who catch and print out certificat's data from the server
|
|
* @param SSL* ssl : the SSL/TLS connection
|
|
*/
|
|
void showCerts(SSL* ssl){
|
|
X509 *cert;
|
|
char *subject, *issuer;
|
|
|
|
// get the server's certificate
|
|
cert = SSL_get_peer_certificate(ssl);
|
|
if(cert != NULL){
|
|
|
|
// JS get server's certificate algorithm name
|
|
int nid;
|
|
SSL_get_peer_signature_type_nid(ssl, &nid);
|
|
printf("Server signature algorithm: %s\n", OBJ_nid2sn(nid));
|
|
|
|
// get certificat's subject
|
|
subject = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
|
|
|
|
// get certificat's issuer
|
|
issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
|
|
|
|
printf("[+] Server certificates :\n");
|
|
printf("\tSubject: %s\n", subject);
|
|
printf("\tIssuer: %s\n", issuer);
|
|
|
|
// Free memory
|
|
free(subject);
|
|
free(issuer);
|
|
X509_free(cert);
|
|
|
|
// check certificat's trust
|
|
if(SSL_get_verify_result(ssl) == X509_V_OK)
|
|
printf("[+] Server certificates X509 is trust!\n");
|
|
else
|
|
printf("[-] Server certificates X509 is not trust...\n");
|
|
}
|
|
else
|
|
printf("[-] No server's certificates\n");
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* main function who coordinate the socket and SSL connection creation, then receive and emit
|
|
data to and from the server.
|
|
*/
|
|
int main(int argc, char **argv){
|
|
int sock, bytes, port;
|
|
SSL_CTX *ctx;
|
|
SSL *ssl;
|
|
char buf[1024];
|
|
char *hostname;
|
|
|
|
if(argc != 5){
|
|
printHeader(argv[0]);
|
|
exit(0);
|
|
}
|
|
|
|
// MJ Add keys for communication
|
|
char *client_key = argv[3];
|
|
char *client_pem = argv[4];
|
|
|
|
hostname = argv[1];
|
|
|
|
// Assign correct port number
|
|
port = (atoi(argv[2]) > 0 && atoi(argv[2]) < 65535) ? atoi(argv[2]) : DEFAULT_PORT;
|
|
|
|
// JS update
|
|
// Load default and OQS providers
|
|
// Default provider must be loaded before OQS provider
|
|
// Providers have to loaded before SSL/TLS engine initSSLContext()
|
|
OSSL_PROVIDER* provider;
|
|
provider = OSSL_PROVIDER_load(NULL, "default");
|
|
if (provider == NULL) {
|
|
printf("Failed to load Default provider\n");
|
|
exit(0);
|
|
}
|
|
|
|
OSSL_PROVIDER* custom_provider = OSSL_PROVIDER_load(NULL, "oqsprovider");
|
|
if (custom_provider == NULL){
|
|
printf("Failed to load OQS-provider\n");
|
|
OSSL_PROVIDER_unload(provider);
|
|
exit(0);
|
|
}
|
|
|
|
// load SSL library and dependances
|
|
ctx = initSSLContext(client_key, client_pem);
|
|
|
|
// make a classic socket to the hostname throught the port
|
|
sock = makeClientSocket(hostname, port);
|
|
|
|
// create new SSL connection state
|
|
ssl = SSL_new(ctx);
|
|
|
|
// JS set key exchange/encapsulation protocols supported by server
|
|
// Without this function, client will use default X25519 protocol
|
|
// First protocol supported by both server and client will be used for KEX/KEM
|
|
// Empty DEFAULT_GROUPS or list of unsupported protocol by server will fail communication
|
|
if (SSL_set1_groups_list(ssl, DEFAULT_GROUPS) != 1){
|
|
printf("KEX/KEM algorithms undefined - check DEFAULT_GROUPS variable\n");
|
|
ERR_print_errors_fp(stderr);
|
|
SSL_free(ssl);
|
|
SSL_CTX_free(ctx);
|
|
OSSL_PROVIDER_unload(provider);
|
|
OSSL_PROVIDER_unload(custom_provider);
|
|
exit(0);
|
|
}
|
|
|
|
// attach the socket descriptor
|
|
SSL_set_fd(ssl, sock);
|
|
|
|
// make the SSL connection
|
|
if(SSL_connect(ssl) == -1)
|
|
ERR_print_errors_fp(stderr);
|
|
else{
|
|
|
|
// JS get chosen (negotiated) key exchange/encapsulation algorithm name
|
|
printf("Used group (KEM): %s\n", SSL_group_to_name(ssl, SSL_get_negotiated_group(ssl)));
|
|
|
|
/*
|
|
if the server suddenly wants a new handshake,
|
|
OpenSSL handles it in the background. Without this
|
|
option, any read or write operation will return an
|
|
error if the server wants a new handshake.
|
|
*/
|
|
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
|
|
|
char msg[] = "ClientName";
|
|
printf("[+] Cipher used : %s\n", SSL_get_cipher(ssl));
|
|
|
|
// Show certificats data
|
|
showCerts(ssl);
|
|
|
|
// encrypt and send message
|
|
SSL_write(ssl, msg, strlen(msg));
|
|
|
|
// get response and decrypt content
|
|
bytes = SSL_read(ssl, buf, sizeof(buf));
|
|
buf[bytes] = 0;
|
|
printf("[+] Server data received : %s\n", buf);
|
|
|
|
// release SSL connection state
|
|
SSL_shutdown(ssl);
|
|
SSL_free(ssl);
|
|
|
|
}
|
|
|
|
// close socket
|
|
CLOSESOCKET(sock);
|
|
#ifdef _WIN32
|
|
WSACleanup();
|
|
#endif
|
|
|
|
// release SSL's context
|
|
SSL_CTX_free(ctx);
|
|
// JS Unload both providers
|
|
OSSL_PROVIDER_unload(provider);
|
|
OSSL_PROVIDER_unload(custom_provider);
|
|
return 0;
|
|
}
|