Example: Establishing a secure client with Global Security Kit APIs
This example demonstrates how to establish a client using the Global Security Kit (GSKit) APIs.
The following graphic shows the API calls on a secure client using the GSKit APIs.
Socket flow of events: GSKit client
This flow describes the socket calls in the following sample application. Use this client example with the GSKit server example and the Example: GSKit secure server with asynchronous handshake.
- The gsk_environment_open() API obtains a handle to a secure environment.
- One or more calls to gsk_attribute_set_xxxxx() to set attributes of the secure environment. At a minimum, either a call to gsk_attribute_set_buffer() to set the GSK_OS400_APPLICATION_ID value or to set the GSK_KEYRING_FILE value. Only one of these should be set. It is preferred that you use the GSK_OS400_APPLICATION_ID value. Also ensure you set the type of application (client or server), GSK_SESSION_TYPE, using gsk_attribute_set_enum().
- A call to gsk_environment_init() to initialize this environment for secure processing and to establish the SSL/TLS security information for all secure sessions that run using this environment.
- The socket() API creates a socket descriptor. The client then issues the connect() API to connect to the server application.
- The gsk_secure_soc_open() API obtains storage for a secure session, sets default values for attributes, and returns a handle that must be saved and used on secure session-related API calls.
- The gsk_attribute_set_numeric_value() API associates a specific socket with this secure session.
- The gsk_secure_soc_init() API starts an asynchronous negotiation of a secure session, using the attributes set for the secureenvironment and the secure session.
- The gsk_secure_soc_write() API
writes data on a secure session to the worker thread. Note: For the GSKit server example, this API writes data to the worker thread where the gsk_secure_soc_startRecv() API is completed. In the asynchronous example, it writes to the completed gsk_secure_soc_startInit() .
- The gsk_secure_soc_read() API receives a message from the worker thread using the secure session.
- The gsk_secure_soc_close() API ends the secure session.
- The gsk_environment_close() API closes the secure environment.
- The close() API ends the connection.
Note: By using the examples, you agree to the terms of the Code license and disclaimer information.
/* GSK Client Program using Application Id */
/* This program assumes that the application id is */
/* already registered and a certificate has been */
/* associated with the application id */
/* */
/* No parameters, some comments and many hardcoded */
/* values to keep it short and simple */
/* use following command to create bound program: */
/* CRTBNDC PGM(MYLIB/GSKCLIENT) */
/* SRCFILE(MYLIB/CSRC) */
/* SRCMBR(GSKCLIENT) */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <gskssl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#define TRUE 1
#define FALSE 0
void main(void)
{
gsk_handle my_env_handle=NULL; /* secure environment handle */
gsk_handle my_session_handle=NULL; /* secure session handle */
struct sockaddr_in6 address;
int buf_len, rc = 0, sd = -1;
int amtWritten, amtRead;
char buff1[1024];
char buff2[1024];
/* hardcoded IP address (change to make address where server program runs) */
char addr[40] = "FE80::1";
/*********************************************/
/* Issue all of the command in a do/while */
/* loop so that cleanup can happen at end */
/*********************************************/
do
{
/* open a gsk environment */
rc = errno = 0;
rc = gsk_environment_open(&my_env_handle);
if (rc != GSK_OK)
{
printf("gsk_environment_open() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* set the Application ID to use */
rc = errno = 0;
rc = gsk_attribute_set_buffer(my_env_handle,
GSK_OS400_APPLICATION_ID,
"MY_CLIENT_APP",
13);
if (rc != GSK_OK)
{
printf("gsk_attribute_set_buffer() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* set this side as the client (this is the default */
rc = errno = 0;
rc = gsk_attribute_set_enum(my_env_handle,
GSK_SESSION_TYPE,
GSK_CLIENT_SESSION);
if (rc != GSK_OK)
{
printf("gsk_attribute_set_enum() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* by default TLSV10, TLSV11, and TLSV12 are enabled */
/* We will disable SSL_V3 for this example. */
rc = errno = 0;
rc = gsk_attribute_set_enum(my_env_handle,
GSK_PROTOCOL_SSLV3,
GSK_PROTOCOL_SSLV3_OFF);
if (rc != GSK_OK)
{
printf("gsk_attribute_set_enum() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* We will disable TLS_V10 for this example. */
rc = errno = 0;
rc = gsk_attribute_set_enum(my_env_handle,
GSK_PROTOCOL_TLSV10,
GSK_FALSE);
if (rc != GSK_OK)
{
printf("gsk_attribute_set_enum() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* We will disable TLS_V11 for this example. */
rc = errno = 0;
rc = gsk_attribute_set_enum(my_env_handle,
GSK_PROTOCOL_TLSV11,
GSK_FALSE);
if (rc != GSK_OK)
{
printf("gsk_attribute_set_enum() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* set the cipher suite to use. By default our default list */
/* of ciphers is enabled. For this example we will just use one */
rc = errno = 0;
rc = gsk_attribute_set_buffer(my_env_handle,
GSK_TLSV12_CIPHER_SPECS_EX,
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
39);
if (rc != GSK_OK)
{
printf("gsk_attribute_set_buffer() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* Initialize the secure environment */
rc = errno = 0;
rc = gsk_environment_init(my_env_handle);
if (rc != GSK_OK)
{
printf("gsk_environment_init() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* initialize a socket to be used for listening */
sd = socket(AF_INET6, SOCK_STREAM, 0);
if (sd < 0)
{
perror("socket() failed");
break;
}
/* connect to the server using a set port number */
memset((char *) &address, 0, sizeof(address));
address.sin6_family = AF_INET6;
address.sin6_port = 13333;
rc = inet_pton(AF_INET6, addr, &address.sin6_addr.s6_addr);
rc = connect(sd, (struct sockaddr *) &address, sizeof(address));
if (rc < 0)
{
perror("connect() failed");
break;
}
/* open a secure session */
rc = errno = 0;
rc = gsk_secure_soc_open(my_env_handle, &my_session_handle);
if (rc != GSK_OK)
{
printf("gsk_secure_soc_open() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* associate our socket with the secure session */
rc=errno=0;
rc = gsk_attribute_set_numeric_value(my_session_handle,
GSK_FD,
sd);
if (rc != GSK_OK)
{
printf("gsk_attribute_set_numeric_value() failed with rc = %d ", rc);
printf("and errno = %d.\n", errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* initiate the secure handshake */
rc = errno = 0;
rc = gsk_secure_soc_init(my_session_handle);
if (rc != GSK_OK)
{
printf("gsk_secure_soc_init() failed with rc = %d and errno = %d.\n",
rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* memset buffer to hex zeros */
memset((char *) buff1, 0, sizeof(buff1));
/* send a message to the server using the secure session */
strcpy(buff1,"Test of gsk_secure_soc_write \n\n");
/* send the message to the client using the secure session */
buf_len = strlen(buff1);
amtWritten = 0;
rc = gsk_secure_soc_write(my_session_handle, buff1, buf_len, &amtWritten);
if (amtWritten != buf_len)
{
if (rc != GSK_OK)
{
printf("gsk_secure_soc_write() rc = %d and errno = %d.\n",rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
else
{
printf("gsk_secure_soc_write() did not write all data.\n");
break;
}
}
/* write results to screen */
printf("gsk_secure_soc_write() wrote %d bytes...\n", amtWritten);
printf("%s\n",buff1);
/* memset buffer to hex zeros */
memset((char *) buff2, 0x00, sizeof(buff2));
/* receive a message from the client using the secure session */
amtRead = 0;
rc = gsk_secure_soc_read(my_session_handle, buff2, sizeof(buff2), &amtRead);
if (rc != GSK_OK)
{
printf("gsk_secure_soc_read() rc = %d and errno = %d.\n",rc,errno);
printf("rc of %d means %s\n", rc, gsk_strerror(rc));
break;
}
/* write results to screen */
printf("gsk_secure_soc_read() received %d bytes, here they are ...\n",
amtRead);
printf("%s\n",buff2);
} while(FALSE);
/* disable secure support for the socket */
if (my_session_handle != NULL)
gsk_secure_soc_close(&my_session_handle);
/* disable the secure environment */
if (my_env_handle != NULL)
gsk_environment_close(&my_env_handle);
/* close the connection */
if (sd > -1)
close(sd);
return;
}