Overview of the SSL handshake
SSL handshake Steps
1. The client sends the server the client's SSL version number, cipher settings, randomly generated data, and other information the server needs to communicate with the client using SSL.
2. The server sends the client the server's SSL version number, cipher settings, randomly generated data, and other information the client needs to communicate with the server over SSL. The server also sends its own digital certificate and, if the client is requesting a server resource that requires client authentication, requests the client's digital certificate.
3. The client uses the information sent by the server to authenticate the server. If the server cannot be authenticated, the user is warned of the problem that an encrypted and authenticated connection cannot be established. If the server can be successfully authenticated, the client proceeds.
Using all data generated in the handshake so far, the client creates the premaster secret for the session, encrypts it with the server's public key (obtained from the server's digital certificate), and sends the encrypted premaster secret to the server.
4. If the server has requested client authentication (an optional step in the handshake), the client also signs another piece of data that is unique to this handshake and known by both the client and server.
5. In this case the client sends both the signed data and the client's own digital certificate to the server along with the encrypted premaster secret.
6. If the server has requested client authentication, the server attempts to authenticate the client. If the client cannot be authenticated, the session is terminated. If the client can be successfully authenticated, the server uses its private key to decrypt the premaster secret, then performs a series of steps which the client also performs, starting from the same premaster secret to generate the master secret.
7. Both the client and the server use the master secret to generate session keys which are symmetric keys used to encrypt and decrypt information exchanged during the SSL session and to verify its integrity.
8. The client informs the server that future messages from the client will be encrypted with the session key. It then sends a separate encrypted message indicating that the client portion of the handshake is finished.
9. The server sends a message to the client informing it that future messages from the server will be encrypted with the session key. It then sends a separate encrypted message indicating that the server portion of the handshake is finished.
10. The SSL handshake is now complete, and the SSL session has begun. The client and the server use the session keys to encrypt and decrypt the data they send to each other and to validate its integrity.
Steps to be followed to execute Client-Server programs :
1. Download openssl latest version from the below link
https://www.openssl.org/source/
2. Extract tar.gz file.
3. In open ssl folder, perform the following steps:
$ ./config
$ make
$ make test
$ sudo make install
This will install openssl latest version into your linux os.
After install openssl , give
Neelkanth_39$ openssl version
OpenSSL 1.1.0g 2 Nov 2017
IN CASE THE FOLLOWING ERROR IS ENCOUNTERED
"error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory"
Solution:
This is caused either by broken link or an unsupported version of the library files in the shared folder.
Copy the library files libcrypto.so.1.1, libcrypto.a and libssl.so from /usr/local/lib to /usr/lib.
4.
Before running the client and server program, we need a Certificate which is used in the programs.
You can generate your own certificate using this command
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem
, where mycert.pem is the name of the Certificate file.
change the file permission of the generated certificate file.
chmod 777 mycert.pem
'or'
1. create 2 directories:
Client_certs and Server_certs.
Neelkanth_39$ ls
client.c Client_certs server.c Server_certs ssl-client ssl-server
2. create client.pem in
Client_certs and server.pem in Server_certs.
Neelkanth_39$ ls Client_certs/
client.pem
Neelkanth_39$ ls Server_certs/
server.pem
5.
Use the below command to read the encrypted content in the certificate
neelkanth_surekha#openssl x509 -text -in mycert.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 13039925153629495725 (0xb4f71ed6b7c461ad)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=IN, ST=tamil-nadu, L=chennai, O=aricent, OU=at&t, CN=neelkanth/emailAddress=www.neelkanth.13@gmail.com
Validity
Not Before: Dec 11 17:55:30 2017 GMT
Not After : Dec 11 17:55:30 2018 GMT
Subject: C=IN, ST=tamil-nadu, L=chennai, O=aricent, OU=at&t, CN=neelkanth/emailAddress=www.neelkanth.13@gmail.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:d5:27:bb:81:00:c7:16:bb:d9:89:15:b0:6e:52:
63:10:9a:4c:71:0e:d8:14:b6:6b:23:dd:1e:f3:a4:
7d:1a:da:22:c2:a0:66:34:df:cd:44:9f:16:ab:d6:
7c:be:6d:23:5e:63:fd:e3:6e:13:a4:31:e3:6f:02:
4b:18:96:71:6a:3e:55:fd:0d:40:95:ee:aa:06:b8:
d2:6a:e2:e4:80:50:43:fd:32:0e:99:e1:fc:9c:05:
24:f7:b3:e9:f2:79:1d:37:78:e7:09:43:4c:f7:9c:
e9:0d:d5:57:e9:65:86:c6:b4:6f:17:a7:11:3f:d4:
0b:e9:dd:b4:a3:9f:51:2f:09
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
2C:B9:EF:08:F6:6F:B0:5E:47:DE:F2:44:1F:0B:88:92:E9:B8:C9:08
X509v3 Authority Key Identifier:
keyid:2C:B9:EF:08:F6:6F:B0:5E:47:DE:F2:44:1F:0B:88:92:E9:B8:C9:08
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
b1:a0:f3:e4:1e:24:2e:84:82:cc:45:a7:a6:0c:23:03:ab:e5:
d1:52:fc:7d:7d:b4:39:dd:75:fc:e3:78:c3:ac:52:6f:b8:43:
56:41:92:67:43:02:a6:a1:07:4c:cb:4c:1c:d9:f6:70:16:60:
d1:45:dc:9b:9f:14:83:8d:f4:a2:da:5f:e1:5a:b2:d3:05:ae:
87:66:74:1b:a3:ef:07:29:c3:b4:6f:fd:5d:60:0d:16:7a:c7:
41:1d:8d:be:4b:6c:63:bd:34:50:4d:fc:a9:c3:d5:8d:db:7b:
5a:46:5f:60:04:80:7e:09:c6:7e:a3:89:32:63:21:aa:60:09:
96:50
-----BEGIN CERTIFICATE-----
MIIC+DCCAmGgAwIBAgIJALT3Hta3xGGtMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD
VQQGEwJJTjETMBEGA1UECAwKdGFtaWwtbmFkdTEQMA4GA1UEBwwHY2hlbm5haTEQ
MA4GA1UECgwHYXJpY2VudDENMAsGA1UECwwEYXQmdDESMBAGA1UEAwwJbmVlbGth
bnRoMSkwJwYJKoZIhvcNAQkBFhp3d3cubmVlbGthbnRoLjEzQGdtYWlsLmNvbTAe
Fw0xNzEyMTExNzU1MzBaFw0xODEyMTExNzU1MzBaMIGUMQswCQYDVQQGEwJJTjET
MBEGA1UECAwKdGFtaWwtbmFkdTEQMA4GA1UEBwwHY2hlbm5haTEQMA4GA1UECgwH
YXJpY2VudDENMAsGA1UECwwEYXQmdDESMBAGA1UEAwwJbmVlbGthbnRoMSkwJwYJ
KoZIhvcNAQkBFhp3d3cubmVlbGthbnRoLjEzQGdtYWlsLmNvbTCBnzANBgkqhkiG
9w0BAQEFAAOBjQAwgYkCgYEA1Se7gQDHFrvZiRWwblJjEJpMcQ7YFLZrI90e86R9
GtoiwqBmNN/NRJ8Wq9Z8vm0jXmP9424TpDHjbwJLGJZxaj5V/Q1Ale6qBrjSauLk
gFBD/TIOmeH8nAUk97Pp8nkdN3jnCUNM95zpDdVX6WWGxrRvF6cRP9QL6d20o59R
LwkCAwEAAaNQME4wHQYDVR0OBBYEFCy57wj2b7BeR97yRB8LiJLpuMkIMB8GA1Ud
IwQYMBaAFCy57wj2b7BeR97yRB8LiJLpuMkIMAwGA1UdEwQFMAMBAf8wDQYJKoZI
hvcNAQELBQADgYEAsaDz5B4kLoSCzEWnpgwjA6vl0VL8fX20Od11/ON4w6xSb7hD
VkGSZ0MCpqEHTMtMHNn2cBZg0UXcm58Ug430otpf4Vqy0wWuh2Z0G6PvBynDtG/9
XWANFnrHQR2NvktsY700UE38qcPVjdt7WkZfYASAfgnGfqOJMmMhqmAJllA=
-----END CERTIFICATE-----
Data:
Version: 3 (0x2)
Serial Number: 13039925153629495725 (0xb4f71ed6b7c461ad)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=IN, ST=tamil-nadu, L=chennai, O=aricent, OU=at&t, CN=neelkanth/emailAddress=www.neelkanth.13@gmail.com
Validity
Not Before: Dec 11 17:55:30 2017 GMT
Not After : Dec 11 17:55:30 2018 GMT
Subject: C=IN, ST=tamil-nadu, L=chennai, O=aricent, OU=at&t, CN=neelkanth/emailAddress=www.neelkanth.13@gmail.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:d5:27:bb:81:00:c7:16:bb:d9:89:15:b0:6e:52:
63:10:9a:4c:71:0e:d8:14:b6:6b:23:dd:1e:f3:a4:
7d:1a:da:22:c2:a0:66:34:df:cd:44:9f:16:ab:d6:
7c:be:6d:23:5e:63:fd:e3:6e:13:a4:31:e3:6f:02:
4b:18:96:71:6a:3e:55:fd:0d:40:95:ee:aa:06:b8:
d2:6a:e2:e4:80:50:43:fd:32:0e:99:e1:fc:9c:05:
24:f7:b3:e9:f2:79:1d:37:78:e7:09:43:4c:f7:9c:
e9:0d:d5:57:e9:65:86:c6:b4:6f:17:a7:11:3f:d4:
0b:e9:dd:b4:a3:9f:51:2f:09
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
2C:B9:EF:08:F6:6F:B0:5E:47:DE:F2:44:1F:0B:88:92:E9:B8:C9:08
X509v3 Authority Key Identifier:
keyid:2C:B9:EF:08:F6:6F:B0:5E:47:DE:F2:44:1F:0B:88:92:E9:B8:C9:08
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
b1:a0:f3:e4:1e:24:2e:84:82:cc:45:a7:a6:0c:23:03:ab:e5:
d1:52:fc:7d:7d:b4:39:dd:75:fc:e3:78:c3:ac:52:6f:b8:43:
56:41:92:67:43:02:a6:a1:07:4c:cb:4c:1c:d9:f6:70:16:60:
d1:45:dc:9b:9f:14:83:8d:f4:a2:da:5f:e1:5a:b2:d3:05:ae:
87:66:74:1b:a3:ef:07:29:c3:b4:6f:fd:5d:60:0d:16:7a:c7:
41:1d:8d:be:4b:6c:63:bd:34:50:4d:fc:a9:c3:d5:8d:db:7b:
5a:46:5f:60:04:80:7e:09:c6:7e:a3:89:32:63:21:aa:60:09:
96:50
-----BEGIN CERTIFICATE-----
MIIC+DCCAmGgAwIBAgIJALT3Hta3xGGtMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD
VQQGEwJJTjETMBEGA1UECAwKdGFtaWwtbmFkdTEQMA4GA1UEBwwHY2hlbm5haTEQ
MA4GA1UECgwHYXJpY2VudDENMAsGA1UECwwEYXQmdDESMBAGA1UEAwwJbmVlbGth
bnRoMSkwJwYJKoZIhvcNAQkBFhp3d3cubmVlbGthbnRoLjEzQGdtYWlsLmNvbTAe
Fw0xNzEyMTExNzU1MzBaFw0xODEyMTExNzU1MzBaMIGUMQswCQYDVQQGEwJJTjET
MBEGA1UECAwKdGFtaWwtbmFkdTEQMA4GA1UEBwwHY2hlbm5haTEQMA4GA1UECgwH
YXJpY2VudDENMAsGA1UECwwEYXQmdDESMBAGA1UEAwwJbmVlbGthbnRoMSkwJwYJ
KoZIhvcNAQkBFhp3d3cubmVlbGthbnRoLjEzQGdtYWlsLmNvbTCBnzANBgkqhkiG
9w0BAQEFAAOBjQAwgYkCgYEA1Se7gQDHFrvZiRWwblJjEJpMcQ7YFLZrI90e86R9
GtoiwqBmNN/NRJ8Wq9Z8vm0jXmP9424TpDHjbwJLGJZxaj5V/Q1Ale6qBrjSauLk
gFBD/TIOmeH8nAUk97Pp8nkdN3jnCUNM95zpDdVX6WWGxrRvF6cRP9QL6d20o59R
LwkCAwEAAaNQME4wHQYDVR0OBBYEFCy57wj2b7BeR97yRB8LiJLpuMkIMB8GA1Ud
IwQYMBaAFCy57wj2b7BeR97yRB8LiJLpuMkIMAwGA1UdEwQFMAMBAf8wDQYJKoZI
hvcNAQELBQADgYEAsaDz5B4kLoSCzEWnpgwjA6vl0VL8fX20Od11/ON4w6xSb7hD
VkGSZ0MCpqEHTMtMHNn2cBZg0UXcm58Ug430otpf4Vqy0wWuh2Z0G6PvBynDtG/9
XWANFnrHQR2NvktsY700UE38qcPVjdt7WkZfYASAfgnGfqOJMmMhqmAJllA=
-----END CERTIFICATE-----
6.
Now compile the client and the server C programs
Compile Server code:
neelkanth_surekha#gcc -Wall -o ssl-server server.c -L/usr/lib -lssl -lcrypto
server.c: In function ‘InitServerCTX’:
server.c:59:12: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
method = TLSv1_2_server_method(); /* create new server-method instance */
^
neelkanth_surekha#
Compile Client Code:
neelkanth_surekha#gcc -Wall -o ssl-client client.c -L/usr/lib -lssl -lcrypto
client.c: In function ‘InitCTX’:
client.c:47:12: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
method = TLSv1_2_client_method(); /* Create new client-method instance */
^
7.
############################################################################
// SSL server C program
############################################################################
// SSL server C program
############################################################################
//SSL-Server.c
Neelkanth_39$ cat server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
#define CLIENT_CERT "Client_certs/client.pem"
#define SERVER_CERT "Server_certs/server.pem"
#define CLIENT_CERT_PATH "Client_certs"
#define SERVER_CERT_PATH "Server_certs"
/****************************************************************************
* Function: OpenListener
*
* Description: Create TCP socket for Server to listen from Client
*****************************************************************************/
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
/* Create Layer 4 TCP socket */
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
/* Bind */
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
printf("Server: bind successful \n");
/* Listen */
if ( listen(sd, 10) != 0 )
{
perror("Can't configure listening port");
abort();
}
printf("Server: Listen successful \n");
return sd;
}
/****************************************************************************
* Function: isRoot
*
* Description: Check whether the server process is started in root.
*****************************************************************************/
int isRoot()
{
if (getuid() != 0) {
return 0;
} else {
return 1;
}
}
/****************************************************************************
* Function: InitServerCTX
*
* Description: Initialize Server SSL connection.
*
* SSL_CTX_new() creates a new SSL_CTX object as framework to establish
* TLS/SSL enabled connections.
*****************************************************************************/
SSL_CTX* InitServerCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
/* load & register all cryptos, etc. */
OpenSSL_add_all_algorithms();
/* load all error messages */
SSL_load_error_strings();
/* create new server-method instance */
method = TLSv1_2_server_method();
/* create new context from method */
ctx = SSL_CTX_new(method);
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
SSL_CTX_set_verify_depth(ctx, 103);
int retval;
/* Set the location where CA certified or self signed Client Certificate
* is stored. Server would use this to validate received Client Certifcate.
*/
retval = SSL_CTX_load_verify_locations(ctx, CLIENT_CERT,
CLIENT_CERT_PATH);
/* for both ssl, retval == 1 is load verified */
if (retval != 1)
{
printf("Err: Could not load verify locations\n");
}
/* If fail to load certificate, set the certificate verify anyway */
/*
* Server mode: the server sends a client certificate request to the client.
* The certificate returned (if any) is checked. If the verification process
* fails, the TLS/SSL handshake is immediately terminated with an alert
* message containing the reason for the verification failure.
*/
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
int depth = SSL_CTX_get_verify_depth(ctx);
printf("\nServer: depth: %d \n", depth);
printf("Server SSL initialized successfully\n");
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
printf("Server: Local certificate from CertFile set successfully \n");
printf("Server: Private key from KeyFile (CertFile) set successfully \n");
printf("Server: Private Key matches the public certificate \n");
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if ( cert != NULL )
{
printf("\nShow Client certificate:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No Client certificates Validated.\n");
}
/****************************************************************************
* Function: Serv_ssl_client_auth_and_serve_conn
*
* Description: Once, TCP connection is established with the Client, the accept
* return client socket file descriptor to which ssl Structure is set.
* Now, perform SSL_accept on this ssl structure. (LAYER 5 ssl)
*
*****************************************************************************/
/* Serve the connection -- threadable */
void Serv_ssl_client_auth_and_serve_conn(SSL* ssl)
{ char buf[1024];
char reply[1024];
int client_fd, bytes;
const char* HTMLecho = "<html><body><pre>%s</pre></body></html>\n";
/* SSL Accept <LAYER 5> Authentication and accept */
/* do SSL-protocol accept */
/* SSL_accept() waits for a TLS/SSL client to initiate the TLS/SSL handshake.
* The communication channel must already have been set and assigned to the
* ssl by setting an underlying BIO.
*/
/*
* A BIO in OpenSSL is similar to a File handle. You use a pair of them
* to communicate with each other securely like you would with two sockets.
*/
printf("******************************************************\n");
printf("STAGE 4: OSI LAYER 5 (SSL/TLS): ACCEPT SSL CONNECT REQUEST FROM CLIENT AND "
" VALIDATE CLIENT CERTIFICATE \n");
if ( SSL_accept(ssl) == FAIL )
{
ERR_print_errors_fp(stderr);
}
else
{
/*
* SSL_get_verify_result - get result of peer certificate
* verification.
*/
int result = SSL_get_verify_result(ssl);
if (X509_V_OK != result) {
printf("Client certificate validation Failed \n");
abort();
} else {
printf("Client Certificate validation Successful \n");
}
printf("Connected with %s encryption\n",
SSL_get_cipher(ssl));
/* Show any Certificates received from Client process */
ShowCerts(ssl); /* get any certificates */
printf("******************************************************\n");
printf("STAGE 5: OSI LAYER 5 (SSL/TLS) DE-CRYPT CLIENT'S MESSAGE\n");
/* Decrypt & read message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Decrypt & read message from Client \n");
printf("Message Received from Client : \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
printf("******************************************************\n");
printf("STAGE 6: OSI LAYER 5 (SSL/TLS) ENCRYPT MESSAGE TO CLIENT\n");
printf("Encrypt & send message to Client \n");
printf("Message Sent to the Client: \"%s\"\n", reply);
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else {
ERR_print_errors_fp(stderr);
}
printf("******************************************************\n");
}
/* get socket file Descriptor of client which is connected to the server */
client_fd = SSL_get_fd(ssl);
/* release connection state */
SSL_free(ssl); /* release SSL state */
/* CLOSE LAYER 4 TCP SOCKET FD */
close(client_fd); /* close connection */
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server_fd;
char *portnum;
/* Server program should be run as root */
/* Usage: sudo ./ssl-server 5000 */
if(!isRoot())
{
printf("This program must be run as root/sudo user!!");
exit(0);
}
if ( count != 2 )
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
/* Initialize SSL Library */
printf("**************************************************************\n");
SSL_library_init();
portnum = strings[1];
printf("STAGE 1: SERVER SSL INITIALIZATION ");
/* Initialize Server SSL connection. */
ctx = InitServerCTX();
/* Load Server Certificates (private key and certificate
* containing Public key) */
LoadCertificates(ctx, SERVER_CERT, SERVER_CERT);
printf("**************************************************************\n");
/**********************************************************************
* LAYER 4 TCP SOCKET CONNECTION TO SERVER *
**********************************************************************/
/* TCP bind, Listen <LAYER 4> */
printf("**************************************************************\n");
printf("STAGE 2: LAYER 4 TCP SOCKET LISTEN TO CLIENT\n");
server_fd = OpenListener(atoi(portnum));
printf("**************************************************************\n");
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
/* TCP Accept */
/* accept connection as usual */
printf("**************************************************************\n");
printf("STAGE 3: LAYER 4 TCP ACCEPT CONNECTION FROM CLIENT\n");
int client_fd = accept(server_fd, (struct sockaddr*)&addr, &len);
printf("Server: Connected to Client: %s:%d now\n",
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
printf("**************************************************************\n");
/* get new SSL state with context */
ssl = SSL_new(ctx);
/*
* SSL_set_fd() sets the file descriptor fd as the input/output facility
* for the TLS/SSL (encrypted) side of ssl. fd will typically be the socket
* file descriptor of a network connection.
* When performing the operation, a socket BIO is automatically created to
* interface between the ssl and fd. The BIO and hence the SSL engine inherit
* the behaviour of fd. If fd is non-blocking, the ssl will also have non-blocking
* behaviour.
*/
/* set Client connection socket to SSL state */
SSL_set_fd(ssl, client_fd);
/**********************************************************************
* LAYER 5 SECURE SOCKET CONNECTION TO CLIENT (SSL/TLS) *
**********************************************************************/
/* Authenticate Client Certificate (Public key) and service connection
* to client. Once the Client Certificate is Authenticated, Perform SSL_read
* and SSL_write on Client ssl.
*/
Serv_ssl_client_auth_and_serve_conn(ssl);
}
/* CLOSE LAYER 4 TCP SOCKET FD */
close(server_fd); /* close server socket */
/* CLOSE LAYER 5 SSL CONTEXT object */
SSL_CTX_free(ctx); /* release context */
}
8.
//############################################################################
// SSL Client C program
//############################################################################
Neelkanth_39$ cat client.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL -1
#define CLIENT_CERT "Client_certs/client.pem"
#define SERVER_CERT "Server_certs/server.pem"
#define CLIENT_CERT_PATH "Client_certs"
#define SERVER_CERT_PATH "Server_certs"
/****************************************************************************
* Function: OpenConnection
*
* Description: Create TCP socket for Client and connect to Server
*****************************************************************************/
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
/* Get Hostname of Server to which Client would connect to */
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
/* Create Layer 4 TCP socket */
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
/* Layer 4 TCP connect successful */
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
printf("hostname error %s\n", hostname);
abort();
}
printf("Client: Connect to server Hostname: %s successful\n", hostname);
return sd;
}
/****************************************************************************
* Function: Init_Client_CTX
*
* Description: Initialize Client SSL connection.
*
* SSL_CTX_new() creates a new SSL_CTX object as framework to establish
* TLS/SSL enabled connections.
*****************************************************************************/
SSL_CTX* Init_Client_CTX(void)
{
SSL_METHOD *method;
SSL_CTX *ctx;
/* Load cryptos, et.al. */
OpenSSL_add_all_algorithms();
/* Bring in and register error messages */
SSL_load_error_strings();
/* Create new client-method instance */
method = TLSv1_2_client_method();
/* Create new context */
ctx = SSL_CTX_new(method);
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
SSL_CTX_set_verify_depth(ctx, 103);
int retval;
/* The below is the place where CA authorized/Self signed Server's Certifates
* are stored. Client would validate the certificate it receives from server
* against the certificates stored in this location. Client would disconnect ssl
* connection, if the certificate validation fails.
*/
retval = SSL_CTX_load_verify_locations(ctx, SERVER_CERT,
SERVER_CERT_PATH);
/* for both ssl, retval == 1 is load verified */
if (retval != 1)
{
printf("Err: Could not load verify locations\n");
}
/* If fail to load certificate, set the certificate verify anyway */
/*
* Client mode: the server certificate is verified.
* If the verification process fails, the TLS/SSL handshake is
* immediately terminated with an alert message containing the reason
* for the verification failure. If no server certificate is sent,
* because an anonymous cipher is used, SSL_VERIFY_PEER is ignored.
* NOTE: the failure condition can be tested by commenting out
* SSL_CTX_load_verify_locations
*/
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
int depth = SSL_CTX_get_verify_depth(ctx);
printf("\nClient: depth: %d \n", depth);
printf("Client SSL initialized successfully\n");
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
printf("Client: Local certificate from CertFile set successfully \n");
printf("Client: Private key from KeyFile (CertFile) set successfully \n");
printf("Client: Private Key matches the public certificate \n");
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("Info: No Server certificates configured.\n");
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int client_fd;
SSL *ssl;
char buf[1024];
int bytes;
char *hostname, *portnum;
/* Usage: ./ssl-client 127.0.0.1 5000 */
if ( count != 3 )
{
printf("usage: %s <hostname> <portnum>\n", strings[0]);
exit(0);
}
/* Initialize SSL Library */
/* SSL_library_init() registers the available SSL/TLS ciphers and digests. */
printf("**************************************************************\n");
SSL_library_init();
/* Server hostname: IP address */
hostname = strings[1];
/* Server Port no.*/
portnum = strings[2];
/* Initialize Client SSL connection. */
printf("STAGE 1: CLIENT SSL INITIALIZATION ");
ctx = Init_Client_CTX();
/* Load Server Certificates (private key and certificate
* containing Public key) */
LoadCertificates(ctx, CLIENT_CERT, CLIENT_CERT);
printf("**************************************************************\n");
/**********************************************************************
* LAYER 4 TCP SOCKET CONNECTION TO SERVER *
**********************************************************************/
/* Connect to server over SSL < LAYER 4 > */
printf("**************************************************************\n");
printf("STAGE 2 & 3: LAYER 4 TCP SOCKET CONNECTION TO SERVER\n");
client_fd = OpenConnection(hostname, atoi(portnum));
printf("**************************************************************\n");
/* create new SSL connection state */
/*
* SSL_new() creates a new SSL structure which is needed to hold the data
* for a TLS/SSL connection. The new structure inherits the settings of
* the underlying context ctx: connection method (SSLv2/v3/TLSv1), options,
* verification settings, timeout settings.
*/
ssl = SSL_new(ctx);
/*
* A BIO in OpenSSL is similar to a File handle. You use a pair of them
* to communicate with each other securely like you would with two sockets.
*/
/*
* SSL_set_fd() sets the file descriptor fd as the input/output facility
* for the TLS/SSL (encrypted) side of ssl. fd will typically be the socket
* file descriptor of a network connection.
* When performing the operation, a socket BIO is automatically created to
* interface between the ssl and fd. The BIO and hence the SSL engine inherit
* the behaviour of fd. If fd is non-blocking, the ssl will also have non-blocking
* behaviour.
*/
/* attach the socket descriptor */
SSL_set_fd(ssl, client_fd);
/**********************************************************************
* LAYER 5 SECURE SOCKET CONNECTION TO SERVER (SSL/TLS) *
**********************************************************************/
/*
* SSL_connect() initiates the TLS/SSL handshake with a server. The
* communication channel must already have been set and assigned to the ssl
* by setting an underlying BIO.
*/
/* SSL connect <LAYER 5> Authentication and connect */
printf("**************************************************************\n");
printf("STAGE 4: OSI LAYER 5 (SSL/TLS): SSL CONNECT TO SERVER AND "
" VALIDATE SERVER CERTIFICATE\n");
if ( SSL_connect(ssl) == FAIL )
{
ERR_print_errors_fp(stderr);
}
else
{
/*
* SSL_get_verify_result - get result of peer certificate
* verification.
*/
int result = SSL_get_verify_result(ssl);
if (X509_V_OK != result) {
printf("Server certificate validation Failed \n");
} else {
printf("Server Certificate validation Successful \n");
}
char *msg = "I am the client";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
/* Show any Certificate received from Server process */
ShowCerts(ssl);
printf("**************************************************************\n");
/* encrypt & send message */
printf("STAGE 5: OSI LAYER 5 (SSL/TLS) SEND ENCRYPTED MESSAGE TO SERVER\n");
printf("encrypt & send message to Server \n");
printf("Message Sent to the Server : \"%s\"\n", msg);
SSL_write(ssl, msg, strlen(msg));
printf("**************************************************************\n");
/* get reply & decrypt */
bytes = SSL_read(ssl, buf, sizeof(buf));
buf[bytes] = 0;
printf("STAGE 6: OSI LAYER 5 (SSL/TLS) DE-CRYPT SERVER'S MESSAGE\n");
printf("Decrypt & read message from Server \n");
printf("Message Received: \"%s\"\n", buf);
printf("******************************************************\n");
/* release connection state */
SSL_free(ssl);
}
/* CLOSE LAYER 4 TCP SOCKET FD */
close(client_fd); /* close socket */
/* CLOSE LAYER 5 SSL CONTEXT object */
SSL_CTX_free(ctx); /* release context */
return 0;
}
9.
Run Server and Client executables now:
neelkanth_surekha#sudo ./ssl-server 5000
|
neelkanth_surekha#./ssl-client 127.0.0.1 5000
|
Neelkanth_39$ sudo ./ssl-server 5005
sudo: unable to resolve host labuser-VirtualBox
[sudo] password for labuser:
**************************************************************
STAGE 1: SERVER SSL INITIALIZATION
Server: depth: 103
Server SSL initialized successfully
Server: Local certificate from CertFile set successfully
Server: Private key from KeyFile (CertFile) set successfully
Server: Private Key matches the public certificate
**************************************************************
**************************************************************
STAGE 2: LAYER 4 TCP SOCKET LISTEN TO CLIENT
Server: bind successful
Server: Listen successful
**************************************************************
**************************************************************
STAGE 3: LAYER 4 TCP ACCEPT CONNECTION FROM CLIENT
Server: Connected to Client: 127.0.0.1:38946 now
**************************************************************
******************************************************
STAGE 4: OSI LAYER 5 (SSL/TLS): ACCEPT SSL CONNECT REQUEST FROM CLIENT AND VALIDATE CLIENT CERTIFICATE
Client Certificate validation Successful
Connected with ECDHE-RSA-AES256-GCM-SHA384 encryption
Show Client certificate:
Subject: /C=IN/ST=client/L=client/O=client/OU=client/CN=client/emailAddress=www.client.com
Issuer: /C=IN/ST=client/L=client/O=client/OU=client/CN=client/emailAddress=www.client.com
******************************************************
STAGE 5: OSI LAYER 5 (SSL/TLS) DE-CRYPT CLIENT'S MESSAGE
Decrypt & read message from Client
Message Received from Client : "I am the client"
******************************************************
STAGE 6: OSI LAYER 5 (SSL/TLS) ENCRYPT MESSAGE TO CLIENT
Encrypt & send message to Client
Message Sent to the Client: "<html><body><pre>I am the client</pre></body></html>
"
******************************************************
**************************************************************
STAGE 3: LAYER 4 TCP ACCEPT CONNECTION FROM CLIENT
|
**************************************************************
STAGE 1: CLIENT SSL INITIALIZATION
Client: depth: 103
Client SSL initialized successfully
Client: Local certificate from CertFile set successfully
Client: Private key from KeyFile (CertFile) set successfully
Client: Private Key matches the public certificate
**************************************************************
**************************************************************
STAGE 2 & 3: LAYER 4 TCP SOCKET CONNECTION TO SERVER
Client: Connect to server Hostname: 127.0.0.1 successful
**************************************************************
**************************************************************
STAGE 4: OSI LAYER 5 (SSL/TLS): SSL CONNECT TO SERVER AND VALIDATE SERVER CERTIFICATE
Server Certificate validation Successful
Connected with ECDHE-RSA-AES256-GCM-SHA384 encryption
Server certificates:
Subject: /C=IN/ST=server/L=server/O=server/OU=server/CN=server/emailAddress=www.server.com
Issuer: /C=IN/ST=server/L=server/O=server/OU=server/CN=server/emailAddress=www.server.com
**************************************************************
STAGE 5: OSI LAYER 5 (SSL/TLS) SEND ENCRYPTED MESSAGE TO SERVER
encrypt & send message to Server
Message Sent to the Server : "I am the client"
**************************************************************
STAGE 6: OSI LAYER 5 (SSL/TLS) DE-CRYPT SERVER'S MESSAGE
Decrypt & read message from Server
Message Received: "<html><body><pre>I am the client</pre></body></html>
"
******************************************************
|