SharkSSL™ Embedded SSL/TLS Stack
SharkSSL Examples

Many practical example programs are included in the SharkSSL source code release. All our examples emphasize establishing a secure connection with the peer side and implementing solutions for tiny devices (microcontrollers).

These example programs are categorized into two sections: client examples and server examples.

SharkSSL client examples

A typical scenario is for a client to authenticate the server by making sure the server's certificate is signed by a trusted source. All of the included client examples both validate the server's certificate and make sure the common name in the certificate matches the "server name" (domain name).

Client Examples

  • E-Mail (SMTP) Example: SMTP/SMTP-example.c - Send emails securely by using the included secure SMTP library.
  • M2M LED SharkMQ: m2m-led-SharkMQ.c - IoT example that uses the secure SMQ library SharkMQ for connecting to our SMQ cluster. The example lets you control LEDs in a device in realtime via a browser. See the Browser to Device LED Control using SMQ tutorial for details. See also the SharkMQ API documentation.
  • M2M LED JSON: m2m-led-json.c - IoT example that shows how to send and receive JSON IoT messages over a raw socket connection. See the JSON documentation for more information on using JSON for IoT communication. The example requires that you have installed our free JSON library in the root path.
  • SharkMQTT Chat Example: chat-SharkMQTT.c - implements a basic chat client by using the MQTT protocol and the SharkMQTT library. The example, by default, connects to an online MQTT broker we have setup. We usually have a machine chat client also connected to the online MQTT broker, and you may chat with this machine or start a second instance of the MQTT client. Our chat machine is a basic implementation of ELIZA the therapist.
  • AWS MQTT - shows how to connect to Amazon's AWS MQTT cloud. You must have an Amazon AWS account in order to use this example. Navigate to your AWS IoT console and register a new device (Register a thing). Take note of the AWS MQTT broker name, open AWS-SharkMQTT.c in an editor, navigate to the line where you find #define AWS_IOT_MQTT_HOST "", and paste the broker name into the name string. Follow the instructions for creating a certificate for the device. On the "Certificate created" page, chose Download for the certificate, private key, and the root CA for AWS IoT. Name these files aws-certificate.pem, aws-private.pem.key, and aws-iot-rootCA.crt. Copy these three files to the directory where you have the example executable. Run the example. You may alternatively embed the certificate, key, and root CA in the executable. To embed the three files, run the two following command line programs as follows:
    SharkSslParseCert aws-certificate.pem aws-private.pem.key > aws-certificate.h
    SharkSSLParseCAList aws-iot-rootCA.crt > aws-iot-rootCA.h

SharkSslParseCert and SharkSSLParseCAList are command line tools included with SharkSSL. Compile the example with the macro EMBED_CERTIFICATES. This macro makes the example include the two generated C header files aws-certificate.h and aws-iot-rootCA.h.

  • WebSocket Echo Client: WsEchoClient.c - connects either to our online ELIZA the therapist WebSocket server (default) or to an online public WebSocket echo server. A #define in the example C code changes what server the client connects to. For the public echo WebSocket server mode, all data entered at the command line is sent to the server which in turn sends or (echoes) the data back to the client.
  • SSL Certificate Check: certcheck.c - a client example that shows how to validate several certificates returned by SSL enabled servers.
  • SSL Session Cache Test: sessioncache.c - connects to various servers twice and measures the time difference between non-cached and cached sessions. The first connection is not cached. The second connection uses the SSL session key from the first connection if the server supports this feature.

SharkSSL server examples

The following examples are designed for the Minnow Server. Refer to the online tutorial Creating Single-Page Apps with the Minnow Server for how to best design WebSocket server compatible applications.

  • WebSocket Chat Server: a basic chat example that echoes characters entered in the server's console window to the browser window and vice versa.
  • WebSocket LED Server: a Single Page Application (SPA) designed for controlling LEDs in a device. This example functions similar to the M2M LED SharkMQ example except for that you connect directly to the device from your browser instead of controlling the device via an online SMQ broker (proxy server).
  • Minnow Server Reference Platform: a more complete WebSocket example that follows the design guidelines in the tutorial Creating Single-Page Apps with the Minnow Server. The example may be downloaded from GitHub and used with the SharkSSL enabled Minnow Server included in the SharkSSL package.
  • SharkTrust: an example that shows how to automate certificate management by using SharkTrust. The example shows how to auto update and maintain a valid certificate for the Minnow Server.

Important information

