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.

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.

  1. The gsk_environment_open() API obtains a handle to a secure environment.
  2. 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().
  3. 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.
  4. The socket() API creates a socket descriptor. The client then issues the connect() API to connect to the server application.
  5. 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.
  6. The gsk_attribute_set_numeric_value() API associates a specific socket with this secure session.
  7. 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.
  8. 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() .
  9. The gsk_secure_soc_read() API receives a message from the worker thread using the secure session.
  10. The gsk_secure_soc_close() API ends the secure session.
  11. The gsk_environment_close() API closes the secure environment.
  12. 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;
}