Programming with the socket API enables TCP/IP communications over a network. The flaw in the standard TCP/IP design is that the data is sent "in the clear." The Internet is made up of many interconnected networks, and anyone with access to one of them can view what you're sending and receiving.
For most communications, this isn't a problem. After all, who cares if someone can see that you're searching Google? Nothing in that transaction is confidential!
Other times, you have data that should be protected. Credit card numbers and Social Security numbers are examples of things that should always be protected.
Secure Sockets Layer (SSL) and Transport Layer Security (TLS) have become an industry standard method of protecting Internet communications. This article explains the basics of these security protocols and demonstrates using them from an RPG program.
This article assumes that you're already familiar with socket programming. If not, please read the following articles first:
Introduction to TCP/IP Programming
Handling Errors in TCP/IP Programming
What Is SSL? What Is TLS?
SSL was developed by Netscape as a means of protecting Internet communications. Netscape released three versions of SSL, each one better and more secure than the last. SSL version 3.0 worked so nicely that the Internet Engineering Task Force (IETF) decided to use it as a basis for the open standard for TCP security. This open standard is called Transport Layer Security (TLS) version 1.0, but you can think of it as SSL version 4.0. It's the latest and greatest version of SSL and is supported by all major SSL software implementations today.
One of the important features of SSL version 3.0 and TLS is that they're able to "fall back" to previous versions of SSL when needed. For that reason, I recommend that you write your software for TLS, and let it fall back to version 3.0 or 2.0 as necessary. Version 1.0 is obsolete and is no longer supported in most SSL packages.
For the remainder of this article, when I refer to SSL, I'm actually talking about both SSL and TLS. Again, TLS is nothing more than the newest version of SSL.
Authentication
SSL solves two problems, that of encryption and that of authentication. In other words, not only does SSL encrypt data so that it's unreadable to third parties, but it also verifies the identity of the program at the other end of the connection. After all, it doesn't do you any good to encrypt data if you're sending it to a malicious hacker! You need to know that you're sending it to someone you trust.
How does it know who it's talking to? Each side of the connection has a digital identity called a "certificate." This certificate contains a cryptographic key that provides positive identification. For example, I could have a certificate on my Web server that identifies it as www.klements.com. When you connect to me with SSL, that certificate is sent to you.
How do you know that I didn't lie about being www.klements.com? When certificates are issued, they must be issued by a certificate authority (CA). The CA digitally signs the certificate to verify that the CA did some research and that it vouches that I'm really Scott Klement, and that I really own www.klements.com. If you can trust the CA, then you know that I'm really who I say I am.
The way you say that you trust a certificate authority is by installing their CA certificate on your system. When you connect with SSL to a system claiming to be signed by that CA, cryptography is used to verify that the key in the CA certificate was used to sign the server certificate of the system you connected to.
Imagine running a site like Amazon.com, where millions of people are connecting with SSL. Surely, it's impractical for Amazon to ask every single customer to download its CA certificate and install it into that customer's Web browser? For that reason, some of the major certificate authority companies have their CA certificates automatically installed when SSL is installed.
VeriSign and Thawte are two of the best-known CA companies. You can order a certificate from them, and they will then do a little bit of research to make sure that you are who you claim to be. Once issued, their certificates are trusted by everyone, because their CA certificate was installed automatically when SSL was installed.
On the other hand, if I create my own certificate authority, and issue my own certificates, it can save me some money especially if I have hundreds or thousands of certificates to issue! The only problem is that my certificate authority certificate would have to be manually installed into the browser, or other SSL software, of anyone who wants to use my services. This actually works very nicely within my company. I can create my own certificates for my TN5250 server, and I can issue a separate certificate for each employee who wants to connect to it. I set things up so that only my own CA is trusted for TN5250. That way, I know that everyone who connects or uses my system is really an employee!
Enough Background!
There are lots of details involved in cryptography, but fortunately the APIs take care of most of the work, and we don't have to worry about it. I hope that the introduction that I've given here gives you enough information to get started. If not, I suggest reading the SSL introduction that Apache has on its Web site. You can find it at the following link:
http://httpd.apache.org/docs/2.2/ssl/ssl_intro.html
Required IBM Software
Before you can start writing software that uses SSL, you need to have the right stuff on your iSeries. Here's a link to the Information Center area that has information about the licensed programs required:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/rzain/rzainplanssl.htm
All the required software is available on your OS/400 or i5/OS installation media, except for the IBM Cryptographic Access Provider (5722-AC3). If you don't already have that, you need to order it from your IBM Business Partner. It's a no-charge item, but it has to be ordered separately due to the various laws governing cryptography around the world.
If you're already using SSL for something else on your system, you already have these licensed programs installed.
Configuring the Software
After the software is installed, you need to create a "certificate store." This is where SSL certificates and their digital keys are stored on the iSeries. The default certificate store is called *SYSTEM. Again, if you're already using SSL on your system, you've already created the *SYSTEM certificate store. If not, you can do so by following these steps:
STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)
The Global Secure Toolkit
IBM released two different sets of APIs for SSL programming on the iSeries. The original SSL API was released in V4R3, and the Global Secure Toolkit (GSKit) API was released in V5R1. IBM has stated that the GSKit API will be the only one that's enhanced and that the original SSL API will eventually be removed. I've also found the GSKit API easier to use, so that's the one that I write about here.
Creating an Environment
The first step to writing an SSL program is creating an environment from which SSL certificates can be created or verified. The environment contains all the cryptographic components for the local side of the connection. You can reuse this environment for many sockets if you like, because the local part of the information won't need to change.
A lot of different parameters are needed to create an SSL environment, but the API does a good job of hiding the complexity for me by providing default values for all the settings. The only values that I need to change are the ones that differ from the defaults.
I start by calling the gsk_environment_open() API. This creates a data structure in the API's memory that contains all of the default SSL settings. It provides me with a pointer that I can't use directly but can pass to the other GSKit APIs to tell them which environment I'm referring to.
There are APIs called gsk_attribute_set_buffer(), gsk_attribute_set_enum(), and gsk_attribute_set_numeric_value() that I can call to change the values of fields in the data structure that contains the environment's parameters. For a simple client application, I need to tell the system that I want to use the *SYSTEM certificate store, and that I want to use it to create client sessions.
After I've changed any of the parameters that I need to change, I call the gsk_environment_init() API. It uses the parameters in the data structure to initialize an SSL environment and it does any of the cryptographic processing that can be done at this point. After I've called gsk_environment_init(), my environment is set up, and I can no longer change the parameters for it.
Here's the RPG code that I used to create a GSKit environment:
P CreateEnv B
D CreateEnv PI like(gsk_handle)
D rc s 10I 0
D SslEnv s like(Gsk_handle)
/free
// Create an SSL environment with default values:
rc = gsk_environment_open(SslEnv);
if (rc <> GSK_OK);
return *NULL;
endif;
// Tell the environment to use the *SYSTEM certificate
// store
rc = gsk_attribute_set_buffer( SslEnv
: GSK_KEYRING_FILE
: '*SYSTEM'
: 0 );
if (rc <> GSK_OK);
gsk_environment_close( SslEnv );
return *NULL;
endif;
// Tell the environment that this is a client connection
rc = gsk_attribute_set_enum( SslEnv
: GSK_SESSION_TYPE
: GSK_CLIENT_SESSION );
if (rc <> GSK_OK);
gsk_environment_close( SslEnv );
return *NULL;
endif;
// Activate the new environment.
rc = gsk_environment_init( SslEnv );
if (rc <> GSK_OK);
gsk_environment_close( SslEnv );
return *NULL;
endif;
return SslEnv;
/end-free
P E
Establishing a TCP Connection
The SSL protocol is a "layer" that runs on top of a standard socket. That's why it's called Secure Socket Layer. To use it, I need to create a standard socket and connect it to a server. Here's some sample code that does that:
P ConnSock B
D ConnSock PI 10I 0
d host 256A const
D port 10I 0 value
D s s 10I 0
D addr s 10U 0
/free
// look up host
addr = inet_addr(%trim(host));
if (addr = INADDR_NONE);
p_hostent = gethostbyname('www.klements.com');
if (p_hostent = *NULL);
errMsg = 'Host not found!';
EscapeMsg();
endif;
addr = h_addr;
endif;
// Create a socket
s = socket(AF_INET: SOCK_STREAM: IPPROTO_IP);
if (s < 0);
ReportError();
endif;
// connect to the host
connto = *ALLx'00';
connto.sin_family = AF_INET;
connto.sin_addr = addr;
connto.sin_port = port;
if (connect(s: %addr(Connto): %size(connto)) = -1);
callp close(S);
ReportError();
endif;
return s;
/end-free
P E
There's nothing special about the preceding socket code. It simply creates a TCP connection to a server. When that connection has been established, I need to "upgrade" that socket to SSL.
Upgrading the Connection to SSL
Upgrading to SSL uses a similar paradigm to that of creating an SSL environment. You first create a data structure containing all the default settings for the new SSL session using the gsk_secure_soc_open() API. You can then change any of those default settings. When you have all the settings the way you want them, you initialize the secure socket by calling the gsk_secure_soc_init() API.
The gsk_secure_soc_init() API does more than just cryptography. It also uses your connected socket to exchange certificates as well as other cryptographic information. This exchange is often called the "SSL Handshake."
There are two settings that I set in my secure socket data structure before I start the SSL handshake. The first one is a timeout value of 30 seconds for the handshake process, and it prevents a long delay from happening if you connect to a site that doesn't support SSL. The other important setting is the socket descriptor itself. For the SSL API to use your connected socket, you have to tell it the descriptor. That's how it knows which socket to communicate over.
Here's the code that upgrades my socket to an SSL one:
P UpgradeSock B
D UpgradeSock PI like(gsk_handle)
D SslEnv like(gsk_handle) value
D sock 10I 0 value
D Handle s like(Gsk_handle)
/free
rc = gsk_secure_soc_open(SslEnv: Handle);
if (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
return *NULL;
endif;
rc = gsk_attribute_set_numeric_value( Handle
: GSK_HANDSHAKE_TIMEOUT
: 30 );
if (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_secure_soc_close(Handle);
return *NULL;
endif;
rc = gsk_attribute_set_numeric_value( Handle
: GSK_FD
: sock );
if (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_secure_soc_close(Handle);
return *NULL;
endif;
rc = gsk_secure_soc_init( Handle );
if (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_secure_soc_close(Handle);
return *NULL;
endif;
return Handle;
/end-free
P E
Sending and Receiving Secure Data
After the handshake is complete, your socket has successfully been upgraded to SSL, and the certificates have been verified, and the encryption is active. To send and receive data over this connection, you use the gsk_secure_soc_write() and gsk_secure_soc_read() API. Do not use the send() or recv() API, because those send the data unencrypted!
Here's an example of sending data over a secure socket:
cmd = 'GET /cgi-bin/ssltest HTTP/1.0' + CRLF
+ 'Host: www.klements.com' + CRLF
+ 'Connection: close' + CRLF
+ CRLF;
len = %len(%trimr(cmd));
QDCXLATE( len
: cmd
: 'QTCPASC' );
callp gsk_secure_soc_write( Handle
: %addr(cmd)
: len
: bytesSent );
The Handle variable in the preceding example is the secure socket handle returned from the gsk_secure_soc_open() API. The cmd variable contains the data that I wanted to send, the len variable contains the length of the data, and the bytesSent variable is returned to me to tell me how many bytes were sent successfully. Because the server that I'm communicating with uses ASCII, I've also translated the data to ASCII using the QDCXLATE API.
Receiving data works the same way, except that you call the gsk_secure_soc_read() API. Here's an example that keeps reading a secure socket until an error occurs:
Reply = *blanks;
left = %size(Reply);
buf = %addr(reply);
received = 0;
// keep reading until we get the entire response
dou (rc <> GSK_OK);
rc = gsk_secure_soc_read( Handle
: buf
: left
: bytesRead );
if (rc = GSK_OK);
received = received + bytesRead;
buf = buf + bytesRead;
left = left - bytesRead;
endif;
enddo;
QDCXLATE( received
: reply
: 'QTCPEBC' );
Closing the Connection
When you're done sending and receiving data, you need to close the socket normally and also close the secure socket using the gsk_secure_soc_close() API.
gsk_secure_Soc_close( handle);
callp close(sock);
When you're done with all the SSL sockets that you plan to use in your program, use the gsk_environment_close() API to get rid of the SSL environment:
gsk_environment_close( SslEnv );
Sample Code and Documentation
To demonstrate everything that I discuss in this article, I've written a program that connects to my Web server at www.klements.com via SSL. It runs a CGI program on that server that reports whether I'm using SSL or not. If you'd like to try it out, you can download the sample code from the following link:
http://www.pentontech.com/IBMContent/Documents/article/52329_64_SslDemo.zip
The reference information for the GSKit API is in the Information Center at the following link:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/unix9.htm