All server examples include a certificate signed by Real Time Logic's root (CA) certificate. You will receive a browser warning if you do not install Real Time Logic's CA certificate in your browser/certificate store. An explanation on how to install a CA certificate is available online. We recommend reading our certificate management tutorial if you are new to certificates. The server examples only respond to HTTPS connections. You must make sure you enter your https://address:port in the browser when connecting to the server examples.

You may still get a browser SSL warning when connecting to the example server after installing the CA certificate in your browser if the examples are not used correctly. Not only does the browser validate that the certificate is from a trusted source; it also makes sure the certificate's "common name" matches the name entered in the browser's address bar. The common name for the WebSocket Chat Server is "localhost", and the common name for the WebSocket LED Server is "device". The WebSocket Chat Server must, for this reason, run on the same computer as the browser such that you connect to "localhost". The WebSocket LED Server requires an entry in your computer's hosts file so you can enter "device" as the name in the browser's address bar.

SharkSSL example libraries

SharkSSL includes a number of example libraries. These libraries include functionality such as WebSockets and SMTP. These libraries are fully functional, but are delivered as examples since they are not part of the SharkSSL core functionality.

SharkSSL Example Libraries

See the following SharkSSL product pages: SMTP library, WebSocket client library, and Minnow Server for an introduction to these products.

The following figure shows the relationship between the core SharkSSL library (red), the example libraries (blue), and the provided example programs (green).

SharkSSL example program features

Demonstration Attributes

The (example) libraries above include special features, which may easily go unnoticed without reading the references contained in this section.

  • Single Active User: The WebSocket Chat Server, WebSocket LED Server, and M2M-Chat Server examples are limited to one active user. You may modify these examples such that they will accept more than one active user.
  • Forced Browser Closure: The WebSocket Chat Server example and WebSocket LED Server example require that you close the current browser window before connecting a new window.
  • Multiple Connected Users: The M2M-LED and M2M-LED-JSON examples are designed to manage multiple connected users. A user is an active browser session that is controlling a device. The two examples include resource management on the server side to handle multiple users. You should try to connect at least two browser windows to one device, and watch both browser windows as you toggle an LED button in the (simulated) device or as you click on an LED in one of the browser Windows.
  • Browser Multiple Connection Conflict: The WebSocket Chat Server and WebSocket LED Server examples include dual HTTPS server/WebSocket server functionality. The web page and resource files are initially loaded using HTTPS via the Minnow Server library. JavaScript code in the browser is activated when all resources are loaded, and this JavaScript code initiates a persistent WebSocket connection with the server. The Minnow Server includes both a basic HTTPS server and WebSocket server. The basic HTTPS server is constructed to be as small as possible and can only handle one connection at a time. This creates a conflict with modern browsers that attempt to open multiple HTTPS connections when connecting to an HTTPS server. The connections will remain pending on the server side and most browsers will automatically time out and cause an initial delay before the WebSocket connection is established. The Minnow Server includes information on how this initial delay can be eliminated.

Tinkering with the examples

Client Side Modifications

The Certificate Management for IoT tutorial shows how to create your own Certificate Authority (CA) and how to sign certificates for the SharkSSL client examples by using the CA (root) certificate.

You can modify the client examples and connect to your own server. The server side code that manages the connections from all client examples can be downloaded and executed on your own computer. The Certificate Management for IoT tutorial shows you how to modify the client examples and how to install and operate your own server.

<em>Server Side Modifications</em>

Let's say you want to change the certificate in the WebSocket LED Server (WsLedServer.c) to your own certificate signed by your own Certificate Authority (CA). The below step-by-step instructions will use the Certificate management tool to illustrate the process for creating a complete new chain of trust:

Steps

  1. Download and install our Certificate Management Tool.
  2. Use the tool to create the CA certificate. We suggest that you initially create an RSA CA certificate.
  3. Install the CA certificate in your browser's certificate store. You can use the instructions we provide for our certificates, but remember to install your own CA certificate and not ours.
  4. Use the Certificate Management tool to create a certificate for the WebSocket LED Server. When you create your own certificates, you can use an IP address as the certificate's "common name"; thus you can use the IP address of the computer where the server will be running. You may also consider creating a Subject Alternative Name (SAN) certificate and use your computer's IP address and a name such as "device" as the alternative names. In this way, you can access the server securely without getting browser warnings by: (1) using the IP address, (2) using the name "device". For example, you can enter one of the following in your browser: https://192.168.1.100 or https://device.
  5. Add the certificate to the WebSocket LED server example.
  6. Compile and run the code.
  7. Navigate to the server by entering https://ip-address in the browser. You should not get any certificate warnings.

