Skip to content

Instantly share code, notes, and snippets.

@deep110
Created January 7, 2021 20:02
Show Gist options
  • Save deep110/a7e5fbc31dea6989907d3dc595efdc4e to your computer and use it in GitHub Desktop.
Save deep110/a7e5fbc31dea6989907d3dc595efdc4e to your computer and use it in GitHub Desktop.
Implementing a TCP server with TLS support using APR and OpenSSL.
#include "apr.h"
#include "apr_network_io.h"
#include "apr_portable.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include <stdlib.h>
int load_ssl_certificate(SSL_CTX* ctx, char* cert_file, char* key_file) {
/* set the local certificate */
if (SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) <= 0) {
return 0;
}
/* set the private key */
if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0 ) {
return 0;
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx)) {
return 0;
}
return 1;
}
int apr_tls_server_destroy(SSL_CTX *ssl_ctx) {
if (ssl_ctx != NULL) {
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
}
return 1;
}
SSL_CTX* apr_tls_server_init(char* cert_file_path, char* key_file_path) {
SSL_CTX *ssl_ctx;
SSL_library_init();
SSL_load_error_strings(); /* load all error messages */
ssl_ctx = SSL_CTX_new(TLSv1_2_server_method()); /* create new context from method */
if (ssl_ctx == NULL) {
return NULL;
}
if (load_ssl_certificate(ssl_ctx, cert_file_path, key_file_path) == 0) {
apr_tls_server_destroy(ssl_ctx);
return NULL;
}
return ssl_ctx;
}
apr_status_t apr_tls_socket_accept(apr_socket_t **new_sock, apr_socket_t *sock,
SSL_CTX *ssl_ctx, SSL **ssl_sock, apr_pool_t *connection_pool
) {
apr_status_t status = apr_socket_accept(new_sock, sock, connection_pool);
if (status) {
return status;
}
if (ssl_ctx != NULL) {
apr_os_sock_t raw_sock;
status = apr_os_sock_get(&raw_sock, *new_sock);
if (status)
return status;
// create new ssl state from ssl context
*ssl_sock = SSL_new(ssl_ctx);
SSL_set_fd(*ssl_sock, raw_sock);
// do ssl handshake
if (SSL_accept(*ssl_sock) != 1) {
printf("SSL Handshake failed");
return 1;
}
}
return status;
}
apr_status_t apr_tls_socket_recv(apr_socket_t *sock, SSL *ssl_sock, char *buf, apr_size_t *len) {
if (ssl_sock == NULL) {
return apr_socket_recv(sock, buf, len);
} else {
int bytes_read = SSL_read(ssl_sock, buf, *len);
*len = (apr_size_t)bytes_read;
if (SSL_get_error(ssl_sock, bytes_read) > 0) {
return 1;
}
return APR_SUCCESS;
}
}
apr_status_t apr_tls_socket_send(apr_socket_t *sock, SSL *ssl_sock, const char *buf, apr_size_t *len) {
if (ssl_sock == NULL) {
return apr_socket_send(sock,buf,len);
} else {
int bytes_wrote = SSL_write(ssl_sock, buf, *len);
*len = (apr_size_t)bytes_wrote;
if (SSL_get_error(ssl_sock, bytes_wrote) > 0) {
return 1;
}
return APR_SUCCESS;
}
}
apr_status_t apr_tls_socket_close(apr_socket_t *thesocket, SSL *ssl_sock) {
if (ssl_sock != NULL) {
SSL_free(ssl_sock);
}
return apr_socket_close(thesocket);
}
apr_status_t create_listening_socket(apr_pool_t *pool, apr_socket_t **lskt, int port) {
apr_sockaddr_t *saddr;
// create a tcp socket
apr_status_t rv = apr_socket_create(lskt, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool);
if (rv)
return rv;
rv = apr_sockaddr_info_get(&saddr, "127.0.0.1", APR_UNSPEC, port, 0, pool);
if (rv)
return rv;
// bind the localhost:<port> to the created listening socket
rv = apr_socket_bind(*lskt, saddr);
if (rv)
return rv;
// now listen for incoming connections on this socket
rv = apr_socket_listen(*lskt, 5);
if (rv)
return rv;
return rv;
}
apr_status_t start_server(apr_pool_t *pool, SSL_CTX *ssl_ctx, int port) {
apr_status_t rv = APR_SUCCESS;
apr_pool_t *subpool;
apr_socket_t *lskt;
// creation of listening socket will remain same
rv = create_listening_socket(pool, &lskt, port);
if (rv) {
return rv;
}
printf("running the TLS server on 127.0.0.1:%d\n", port);
apr_pool_create(&subpool, pool);
for (;;) {
apr_socket_t *cskt;
SSL *ssl_socket;
apr_pool_clear(subpool);
// connect to an incoming socket connection
rv = apr_tls_socket_accept(&cskt, lskt, ssl_ctx, &ssl_socket, subpool);
if (rv)
return rv;
while(1) {
apr_size_t len = 1024;
char buf[1024] = {0};
rv = apr_tls_socket_recv(cskt, ssl_socket, &buf, &len); // read data
if (rv) {
break;
}
rv = apr_tls_socket_send(cskt, ssl_socket, &buf, &len); // write same data back
break;
}
apr_tls_socket_close(cskt, ssl_socket);
}
return rv;
}
int main() {
apr_pool_t *pool;
apr_initialize();
atexit(apr_terminate);
// create apr pool
apr_pool_create(&pool, NULL);
// init ssl context
SSL_CTX *ssl_ctx = apr_tls_server_init("/home/cert.pem", "/home/key.pem");
apr_status_t rv = start_server(pool, ssl_ctx, 8000);
if (rv) {
char buffer[256] = { 0 };
printf("error: %s\n", apr_strerror(rv, buffer, sizeof(buffer)));
}
// destroy ssl context
apr_tls_server_destroy(ssl_ctx);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment