390 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			390 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|   JS 2024-05-07 - doplnene priklady nastavenia premennej DEFAULT_GROUPS, doplnene info o ML-KEM
 | |
|                 - testovane s WinLibs 13.2.0 release 8
 | |
| */
 | |
| /*
 | |
|   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: "mlkem512:mlkem768:mlkem1024: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 "mlkem512:hqc128: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;
 | |
| }
 |