In step 5, we convert an X.509 certificate and key to the optimized SharkSSL format. This provides the appropriate APIs that allow you to load a standard X.509 certificate (or) the optimized SharkSSL certificate format. The LED server demo is using the optimized format, but you may change the example and use the SharkSSL APIs to allow a direct load of an X.509 certificate. The SharkSSL source code can be compiled without the X.509 processing code, thus saving memory in constrained devices. See certificate Management with sharkSSL for a detailed explanation.

Signing and Verifying Binaries

The following two examples, which are accompanied by our Securing Edge Nodes Whitepaper, show how to use RayCrypto for signing and verifying binaries such as firmware. The examples can be used as a base for creating secure boot.

Signing Binaries

The signature is typically performed on a host computer, such as Windows or Linux, as part of releasing new firmware. The following example shows how this can be done by creating a C program that runs on say Windows. The private key can be loaded dynamically from the file system, or the key can be embedded directly in the C program by converting the key from PEM format to the SharkSSL format by using the command line tool SharkSslParseKey. In the following example, the private key is embedded in the C program.

/* C data for 'private key' produced by SharkSslParseKey */
const U8 sharkSslPrivECKey256[104] =
{
0x30, 0x82, 0x00, 0x00, 0x02, 0x20, 0x17, 0x20,
0xF6, 0x9C, 0x88, 0x3D, 0x9C, 0x32, 0x41, 0xDE,
0x25, 0x34, 0xD9, 0x23, 0xDD, 0x71, 0x0E, 0xF2,
0x37, 0x83, 0xAE, 0xC6, 0xD5, 0xBF, 0xEA, 0x61,
0xC9, 0x81, 0xE5, 0x0F, 0x84, 0x83, 0xFA, 0x3F,
0x11, 0x23, 0xE8, 0xEA, 0x05, 0x14, 0x28, 0xE0,
0x37, 0xAC, 0xF3, 0x0E, 0x35, 0x58, 0x58, 0xA8,
0x16, 0x0B, 0x62, 0xEB, 0xEE, 0xC9, 0x06, 0x2F,
0x2A, 0xCF, 0x83, 0x1F, 0x93, 0x3C, 0xDF, 0x84,
0x04, 0xBF, 0x4E, 0x80, 0x5D, 0xA8, 0x0D, 0x15,
0xD7, 0x02, 0xAD, 0x8E, 0xD0, 0xFA, 0xE2, 0xB5,
0x69, 0x8C, 0x92, 0x00, 0xF5, 0xB6, 0xA8, 0x1C,
0x0D, 0x7F, 0x9E, 0x5C, 0x27, 0x93, 0x5C, 0x57
};
U8 dataChunk[256];
U8 sha256digest[SHARKSSL_SHA256_HASH_LEN];
U8 *signature;
U32 len;
U16 sl;
SharkSslSha256Ctx ctx; /* Hash engine */
/* Read firmware in chunks from local file system
and compute hash.
*/
while(readFirmwareChunkFromDisk(dataChunk,&len))
{
SharkSslSha256Ctx_append(&ctx, dataChunk, len);
}
/* All firmware data chunks read: Finish the hash calculation */
SharkSslSha256Ctx_finish(&ctx, sha256digest);
/* Determine the maximum length for the signature
in order to allocate memory for it.
*/
sl = sharkssl_ECDSA_siglen(sharkSslPrivECKey256);
signature = (U8*)malloc(sl);
/* Sign the hash using the private key */
(SharkSslECCKey) sharkSslPrivECKey256, /* ECC private key */
signature, &sl, /* out variables: signature and it's length */
sha256digest, /* Firmware fingerprint (hash) */
SHARKSSL_SHA256_HASH_LEN) == SHARKSSL_ECDSA_OK)
{
/* Success:
Attach the signature to the end of the firmware.
Variables to use: 'signature' and length 'sl'.
*/
}
free(signature);

Verifying Binaries

The following example shows how to perform the verification process in a device. Note that the public key is embedded in the C program and follows the same construction as the signing example above.

