This is a sample how client and server to communicate over SSL.
-- 1. server.c --
/*
* ++
* FACILITY:
*
* Simplest SSL Server
*
* ABSTRACT:
*
* This is an example of a SSL server with minimum functionality.
* The socket APIs are used to handle TCP/IP operations. This SSL
* server loads its own certificate and key, but it does not verify
* the certificate of the SSL client.
*
* ENVIRONMENT:
*
* OpenVMS Alpha V7.2-2 or higher
* TCP/IP Services V5.0A or higher
*
* AUTHOR:
*
* Taka Shinagawa, OpenVMS Security Group
*
* CREATION DATE:
*
* 1-Jan-2002
*
* --
*/
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define RSA_SERVER_CERT "server.pem"
#define RSA_SERVER_KEY "server.key"
#define RSA_CLIENT_CERTS "client.pem"
void main()
{
int err;
int verify_client = 1; /* Whether to verify a client certificate or not. */
int listen_sock;
int client_sock;
struct sockaddr_in sa_server;
struct sockaddr_in sa_client;
size_t client_len;
char *str;
char buf[4096];
SSL_CTX *ctx;
SSL *ssl;
SSL_METHOD *meth;
X509 *client_cert = NULL;
short int s_port = 5555;
/*-----------------------------------------------------------------------------------------*/
/* Load encryption & hashing algorithms for the SSL program */
SSL_library_init();
/* Load the error strings for SSL & CRYPTO APIs */
SSL_load_error_strings();
/* Create a SSL_METHOD structure (choose a SSL/TLS protocol version) */
meth = SSLv3_method();
/* Create a SSL_CTX structure */
ctx = SSL_CTX_new(meth);
if (ctx == NULL)
{
fprintf(stderr, "Failed when SSL_CTX_new(). Exit./n");
exit(1);
}
/* Load the server certificate into the SSL_CTX structure */
if (SSL_CTX_use_certificate_file(ctx, RSA_SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(1);
}
/* Load the private-key corresponding to the server certificate */
if (SSL_CTX_use_PrivateKey_file(ctx, RSA_SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(1);
}
/* Check if the server certificate and private-key matches */
if (!SSL_CTX_check_private_key(ctx)) {
fprintf(stderr,"Private key does not match the certificate public key/n");
exit(1);
}
if(verify_client)
{
/* Load the RSA CA certificate into the SSL_CTX structure */
if (!SSL_CTX_load_verify_locations(ctx, RSA_CLIENT_CERTS, NULL))
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Set to require peer (client) certificate verification */
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
/* Set the verification depth to 1 */
SSL_CTX_set_verify_depth(ctx,1);
}
/* ----------------------------------------------- */
/* Set up a TCP socket */
listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_sock == -1)
{
perror("Cannot create a listen socket");
exit(1);
}
memset (&sa_server, '/0', sizeof(sa_server));
sa_server.sin_family = AF_INET;
sa_server.sin_addr.s_addr = INADDR_ANY;
sa_server.sin_port = htons(s_port);
err = bind(listen_sock, (struct sockaddr*)&sa_server,sizeof(sa_server));
if (err == -1)
{
perror("Cannot bind server socket");
exit(1);
}
/* Wait for an incoming TCP connection. */
err = listen(listen_sock, 5);
if (err == -1)
{
perror("Cannot listen server socket");
exit(1);
}
client_len = sizeof(sa_client);
/* Socket for a TCP/IP connection is created */
client_sock = accept(listen_sock, (struct sockaddr*)&sa_client, &client_len);
if (client_sock == -1)
{
perror("Cannot accept a client connection");
exit(1);
}
close (listen_sock); // we just accept one client connection
printf ("Connection from %lx, port %x/n", sa_client.sin_addr.s_addr, sa_client.sin_port);
/* ----------------------------------------------- */
/* TCP connection is ready. */
/* A SSL structure is created */
ssl = SSL_new(ctx);
if (ssl == NULL)
{
fprintf(stderr, "Failed when call SSL_new()./n");
exit(1);
}
/* Assign the socket into the SSL structure (SSL and socket without BIO) */
SSL_set_fd(ssl, client_sock);
/* Perform SSL Handshake on the SSL server */
err = SSL_accept(ssl);
if (err == -1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Informational output (optional) */
printf("SSL connection using %s/n", SSL_get_cipher (ssl));
if (verify_client)
{
/* Get the client's certificate (optional) */
client_cert = SSL_get_peer_certificate(ssl);
if (client_cert != NULL)
{
printf ("Client certificate:/n");
str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
if (str == NULL)
{
fprintf(stderr, "Cannot get client certificate's subject/n");
exit(1);
}
printf ("/tsubject: %s/n", str);
free(str);
str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
if (str == NULL)
{
fprintf(stderr, "Cannot get client certificate's ussuer/n");
exit(1);
}
printf ("/tissuer: %s/n", str);
free (str);
X509_free(client_cert);
}
else
printf("The SSL client does not have certificate./n");
}
/*--------------- DATA EXCHANGE - Receive message and send reply. ---------------*/
/* Receive data from the SSL client */
err = SSL_read(ssl, buf, sizeof(buf) - 1);
if (err == -1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
buf[err] = '/0';
printf ("Received %d chars: '%s'/n", err, buf);
/* Send data to the SSL client */
strncpy(buf+err,buf,err); // double the data, and send it back to client.
err = SSL_write(ssl, buf, strlen(buf));
if (err == -1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/*--------------- SSL closure ---------------*/
/* Shutdown this side (server) of the connection. */
err = SSL_shutdown(ssl);
if (err == -1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Terminate communication on a socket */
err = close(client_sock);
if (err == -1)
{
perror("Cannot close connection socket");
exit(1);
}
/* Free the SSL structure */
SSL_free(ssl);
/* Free the SSL_CTX structure */
SSL_CTX_free(ctx);
}
-- 2. client.c --
/*
* ++
* FACILITY:
*
* Simplest SSL Server
*
* ABSTRACT:
*
* This is an example of a SSL server with minimum functionality.
* The socket APIs are used to handle TCP/IP operations. This SSL
* server loads its own certificate and key, but it does not verify
* the certificate of the SSL client.
*
* ENVIRONMENT:
*
* OpenVMS Alpha V7.2-2 or higher
* TCP/IP Services V5.0A or higher
*
* AUTHOR:
*
* Taka Shinagawa, OpenVMS Security Group
*
* CREATION DATE:
*
* 1-Jan-2002
*
* --
*/
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define RSA_CLIENT_CERT "client.pem"
#define RSA_CLIENT_KEY "client.key"
#define RSA_SERVER_CERTS "server.pem"
void main()
{
int err;
int verify_client = 1; /* Whether to verify a client certificate or not. */
int sock;
struct sockaddr_in server_addr;
char *str;
char buf [4096];
char hello[80];
SSL_CTX *ctx;
SSL *ssl;
SSL_METHOD *meth;
X509 *server_cert;
short int s_port = 5555;
const char *s_ipaddr = "127.0.0.1";
/*----------------------------------------------------------*/
printf ("Message to be sent to the SSL server: ");
//fgets (hello, 80, stdin);
scanf("%s",hello);
/* Load encryption & hashing algorithms for the SSL program */
SSL_library_init();
/* Load the error strings for SSL & CRYPTO APIs */
SSL_load_error_strings();
/* Create an SSL_METHOD structure (choose an SSL/TLS protocol version) */
meth = SSLv3_method();
/* Create an SSL_CTX structure */
ctx = SSL_CTX_new(meth);
if (ctx == NULL)
{
fprintf(stderr, "Failed when SSL_CTX_new(). Exit./n");
exit(1);
}
/*-------------------------------------------------------------------------*/
if(verify_client)
{
/* Load the client certificate into the SSL_CTX structure */
if (SSL_CTX_use_certificate_file(ctx, RSA_CLIENT_CERT, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(1);
}
/* Load the private-key corresponding to the client certificate */
if (SSL_CTX_use_PrivateKey_file(ctx, RSA_CLIENT_KEY, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(1);
}
/* Check if the client certificate and private-key matches */
if (!SSL_CTX_check_private_key(ctx)) {
fprintf(stderr,"Private key does not match the certificate public key/n");
exit(1);
}
}
/* Load the RSA CA certificate into the SSL_CTX structure */
/* This will allow this client to verify the server's */
/* certificate. */
if (!SSL_CTX_load_verify_locations(ctx, RSA_SERVER_CERTS, NULL)) {
ERR_print_errors_fp(stderr);
exit(1);
}
/* Set flag in context to require peer (server) certificate verification */
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_set_verify_depth(ctx,1);
/* ----------------------------------------------------------------- */
/* Set up a TCP socket */
sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1)
{
perror("Cannot create a client socket");
exit(1);
}
memset (&server_addr, '/0', sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(s_port); /* Server Port number */
server_addr.sin_addr.s_addr = inet_addr(s_ipaddr); /* Server IP */
/* Establish a TCP/IP connection to the SSL client */
err = connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr));
if (err == -1)
{
perror("Cannot connect to server");
exit(1);
}
/* ----------------------------------------------- */
/* An SSL structure is created */
ssl = SSL_new (ctx);
if (ssl == NULL)
{
fprintf(stderr, "Failed when call SSL_new()./n");
exit(1);
}
/* Assign the socket into the SSL structure (SSL and socket without BIO) */
SSL_set_fd(ssl, sock);
/* Perform SSL Handshake on the SSL client */
err = SSL_connect(ssl);
if (err ==-1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Informational output (optional) */
printf ("SSL connection using %s/n", SSL_get_cipher (ssl));
/* Get the server's certificate (optional) */
server_cert = SSL_get_peer_certificate (ssl);
if (server_cert != NULL)
{
printf ("Server certificate:/n");
str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
if (str == NULL)
{
fprintf(stderr, "Cannot get server certificate's subject/n");
exit(1);
}
printf ("/tsubject: %s/n", str);
free (str);
str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0);
if (str == NULL)
{
fprintf(stderr, "Cannot get server certificate's issuer/n");
exit(1);
}
printf ("/tissuer: %s/n", str);
free(str);
X509_free (server_cert);
}
else
printf("The SSL server does not have certificate./n");
/*--------------- DATA EXCHANGE - send message and receive reply. ---------------*/
/* Send data to the SSL server */
err = SSL_write(ssl, hello, strlen(hello));
if (err == -1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Receive data from the SSL server */
err = SSL_read(ssl, buf, sizeof(buf)-1);
if (err == -1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
buf[err] = '/0';
printf ("Received %d chars:'%s'/n", err, buf);
/*--------------- SSL closure ---------------*/
/* Shutdown the client side of the SSL connection */
err = SSL_shutdown(ssl);
if (err ==-1)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Terminate communication on a socket */
err = close(sock);
if (err == -1)
{
perror("Cannot close socket");
exit(1);
}
/* Free the SSL structure */
SSL_free(ssl);
/* Free the SSL_CTX structure */
SSL_CTX_free(ctx);
}
-- 3. compile server&client --
#: cat Makefile
CFLAGS += -I/opt/exp/lib/openssl/include
LDFLAGS += -lsocket -lnsl -lrt -L/opt/exp/lib/openssl/lib -lssl -lcrypto
all : client server
client : client.c
cc $(CFLAGS) $(LDFLAGS) -o $@ $^
server : server.c
cc $(CFLAGS) $(LDFLAGS) -o $@ $^
clean:
rm -rf client server
-- 4. generate server & client's private key and certificate --
-- for server --
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.pem -days 1095
-- for client --
openssl genrsa -out client.key 2048
openssl req -new -x509 -key client.key -out client.pem -days 1095
-- 5. execute the server & client
#: ./server
Connection from 7f000001, port f5ed
SSL connection using AES256-SHA
Client certificate:
subject: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aclient
issuer: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aclient
Received 3 chars: '123'
#: ./client
Message to be sent to the SSL server: 123
SSL connection using AES256-SHA
Server certificate:
subject: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aserver
issuer: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aserver
Received 6 chars:'123123'