One way to make a TLS server connection with OpenSSL is to use its SSL layer on top of a TCP connection made using the Berkeley sockets API. Creating the TCP server connection is done in the usual way. For the TLS connection, the first requirement is to create an SSL context that tells which TLS version to use, and manages certificates. A TLS server requires a server certificate and a key, both of which are loaded into the SSL context. When a new TCP connection is received, an SSL session can be created using the SSL context. The SSL session is associated with the socket for the new connection. After this association is made, most of the interaction with the socket should go through the SSL session.
Once the TCP socket is connected, the next step is the TLS handshake. OpenSSL handles all of the details of the handshake. The server application only needs to poll the handshake status until either an error or success is returned. If the handshake succeeds, the SSL session can then be used to do encrypted reads and writes on the socket. OpenSSL handles the details of encryption and decryption, so the server application exchanges clear-text data with the SSL session read and write functions. When the server is finished with the connection, the TCP socket can be closed and the SSL session freed.
The following code implements a minimal TLS server:
server.c
#include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <openssl/ssl.h>
int main (int argc, char *argv[]) { int s, cs, len, result; struct sockaddr_in srv_addr, cli_addr; char buf[64]; SSL_CTX *ctx; SSL *ssl;
/* Create a TLS server context with certificates */ ctx = SSL_CTX_new(TLS_server_method()); SSL_CTX_use_certificate_file(ctx, “server.crt”, SSL_FILETYPE_PEM); SSL_CTX_use_PrivateKey_file(ctx, “server.key”, SSL_FILETYPE_PEM);
/* Set the address and port to listen on */ srv_addr.sin_family = AF_INET; srv_addr.sin_port = 9001; inet_pton(AF_INET, “127.0.0.1”, &srv_addr.sin_addr);
/* Create a socket and listen */ s = socket(AF_INET, SOCK_STREAM, 0); bind(s, (struct sockaddr *)&srv_addr, sizeof(srv_addr)); listen(s, 1);
/* Wait for a new client connection */ printf(“Waiting for a client…\n”); len = sizeof(cli_addr); cs = accept(s, (struct sockaddr*)&cli_addr, &len);
/* Create an SSL session for the new socket */ ssl = SSL_new(ctx); SSL_set_fd(ssl, cs);
/* Run the OpenSSL handshake */ result = SSL_accept(ssl); if (result == 1) {
/* Exchange some data if the connection succeeded */ sprintf(buf, “Hello from the server”); SSL_write(ssl, buf, strlen(buf) + 1); len = SSL_read(ssl, buf, sizeof(buf)); printf(“Received message from client: ‘%s’\n”, buf); }
/* Done */ close(cs); close(s); SSL_free(ssl); SSL_CTX_free(ctx); return 0; } |