/* C data for 'private key' produced by SharkSslParseKey */
const U8 sharkSslPubECKey256[72] =
{
0x30, 0x82, 0x00, 0x00, 0x0A, 0x00, 0x17, 0x20,
0x11, 0x23, 0xE8, 0xEA, 0x05, 0x14, 0x28, 0xE0,
0x37, 0xAC, 0xF3, 0x0E, 0x35, 0x58, 0x58, 0xA8,
0x16, 0x0B, 0x62, 0xEB, 0xEE, 0xC9, 0x06, 0x2F,
0x2A, 0xCF, 0x83, 0x1F, 0x93, 0x3C, 0xDF, 0x84,
0x04, 0xBF, 0x4E, 0x80, 0x5D, 0xA8, 0x0D, 0x15,
0xD7, 0x02, 0xAD, 0x8E, 0xD0, 0xFA, 0xE2, 0xB5,
0x69, 0x8C, 0x92, 0x00, 0xF5, 0xB6, 0xA8, 0x1C,
0x0D, 0x7F, 0x9E, 0x5C, 0x27, 0x93, 0x5C, 0x57
};
U8 sha256digest[SHARKSSL_SHA256_HASH_LEN];
U8 *signature;
U32 len;
U16 sl;
SharkSslSha256Ctx ctx; /* Hash engine */
/* Calculate hash as firmware data trickles in via secure TCP/IP connection.
Note: Function receiveFirmwareChunk is assumed to stop at the end
of the firmware and just before the attached signature starts.
Error management is ignored in this example.
*/
while(receiveFirmwareChunk(dataChunk,&len))
{
SharkSslSha256Ctx_append(&ctx, dataChunk, len);
copyFirmwareChunk2FlashMemory(dataChunk, len);
}
/* All firmware data chunks read: Finish the hash calculation */
SharkSslSha256Ctx_finish(&ctx, sha256digest);
/* The following device specific function extracts the signature from
the TCP stream -- the binary data immediately following the firmware.
*/
signature = getSignatureFromStream(&sl);
/* Sign the computed digest 'sha256digest' and compare to the received
signature.
*/
(SharkSslECCKey) sharkSslPubECKey256, /* ECC public key */
signature, /* extracted from TCP stream */
sl, /* extracted signature length */
sha256digest, /* Computed digest calculated from received firmware */
SHARKSSL_SHA256_HASH_LEN) == SHARKSSL_ECDSA_OK)
{
/* Signature received matches computed signature. Activate new firmware */
}

Interfacing LED Demo Programs to Hardware

The SMQ LED demo and the Minnow Server LED demo require that you interface the example code to your development board.

The following code is extracted from the mbed platform example. The code example shows how the required interface functions are connected to the LEDS on an mbed board with four LEDS.

