Skip to content

Instantly share code, notes, and snippets.

@vedantroy
Last active April 8, 2024 22:26
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save vedantroy/d2b99d774484cf4ea5165b200888e414 to your computer and use it in GitHub Desktop.
Save vedantroy/d2b99d774484cf4ea5165b200888e414 to your computer and use it in GitHub Desktop.
A C++ Client That Sends Data Over TLS Using OpenSSL
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//Not sure what headers are needed or not
//This code (theoretically) writes "Hello World, 123" to a socket over a secure TLS connection
//compiled with g++ -Wall -o client.out client.cpp -L/usr/lib -lssl -lcrypto
//Based off of: https://www.cs.utah.edu/~swalton/listings/articles/ssl_client.c
//Some of the code was taken from this post: https://stackoverflow.com/questions/52727565/client-in-c-use-gethostbyname-or-getaddrinfo
const int ERROR_STATUS = -1;
SSL_CTX *InitSSL_CTX(void)
{
const SSL_METHOD *method = TLS_client_method(); /* Create new client-method instance */
SSL_CTX *ctx = SSL_CTX_new(method);
if (ctx == nullptr)
{
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
return ctx;
}
int OpenConnection(const char *hostname, const char *port)
{
struct hostent *host;
if ((host = gethostbyname(hostname)) == nullptr)
{
perror(hostname);
exit(EXIT_FAILURE);
}
struct addrinfo hints = {0}, *addrs;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
const int status = getaddrinfo(hostname, port, &hints, &addrs);
if (status != 0)
{
fprintf(stderr, "%s: %s\n", hostname, gai_strerror(status));
exit(EXIT_FAILURE);
}
int sfd, err;
for (struct addrinfo *addr = addrs; addr != nullptr; addr = addr->ai_next)
{
sfd = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
if (sfd == ERROR_STATUS)
{
err = errno;
continue;
}
if (connect(sfd, addr->ai_addr, addr->ai_addrlen) == 0)
{
break;
}
err = errno;
sfd = ERROR_STATUS;
close(sfd);
}
freeaddrinfo(addrs);
if (sfd == ERROR_STATUS)
{
fprintf(stderr, "%s: %s\n", hostname, strerror(err));
exit(EXIT_FAILURE);
}
return sfd;
}
void DisplayCerts(SSL *ssl)
{
X509 *cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if (cert != nullptr)
{
printf("Server certificates:\n");
char *line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
delete line;
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
delete line;
X509_free(cert);
}
else
{
printf("Info: No client certificates configured.\n");
}
}
int main(int argc, char const *argv[])
{
SSL_CTX *ctx = InitSSL_CTX();
SSL *ssl = SSL_new(ctx);
if (ssl == nullptr)
{
fprintf(stderr, "SSL_new() failed\n");
exit(EXIT_FAILURE);
}
//Host is hardcoded to localhost for testing purposes
const int sfd = OpenConnection("127.0.0.1", argv[1]);
SSL_set_fd(ssl, sfd);
const int status = SSL_connect(ssl);
if (status != 1)
{
SSL_get_error(ssl, status);
ERR_print_errors_fp(stderr); //High probability this doesn't do anything
fprintf(stderr, "SSL_connect failed with SSL_get_error code %d\n", status);
exit(EXIT_FAILURE);
}
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
DisplayCerts(ssl);
const char *chars = "Hello World, 123!";
SSL_write(ssl, chars, strlen(chars));
SSL_free(ssl);
close(sfd);
SSL_CTX_free(ctx);
return 0;
}
@talregev
Copy link

Can you implement the server? that server will support tls and non tls, and the client send the message first.

@jkrause1
Copy link

At which point does this client check for the validity of the certificate that the server send?
It is my understanding, that the client checks the certificate for trustworthiness as part of the Handshake, but where does it actually happen?

@wizard00000
Copy link

ty for inspiration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment