SSL Programmer's Reference
Contents
Introduction to Secure Sockets Layer and Transport Layer Security
Secure Sockets Layer (SSL) and its newer IETF version Transport Layer Security (TLS) runs above TCP layer and below higher application level protocols such as HTTP, FTP, SMTP, see Figure 1.
Figure 1: SSL/TLS runs between network layer and application layer
SSL/TLS allows an SSL-enabled server to authenticate itself to an SSL-enabled client, and if necessary, allows the client to authenticate itself to the server. After the authentication and cryptology parameter negotiation, a secure channel is established so that the client and server can exchange information in a secure way.
In order to SSL/TLS-enable your server, firstly, you need obtain a certificate from a Certificate Authority (CA) whose public certificate is accessible to all your potential clients. For example, if you want to build an SSL/TLS enabled web server with potential clients all over the world, you need a certificate from CA like http://wwww.verisign.com, while, if your clients are all from the same company, a certificate from company Registration Authority (RA) is good enough. Secondly, the certificate you obtained must have a certain binding to your SSL/TLS-enabled server. For example, if your SSL/TLS server is running at www.sslfoobar.com, then your certificate should bind to "www.sslfoobar.com", most likely as the Common Name in the SubjectName field of your certificate.
Figure 2: Packet Format of SSL Record
Figure 2 shows the packet format of an SSL record. One TCP fragment may include one or more SSL records, or even partial of one SSL record. All shaded parts in Figure 2 are encrypted upon receiving. The receiver waits until a full SSL record has been received, then it decrypts the record, verifies the padding if necessary, and verifies the hashing results. If all the verification passes, the receiver puts the Data into socket receiving queue for user to retrieve.
SSL/TLS handshake messages are responsible to negotiate the encryption and hashing algorithms to protect Data. Before handshake negotiation finishes, SSL/TLS handshake messages are sent in format as shown in Figure 2, however, in clear text format rather than encrypted, and no hashing results and no padding. The receiver can tell if an SSL record is a handshake record or not by looking at the 'type' field. Figure 3 shows a typical handshake exchange.
Client Server ClientHello --------> ServerHello Certificate <-------- ServerHelloDone ClientKeyExchange ChangeCipherSpec Finished(encrypted) --------> ChangeCipherSpec <-------- Finished(encrypted) Application Data <------------------> Application Data (encrypted) (encrypted)
Figure 3: Typical SSL Handshake
Treck SSL/TLS Features
Treck SSL/TLS is proud to have the following features:
- Small code size. Treck SSL has small code size of about 50k.
- Supports 512, 1024, 2048-bit and above exportable and non-exportable cipher suites
- Configurable support for any combination of SSL 3.0, TLS 1.0, TLS 1.1 and TLS 1.2
- Configurable support for SSL server, SSL client or both
- Configurable support for RSA and Ephemeral Diffie-Hellman key exchange method
- Configurable support for RSA signature algorithm with MD5 or SHA1 to SHA512
- Configurable support for DSS signature algorithm with MD5 or SHA1 to SHA256
- Configurable support for Mutual authentication
- Support SSL re-handshake
- Configurable support for parsing SSL 2.0 client hello
- Configurable support for DES, 3DES, AES, RC2, and ARCFOUR (compatible with RC4) algorithms
- Support resumed handshake, user determines the cache size.
- Support for configuring cipher suite per session level
- Support user interaction in certificate processing
- Support wild card certificate match
- Support socket call back function for SSL events, such as handshake failure, connection establishment, connection close for each direction, or bad certificate
- Standard BSD Socket APIs for sending and receiving user data
- Support for the TLS Server Name Indication (SNI) extension (RFC 6066):
- Define macro TM_USE_TLSEXT_SERVER_NAME in trsystem.h to enable support.
- Call tfSslSetHostname() to set the name (client-side).
- Call tfSslSetSessionOptions() to configure the type of response (server-side).
- Supported Cipher suites include:
TM_TLS_RSA_NULL_MD5 0x0001 TM_TLS_RSA_NULL_SHA 0x0002 TM_TLS_RSA_EXPORT_RC4_40_MD5 0x0003 TM_TLS_RSA_RC4_128_MD5 0x0004 TM_TLS_RSA_RC4_128_SHA 0x0005 TM_TLS_RSA_EXPORT_RC2_40_MD5 0x0006 TM_TLS_RSA_EXPORT_DES40_CBC_SHA 0x0008 TM_TLS_RSA_DES_CBC_SHA 0x0009 TM_TLS_RSA_3DES_EDE_CBC_SHA 0x000A TM_TLS_DHE_DSS_EPT_DES40_CBC_SHA 0x0011 TM_TLS_DHE_DSS_DES_CBC_SHA 0x0012 TM_TLS_DHE_DSS_3DES_EDE_CBC_SHA 0x0013 TM_TLS_DHE_RSA_EPT_DES40_CBC_SHA 0x0014 TM_TLS_DHE_RSA_DES_CBC_SHA 0x0015 TM_TLS_DHE_RSA_3DES_EDE_CBC_SHA 0x0016 TM_TLS_RSA_AES_128_CBC_SHA 0x002F TM_TLS_DHE_DSS_AES_128_CBC_SHA 0x0032 TM_TLS_DHE_RSA_AES_128_CBC_SHA 0x0033 TM_TLS_RSA_AES_256_CBC_SHA 0x0035 TM_TLS_DHE_DSS_AES_256_CBC_SHA 0x0038 TM_TLS_DHE_RSA_AES_256_CBC_SHA 0x0039 TM_TLS_RSA_EPT1K_DES_CBC_SHA 0x0062 TM_TLS_DHE_DSS_EPT1K_DES_CBC_SHA 0x0063 TM_TLS_RSA_EPT1K_RC4_56_SHA 0x0064 TM_TLS_DHE_DSS_EPT1K_RC4_56_SHA 0x0065 TM_TLS_DHE_DSS_RC4_128_SHA 0x0066
- TLS 1.2 cipher suites:
TM_TLS_RSA_NULL_SHA256 0x003B TM_TLS_RSA_AES_128_CBC_SHA256 0x003C TM_TLS_RSA_AES_256_CBC_SHA256 0x003D TM_TLS_DHE_DSS_AES_128_CBC_SHA256 0x0040 TM_TLS_DHE_RSA_AES_128_CBC_SHA256 0x0067 TM_TLS_DHE_DSS_AES_256_CBC_SHA256 0x006A TM_TLS_DHE_RSA_AES_256_CBC_SHA256 0x006B
- Elliptic Curve cipher suites:
TM_TLS_ECDH_ECDSA_NULL_SHA 0xC001 TM_TLS_ECDH_ECDSA_RC4_128_SHA 0xC002 TM_TLS_ECDH_ECDSA_3DES_EDE_CBC_SHA 0xC003 TM_TLS_ECDH_ECDSA_AES_128_CBC_SHA 0xC004 TM_TLS_ECDH_ECDSA_AES_256_CBC_SHA 0xC005 TM_TLS_ECDHE_ECDSA_NULL_SHA 0xC006 TM_TLS_ECDHE_ECDSA_RC4_128_SHA 0xC007 TM_TLS_ECDHE_ECDSA_3DES_EDE_CBC_SHA 0xC008 TM_TLS_ECDHE_ECDSA_AES_128_CBC_SHA 0xC009 TM_TLS_ECDHE_ECDSA_AES_256_CBC_SHA 0xC00A TM_TLS_ECDHE_RSA_NULL_SHA 0xC010 TM_TLS_ECDHE_RSA_RC4_128_SHA 0xC011 TM_TLS_ECDHE_RSA_3DES_EDE_CBC_SHA 0xC012 TM_TLS_ECDHE_RSA_AES_128_CBC_SHA 0xC013 TM_TLS_ECDHE_RSA_AES_256_CBC_SHA 0xC014 TM_TLS_ECDHE_ECDSA_AES_128_CBC_SHA256 0xC023 TM_TLS_ECDHE_ECDSA_AES_256_CBC_SHA384 0xC024 TM_TLS_ECDHE_RSA_AES_128_CBC_SHA256 0xC027 TM_TLS_ECDHE_RSA_AES_256_CBC_SHA384 0xC028
- GCM (Galois/Counter Mode) cipher suites:
TM_TLS_RSA_AES_128_GCM_SHA256 0x009C TM_TLS_RSA_AES_256_GCM_SHA384 0x009D TM_TLS_DHE_RSA_AES_128_GCM_SHA256 0x009E TM_TLS_DHE_RSA_AES_256_GCM_SHA384 0x009F TM_TLS_DHE_DSS_AES_128_GCM_SHA256 0x00A2 TM_TLS_DHE_DSS_AES_256_GCM_SHA384 0x00A3 TM_TLS_ECDHE_ECDSA_AES_128_GCM_SHA256 0xC02B TM_TLS_ECDHE_ECDSA_AES_256_GCM_SHA384 0xC02C TM_TLS_ECDHE_RSA_AES_128_GCM_SHA256 0xC02F TM_TLS_ECDHE_RSA_AES_256_GCM_SHA384 0xC030
- Pre-Shared Key cipher suites:
TM_TLS_PSK_RC4_128_SHA 0x008A TM_TLS_PSK_3DES_EDE_CBC_SHA 0x008B TM_TLS_PSK_AES_128_CBC_SHA 0x008C TM_TLS_PSK_AES_256_CBC_SHA 0x008D
Compile Time Settings
Function Reference
For PKI APIs please see the PKI page.
Examples
SSL Server Example
#include <trsocket.h> int main() { ttUserLinkLayer linkLayerHandle; ttUserInterface interfaceHandle; struct sockaddr_storage myIp4Addr; struct sockaddr_storage peerIp4Addr; char * rootCaCertIdentity = âroot_ca_certificateâ; char * myCertIdentity = âssl_server_certificateâ; char buffer[BUFFER_SIZE]; int value; int sockListen; int sockAccept; int sessionId; int recvLen; int sentLen; ... /*Step 1. Start Treck */ errorCode = tfStartTreck(); /*Step 2. Open Link layer and open interface. */ linkLayerHandle = tfUseEthernet(); /* Using win32 port */ interfaceHandle = tfUseWin32Driver( "eth0", linkLayerHandle, &errorCode); errorCode = tfNgOpenInterface( interfaceHandle, &myIp4Addr, 24, TM_DEV_MCAST_ENB, 0, 1, 0); assert(errorCode == TM_ENOERROR); /*Step 3. Open a listening socket and bind it to SSL server address, if SSL is not used, we may call listen (step 7) right after this step. Now, since SSL is used, we need insert step 4, step 5 and step 6 before we call listen */ sockListen = socket(PF_INET, SOCK_STREAM, IP_PROTOTCP); assert(sockListen != -1); myIp4Addr.ss_port = htons(TM_SSL_PORT); errorCode = bind(sockListen, (struct sockaddr *)&myIp4Addr.addr.ipSockAddr, sizeof(myIp4Addr)); assert(errorCode == TM_ENOERROR); #ifdef TM_USE_SSL_SERVER /*Step 4. Enable PKI and add certificates , we need at least add root CAâs certificate as well as the SSL serve râs own certificate. In order to add SSL serverâs own certificate, we must add private/public key pair first */ errorCode = tfUsePki(); assert(errorCode == TM_ENOERROR); /* add CAâs certificate, name it â rootcascertificateâ, cacert.pem is the CA certificate file, must in openssl format , i.e., starting line must contain âBeginâ, ending line must contain âEndâ . Note that if no file system is supported, you can call with memory pointer rather than file name, please see tfPkiCertificateAdd for details */ errorCode = tfPkiCertificateAdd ( "cacert.pem", /*the file name of ca cert*/ TM_PKI_CERTIFICATE_PEM, TM_PKI_CERT_NONLOCAL | TM_PKI_CERT_ROOTCA, rootCaCertIdentity, /*name of ca cert*/ strlen(rootCaCertIdentity), 0); /* add SSL serverâs private key and public key pair. Suppose we are going to use RSA key pairs, OpenSSL calls this private key */ errorCode = tfPkiOwnKeyPairAdd ( "rsa1024key.pem", TM_PKI_CERTIFICATE_PEM, TM_PKI_RSA_KEY ); /* add SSL serverâs certificate. This LOCAL certificate certificates the key pair you just added above */ errorCode = tfPkiCertificateAdd ( "rsa1024cert.pem", TM_PKI_CERTIFICATE_PEM, TM_PKI_CERT_LOCAL, myCertIdentity ,/*name of SSL server cert*/ strlen(myCertIdentity), rootCaCertIdentity); /* The ca certificate which is used to sign SSL serverâs certificate */ assert(errorCode == TM_ENOERROR); /*Step 5. Enable SSL and open a new SSL server session. If we need add ephemeral RSA keys, add it now by calling tfSslAddEphemeralRsaKeys. If we use mutual authentication and we need to add client authentication CAs, add it now by calling tfSslServerAddClientAuthCa */ errorCode = tfUseSsl(16); /*as many as 16 sessions are supported */ assert(errorCode == TM_ENOERROR); sessionId = tfSslNewSession( /*In this session, use the following SSL serverâs certificate. If you have two SSL servers to support, you need two server sessions */ myCertIdentity, /* each session will have as many as 16 cache entries */ 16, /* This session, TLS 1.0, 1.1 and 1.2 are supported */ TM_TLS_VERSION_10 | TM_TLS_VERSION_11 | TM_TLS_VERSION_12, /* No options are required. (No client authentication) */ 0); assert(sessionId != -1); /*Step 6. set socket option for that listening socket . If you want to enable SSL after a normal TCP connection has been established, please see the example in tfSslServerUserCreate */ value = 1; /* To indicate that this is SSL server */ errorCode = setsockopt (sockListen, IP_PROTOTCP, TM_TCP_SSL_SERVER, (const char TM_FAR *) &value, sizeof (int)); assert(errorCode == TM_ENOERROR); /*This listening socket is going to use SSL session # sessionId */ value = sessionId; errorCode = setsockopt (sockListen, IP_PROTOTCP, TM_TCP_SSLSESSION, (const char TM_FAR *) &value, sizeof (int)); assert(errorCode == TM_ENOERROR); /* Set the SSL send threshold size. This call will overwrite the default value TM_SSL_SEND_DATA_MIN_SIZE */ value = 300; errorCode = setsockopt (sockListen, IP_PROTOTCP, TM_TCP_SSL_SEND_MIN_SIZE, (const char TM_FAR *) &value, sizeof (int)); assert(errorCode == TM_ENOERROR); #endif /* TM_USE_SSL_SERVER */ /*Step 7. Now we are able to call listen, accept, send and receive. Data exchanged in this SSL-enabled socket is protected by the SSL cipher suite negotiated in SSL handshake. Note that, we use the same send() and recv() API for SSL and normal TCP connec tion */ errorCode = listen(sockListen, 1); assert(errorCode != TM_SOCKET_ERROR); sockAccept = accept(sockListen, (struct sockaddr TM_FAR *)&peerIp4Addr, (int TM_FAR *)&sockaddrLength); { recvLen = recv( sockAccept, buffer, BUFFER_SIZE, 0); sentLen = send( sockAccept, buffer, recvLen, 0); ... } #ifdef TM_USE_SSL_SERVER /*Step 8. User may explicitly flush the SSL send buffer */ sentLen = tfSslUserSendFlush(sockAccept); /*Step 9. User may explicitly call connect close to close the SSL layer on sockAccept */ errorCode = tfSslConnectUse rClose(sockAccept) #endif /* TM_USE_SSL_SERVER */ /*Step 9.1. After SSL layer is tore down, user can still be able to call send and recv on this same socket to send/receive unprotected TCP data. */ { recvLen = recv( sockAccept, buffer, BUFFER_SIZE, 0); sentLen = send( sockAccept, buffer, recvLen, 0); ... } /* If SSL is used, and user doesnât explicitly call Ste p 8 and Step 9, the tfClose call will implicitly call them */ tfClose(sockAccept); tfClose(sockListen); /*Step 10. If sessionId is not used any more, close it */ tfSslSessionUserClose(sessionId); /*Step 11. If SSL is not used by any other app lications, un-initialize it, i.e., free the SSL global variable */ tfSslUninitialize(); /*Step 12. If PKI is not used by any other applications, un -initialize it, i.e., free the PKI global variable */ tfPkiUninitialize(); return errorCode; }
SSL Client Example
#include <trsocket.h> int main() { ttUserLinkLayer linkLayerHandle; ttUserInterface interfaceHandle; struct sockaddr_storage myIp4Addr; struct sockaddr_storage serverAddr; char * rootCaCertIdentity = "root_ca_certificate"; char * myCertIdentity = (char *)0; char buffer[BUFFER_SIZE]; int value; int sockConn; int sessionId; int recvLen; int sentLen; ... /*Step 1. Start Treck */ errorCode = tfStartTreck(); /*Step 2. Open Link layer and open interface. */ linkLayerHandle = tfUseEthernet(); /* Using win32 port */ interfaceHandle = tfUseWin32Driver( "eth0", linkLayerHandle, &errorCode); errorCode = tfNgOpenInterface( interfaceHandle, &myIp4Addr, 24, TM_DEV_MCAST_ENB, 0, 1, 0); assert(errorCode == TM_ENOERROR); /*Step 3. Open a connecting socket, set the server's address. If SSL is not used, we may call connect (step 7) right after this step. Now, since SSL is used, we need insert step 4, step 5 and step 6 before we call connect */ sockConn = socket(PF_INET, SOCK_STREAM, IP_PROTOTCP); assert(sockConn != -1); serverAddr.ss_len = sizeof(struct sockaddr_in); serverAddr.ss_family = PF_INET; serverAddr.addr.ipv4.sin_addr.s_addr = inet_addr("192.168.0.111"); serverAddr.ss_port = htons(TM_SSL_PORT); #ifdef TM_USE_SSL_CLIENT /*Step 4. Enable PKI and add certificates, we need at least add root CA's certificate as well as the SSL server's own certificate. In order to add SSL server's own certificate, we must add private/public key pair first */ errorCode = tfUsePki(); assert(errorCode == TM_ENOERROR); /* add CA's certificate, name it " rootcascertificate", cacert.pem is the CA certificate file, must in openssl format, i.e., starting line must contain `Begin', ending line must contain `End'. Note that if no file system is supported, you can call with memory pointer rather than file name, please see tfPkiCertificateAdd for details */ errorCode = tfPkiCertificateAdd ("cacert.pem", /*the file name of ca cert*/ TM_PKI_CERTIFICATE_PEM, TM_PKI_CERT_NONLOCAL | TM_PKI_CERT_ROOTCA, rootCaCertIdentity, /*name of ca cert*/ strlen(rootCaCertIdentity), 0); /* If client authentication is used, we need to add SSL client's private/public key pairs and the corresponding certificate, see SSL server example to see how to add them */ /*Step 5. Enable SSL and open a new SSL client session. If we need change default cipher suite proposals, we call tfSslSetSessionProposals on that client session */ errorCode = tfUseSsl(16); /*as many as 16 sessions are supported */ assert(errorCode == TM_ENOERROR); sessionId = tfSslNewSession( /* If you don't have a certificate, input NULL */ myCertIdentity, /* maximum caches for this session */ 32, /* This session, TLS 1.0, 1.1 and 1.2 are supported */ TM_TLS_VERSION_10 | TM_TLS_VERSION_11 | TM_TLS_VERSION_12, 0); assert(sessionId != -1); /*Step 6. set socket option for th is connect socket */ value = 1; /* To indicate that this is SSL server */ errorCode = setsockopt (sockConn, IP_PROTOTCP, TM_TCP_SSL_CLIENT, (const char TM_FAR *) &value, sizeof (int)); assert(errorCode == TM_ENOERROR); /*This connect socket is going to use SSL session # sessionId */ value = sessionId; errorCode = setsockopt (sockConn, IP_PROTOTCP, TM_TCP_SSLSESSION, (const char TM_FAR *) &value, sizeof (int)); assert(errorCode == TM_ENOERROR); #endif /* TM_USE_SSL_CLIENT */ /*Step 7. Now we are able to call connect */ errorCode = connect(sockConn, (struct sockaddr TM_FAR*)&serverAddr, sizeof(struct sockaddr_storage)); assert(errorCode != TM_SOCKET_ERROR); #ifdef TM_USE_SSL_CLIENT /*Step 8. After TCP connection is established, we start SSL */ errorCode = tfSslClientUserStart(sockConn, "www.mytreck.com"); assert(errorCode == TM_ENOERROR); #endif /* TM_USE_SSL_CLIENT */ { recvLen = recv( sockConn, buffer, BUFFER_SIZE, 0); sentLen = send( sockConn, buffer, recvLen, 0); ... } #ifdef TM_USE_SSL_CLIENT /*Step 9. User may explicitly flush the SSL send buffer */ sentLen = tfSslUserSendFlush(sockConn); /*Step 10. User may explicitly call connect close to close the SSL layer on sockConn */ errorCode = tfSslConnectUserClose(sockConn) #endif /* TM_USE_SSL_CLIENT */ /* If SSL is used, and user doesn't explicitly call Step 8 and Step 9, the tfClose call will implicitly call them */ tfClose(sockConn); /*Step 11. If sessionId is not used any more, close it */ tfSslSessionUserClose(sessionId); /*Step 12. If SSL is not used by any other applications, un -initialize it, i.e., free the SSL global variable */ tfSslUninitialize(); /*Step 13. If PKI is not used by any other applications, un -initialize it, i.e., free the PKI global variable */ tfPkiUninitialize(); return errorCode; }
Applications
Treck SSL can be used with other Treck products, such as HTTP server or FTP server/client, this may require a separate purchase. For more details please see the following sections
- Using SSL/TLS with the Treck FTP Client
- Using SSL/TLS with the Treck FTP Server
- Using SSL/TLS with the Treck SMTP Client
- Using SSL/TLS with the Treck Web Server
- Using SSL/TLS with the Treck TELNET Server
References
Please see Appendix E: Open Source Licensing Information.