#include "mbed.h"
#include "ledctrl.h"
#include "EthernetInterface.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
static const LedInfo ledInfo[] = {
{
"LED 1",
LedColor_yellow,
1
},
{
"LED 2",
LedColor_red,
2
},
{
"LED 3",
LedColor_blue,
3
},
{
"LED 4",
LedColor_yellow,
4
}
};
static int leds[sizeof(ledInfo)/sizeof(ledInfo[1])];
/* Returns the LED on/off state for led with ID 'ledId'.
*/
int getLedState(int ledId)
{
baAssert(ledId >= 1 && ledId <= sizeof(ledInfo)/sizeof(ledInfo[1]));
return leds[ledId-1];
}
/*
Return an array of LedInfo (struct). Each element in the array
provides information for one LED. The 'len' argument must be set by
function getLedInfo. The out argument 'len' specifies the length of
the returned array, that is, number of LEDs in the device. Each LED
has a name, color, and ID. The ID, which provides information about
which LED to turn on/off, is used by control messages sent between
device code and UI clients. The IDs for a four LED device can for
example be 1,2,3,4.
*/
const LedInfo* getLedInfo(int* len)
{
*len = sizeof(ledInfo) / sizeof(ledInfo[0]);
return ledInfo;
}
/* Returns the name of this device. The name is presented by UI
clients such as browsers.
*/
const char* getDevName(void)
{
return "mbed";
}
static void blinkAll(int fast)
{
int i;
for(i = 1 ; i <= 4 ; i++) setLed(i, FALSE);
for(i = 1 ; i <= 4 ; i++)
{
setLed(i, TRUE);
wait_ms(fast ? 120: 400);
}
for(i = 1 ; i <= 4 ; i++)
{
setLed(i, FALSE);
wait_ms(fast ? 120: 400);
}
}
static void blink(int led)
{
int i;
for(i = 0 ; i < 30; i++)
{
setLed(led, 1);
wait_ms(120);
setLed(led, 0);
wait_ms(120);
}
}
/* Command sent by UI client to turn LED with ID on or off. This
function must set the LED to on if 'on' is TRUE and off if 'on' is FALSE.
*/
int setLed(int ledId, int on)
{
baAssert(ledId >= 1 && ledId <= sizeof(ledInfo)/sizeof(ledInfo[1]));
leds[ledId-1] = on;
on = on ? 0 : 1; /* Invert */
switch(ledId)
{
case 1: led1 = on; break;
case 2: led2 = on; break;
case 3: led3 = on; break;
case 4: led4 = on; break;
}
return 0;
}
/*
An optional function that enables LEDs to be set directly by the
device. This function is typically used by devices that include one
or more buttons. A button click may for example turn on a specific
LED. The function is called at intervals (polled) by the LED device
code. The function may for example detect a button click and return
the information to the caller. Arguments 'ledId' and 'on' are out
arguments, where 'ledId' is set to the LED ID and 'on' is set to
TRUE for on and FALSE for off. The function must return TRUE (a non
zero value) if the LED is to be set on/off and zero on no
change. Create an empty function returning zero if you do not plan
on implementing this feature.
*/
int setLedFromDevice(int* ledId, int* on)
{
return FALSE;
}
/*
The purpose with program status is to provide visible program
connection state information during startup. The function is typically
used to signal information via the LEDs. Simply create an empty
function if you do not want to set program status.
*/
void setProgramStatus(ProgramStatus s)
{
int i;
for(i = 1 ; i <= 4 ; i++) setLed(i, FALSE);
switch(s)
{
case ProgramStatus_Restarting:
blinkAll(FALSE);
case ProgramStatus_Starting:
blinkAll(TRUE);
break;
case ProgramStatus_Connecting:
setLed(1, TRUE);
break;
case ProgramStatus_SslHandshake:
setLed(2, TRUE);
break;
case ProgramStatus_DeviceReady:
for(i = 1 ; i <= 4 ; i++) setLed(i, TRUE);
wait(1);
for(i = 1 ; i <= 4 ; i++) setLed(i, FALSE);
break;
case ProgramStatus_CloseCommandReceived:
blink(3);
break;
default:
blinkAll(FALSE);
switch(s)
{
case ProgramStatus_SocketError:
case ProgramStatus_DnsError:
case ProgramStatus_WebServiceNotAvailError:
case ProgramStatus_InvalidCommandError:
case ProgramStatus_PongResponseError:
blink(1);
break;
case ProgramStatus_ConnectionError:
blink(2);
break;
case ProgramStatus_CertificateNotTrustedError:
case ProgramStatus_SslHandshakeError:
blink(3);
break;
case ProgramStatus_MemoryError:
for(i = 1 ; i <= 4 ; i++) blink(i);
break;
}
}
}
/* Required by SMQ examples.
The unique ID is used when calling the SMQ constructor.
The unique ID is typically set to the MAC address. See the SMQ
documentation for details:
https://realtimelogic.com/ba/doc/en/C/shark/structSharkMQ.html
If you do not have access to the MAC address or if the MAC address
is not unique (set by the manufacturer), you may compile the
example code with the macro GETUNIQUEID. This macro includes an
alternative implementation for function getUniqueId. See the LED
example code for more information (search for function
getUniqueId).
*/
int getUniqueId(const char** id)
{
*id=eth.getMACAddress();
return strlen(*id);
}
SHARKSSL_ECDSA_OK
@ SHARKSSL_ECDSA_OK
OK.
Definition: SharkSSL.h:2337
SharkSslSha256Ctx
SHA256.
Definition: SharkSslCrypto.h:97
sharkssl_ECDSA_verify_hash
SHARKSSL_API sharkssl_ECDSA_RetVal sharkssl_ECDSA_verify_hash(SharkSslECCKey pubkey, U8 *sig, U16 siglen, U8 *hash, U8 hashlen)
Verify a message using the ECC public key and a hash algorithm.
sharkssl_ECDSA_siglen
SHARKSSL_API U16 sharkssl_ECDSA_siglen(SharkSslECCKey privkey)
Returns the maximum length (in bytes) of a DER-encoded ECDSA signature generated with the private key...
SharkSslECCKey
U8 * SharkSslECCKey
Definition: SharkSSL.h:2189
sharkssl_ECDSA_sign_hash
SHARKSSL_API sharkssl_ECDSA_RetVal sharkssl_ECDSA_sign_hash(SharkSslECCKey privkey, U8 *sig, U16 *siglen, U8 *hash, U8 hashlen)
Generate the signature using the ECC private key and a hash.
SharkSslSha256Ctx_finish
SHARKSSL_API void SharkSslSha256Ctx_finish(SharkSslSha256Ctx *, U8 digest[SHARKSSL_SHA256_HASH_LEN])
finish
SharkSslSha256Ctx_constructor
SHARKSSL_API void SharkSslSha256Ctx_constructor(SharkSslSha256Ctx *ctx)
Initialize.
SharkSslSha256Ctx_append
SHARKSSL_API void SharkSslSha256Ctx_append(SharkSslSha256Ctx *, const U8 *data, U32 len)
append