Last active
November 5, 2021 07:39
-
-
Save caiorss/bb884fd36b8930cb7358133c2afe9b56 to your computer and use it in GitHub Desktop.
Sample TCP/IP with TLS encapsulation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-----BEGIN CERTIFICATE----- | |
MIIDJDCCAo2gAwIBAgIUV1vMUJT+X+jLfkRDgFB2J0dhun4wDQYJKoZIhvcNAQEL | |
BQAwgaMxCzAJBgNVBAYTAlVLMRAwDgYDVQQIDAdCcmlzdG9sMRIwEAYDVQQHDAlZ | |
b3Jrc2hpcmUxFTATBgNVBAoMDHNvbWUgY29tcGFueTEZMBcGA1UECwwQZHVtbXkg | |
ZGVwYXJ0bWVudDEZMBcGA1UEAwwQd3d3Lm15c2VydmVyLmNvbTEhMB8GCSqGSIb3 | |
DQEJARYSY29tcGFueUBtYWlsLmNvLmRlMB4XDTIwMTIwOTIyMjUwOVoXDTM0MDgx | |
ODIyMjUwOVowgaMxCzAJBgNVBAYTAlVLMRAwDgYDVQQIDAdCcmlzdG9sMRIwEAYD | |
VQQHDAlZb3Jrc2hpcmUxFTATBgNVBAoMDHNvbWUgY29tcGFueTEZMBcGA1UECwwQ | |
ZHVtbXkgZGVwYXJ0bWVudDEZMBcGA1UEAwwQd3d3Lm15c2VydmVyLmNvbTEhMB8G | |
CSqGSIb3DQEJARYSY29tcGFueUBtYWlsLmNvLmRlMIGfMA0GCSqGSIb3DQEBAQUA | |
A4GNADCBiQKBgQDzc8SMhm7VBqeGXR0v8+d+zfUwtcchR8KLP/TzCTAnfl+dqUS5 | |
XeRQS/7XQdAX2nKmmfclxeHxH+5HadDCR2P38Ur/qjxmVyk1pMidss9E5MQVIYtN | |
JWHD7sRHUIi2Gdd3BjnYbzTwUZ+GeC5c2aXmM8QppPiOAcDHJ/5zv+o9LwIDAQAB | |
o1MwUTAdBgNVHQ4EFgQUUkiKo3hJvWWl4snshv8Fk9F/pMQwHwYDVR0jBBgwFoAU | |
UkiKo3hJvWWl4snshv8Fk9F/pMQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B | |
AQsFAAOBgQC47r7mF1+fvmGfBcjSWPeGcIRfSwwq6OUZAyBib5M0DGWvaKyVrDOE | |
fj4EVGkmo/ZgYSU48gwklPxoWvQC4WGMp71jHTnguffXd+oeWxATKYUmv6Dc5n1P | |
/3Mm5NeS875sW1XJb+NOGqawqM5Z6Ewhs7cDfCZxpGGNJJvP2NSKSw== | |
-----END CERTIFICATE----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.9) | |
project(Sample_SLL) | |
#========== Global Configurations =============# | |
#----------------------------------------------# | |
set(CMAKE_CXX_STANDARD 17) | |
set(CMAKE_VERBOSE_MAKEFILE ON ) | |
#----------- Set targets -------------------------------# | |
find_package( OpenSSL REQUIRED ) | |
add_executable( ssl-test ssl-test.cpp ) | |
target_link_libraries( ssl-test ${OPENSSL_LIBRARIES} ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-----BEGIN PRIVATE KEY----- | |
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPNzxIyGbtUGp4Zd | |
HS/z537N9TC1xyFHwos/9PMJMCd+X52pRLld5FBL/tdB0BfacqaZ9yXF4fEf7kdp | |
0MJHY/fxSv+qPGZXKTWkyJ2yz0TkxBUhi00lYcPuxEdQiLYZ13cGOdhvNPBRn4Z4 | |
LlzZpeYzxCmk+I4BwMcn/nO/6j0vAgMBAAECgYAUIzZV3WTbkCJZVehtKAK1FXo7 | |
nj2rfhEUjaTIWbE3AxgLpY2+u4qALdkVmycIYhRrvX6ZDEZFOLvwAku3VkppdaoY | |
81jXDpyEBSUVtEQPGB9UwnCiXaHlblIfH2T0z6HYsVh1jMkIkF0Zqd3YeDBy4+n8 | |
E1OfI4HNNXS3O/X/GQJBAPp4YhD7bhNTY/kOYbV2ruhp0obfdHWHmp5zkm7szmKw | |
I6JxrxTK55Te8t8jKxHIlGe89jnTkKMxw3KwxdiNC+sCQQD407hOafz3TkHLyZbU | |
4u8652rlmMb3Jc+UDiW4wbi/StKZ/NIqpLd+YrHGfwS6RJgYlXB20rQ2tGHECnKC | |
9JbNAkEAypNE1XFVVOIUMGIWWprT2fuEnzrpSQlU36SfoYF7ZswI9iA2N33oETrE | |
ef5KnkZ46PImvxxClgrwhbk9OujQ4wJBAM49LhZQYwvYIVD31by+G+uGxGNpLgDL | |
pjHhSALLDoX/Tm+zzb7qp+xpgVA1F4YMNMSrmHvkSNrOx/nlbuR8NkECQQDOd4lm | |
zW5KKibqEPjYhz68Jo1b5zNY1RXlzFQvUBSR032FZTDvtJT7B3UFiqT59yp0SsbT | |
kgBrnp408jsg5twu | |
-----END PRIVATE KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <cstring> // Equivalent to #include <string.h> in C | |
#include <cassert> // assert() macro. | |
// ----- Unix/Linux headers -----// | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netdb.h> | |
#include <limits.h> | |
#include <tuple> | |
// ----- OpenSSL headers -------// | |
#include <openssl/ssl.h> | |
#include <openssl/bio.h> | |
#include <openssl/err.h> | |
constexpr int FAILURE = -1; | |
constexpr int SSL_FAILURE = -1; | |
using SSL_Tuple = std::tuple<SSL_CTX*, SSL*>; | |
// Create and return a client socket and connecting to a hostname. | |
int socket_connect(const char* hostname, std::uint16_t port); | |
// Instantiate SSL data structures. | |
SSL_Tuple setup_ssl(); | |
// Shows certificate information. | |
void display_certificate(SSL* ssl); | |
int main(int argc, char** argv) | |
{ | |
if(argc < 3) | |
{ | |
std::fprintf(stderr, " Usage: %s <HOSTNAME> <PORT> \n", argv[0]); | |
return EXIT_FAILURE; | |
} | |
uint16_t port = std::stod(argv[2]); | |
const char* hostname = argv[1]; | |
const char* trust_cert_path = X509_get_default_cert_dir(); | |
std::fprintf( stderr, " [TRACE] X509 Trust Certificate Directory: %s \n" | |
, trust_cert_path); | |
// =========== SSL/TSL Initialization ===============// | |
//---------------------------------------------------// | |
// Requires C++ 17 | |
auto [ctx, ssl] = setup_ssl(); | |
//============ Connect to server =====================// | |
//----------------------------------------------------// | |
int sockfd = socket_connect(hostname, port); | |
// Encapsulate TCP protcol | |
SSL_set_fd(ssl, sockfd); | |
if( SSL_connect(ssl) == SSL_FAILURE ) | |
{ | |
std::fprintf(stderr, " [ERROR] Failure to setup SSL/TSL connection"); | |
ERR_print_errors_fp(stderr); | |
std::abort(); | |
} | |
std::fprintf(stdout, " [INFO] Connected to the server Ok. "); | |
// From OpenSSL library | |
display_certificate(ssl); | |
// Check certifcate | |
if( SSL_get_verify_result(ssl) == X509_V_OK ) { | |
std::fprintf(stdout, " [INFO] Certificate validated. Ok. \n"); | |
} else { | |
std::fprintf(stdout, " [ERROR] Certificate validation. => May be self signed. \n"); | |
ERR_print_errors_fp(stderr); | |
} | |
// ========= Session Loop =============================// | |
//-----------------------------------------------------// | |
constexpr size_t BUFFER_SIZE = 500; | |
// Null character '\0' initialized buffer | |
char buffer[BUFFER_SIZE] = {0}; | |
for(;;) | |
{ | |
ssize_t size = SSL_read(ssl, buffer, BUFFER_SIZE); | |
// Return 0 bytes when peer (server) closes connection. | |
if(size == 0) | |
{ | |
std::fprintf(stderr, " [INFO] Peer closed the connection. \n"); | |
break; | |
} | |
if(size == -1){ | |
std::fprintf(stderr, " [ERROR] Failed to read socket. \n"); | |
} | |
std::string msg = " [SERVER] " + std::string(buffer, buffer + size); | |
std::cout << msg << '\n'; | |
// Write back message to server. | |
SSL_write(ssl, msg.data(), msg.size() ); | |
} | |
// ========= Dispose Resources ========================// | |
//-----------------------------------------------------// | |
// Dispose resource (file descriptor) | |
close(sockfd); | |
// Release SSL context | |
SSL_CTX_free(ctx); | |
} | |
//==================================================// | |
// I M P L E M E N T A T I O N S // | |
//==================================================// | |
int | |
socket_connect(const char* hostname, std::uint16_t port) | |
{ | |
int sockfd = socket ( AF_INET, SOCK_STREAM, 0); | |
// assert() => Placeholder for future error handling. | |
assert( sockfd != FAILURE ); | |
// Query DNS | |
struct hostent* h = gethostbyname(hostname); | |
assert( h != nullptr ); | |
struct sockaddr_in sa; | |
std::memcpy(&sa.sin_addr.s_addr, h->h_addr, h->h_length); | |
sa.sin_family = AF_INET; | |
sa.sin_port = htons(port); | |
int res = connect( sockfd | |
, reinterpret_cast<sockaddr*>(&sa) | |
, sizeof(sockaddr_in)); | |
assert( res != FAILURE && "Failure to connect => Check errno. " ); | |
return sockfd; | |
} | |
SSL_Tuple | |
setup_ssl() | |
{ | |
SSL_load_error_strings(); | |
ERR_load_BIO_strings(); | |
OpenSSL_add_all_algorithms(); | |
SSL_library_init(); | |
// Instantiate SSL method | |
const SSL_METHOD* method = SSLv23_method(); | |
assert( method != nullptr && "Failure to load SSL method."); | |
// Create SSL context (ctx) | |
SSL_CTX* ctx = SSL_CTX_new( method ); | |
if( ctx == nullptr ) | |
{ | |
std::fprintf(stderr, " [ERROR] Failed to create SSL context \n"); | |
ERR_print_errors_fp(stderr); | |
std::abort(); | |
} | |
if( !SSL_CTX_set_default_verify_paths(ctx) ) | |
{ | |
std::fprintf(stderr, " [ERROR] Failure to set default trusted CA paths"); | |
ERR_print_errors_fp(stderr); | |
exit(EXIT_FAILURE); | |
} | |
SSL* ssl = SSL_new(ctx); | |
assert( ssl != nullptr ); | |
return SSL_Tuple{ ctx, ssl }; | |
} | |
void | |
display_certificate(SSL* ssl) | |
{ | |
X509* cert = SSL_get_peer_certificate(ssl); | |
if( cert == nullptr ) | |
{ | |
std::fprintf(stderr, " [ERROR] Failed to get certificate \n"); | |
ERR_print_errors_fp(stderr); | |
return; | |
} | |
char* out = nullptr; | |
long version = X509_get_version(cert); | |
std::fprintf(stdout, " [CERTIFICATE] version = %d \n", version); | |
out = X509_NAME_oneline( X509_get_subject_name(cert), 0, 0); | |
std::fprintf(stdout, " [CERTIFICATE] name = %s \n", out); | |
free(out); | |
out = X509_NAME_oneline( X509_get_issuer_name(cert), 0, 0); | |
std::fprintf(stdout, " [CERTIFICATE] issuer = %s \n", out); | |
free(out); | |
X509_free(cert); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment