Skip to content

Instantly share code, notes, and snippets.

@caiorss
Last active November 5, 2021 07:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save caiorss/bb884fd36b8930cb7358133c2afe9b56 to your computer and use it in GitHub Desktop.
Save caiorss/bb884fd36b8930cb7358133c2afe9b56 to your computer and use it in GitHub Desktop.
Sample TCP/IP with TLS encapsulation
-----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-----
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} )
-----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-----
#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