Bringing SSL to Arduino on the Intel Galileo board through wolfSSL
A PDF version of this article, as well as a zip archive of the code samples, are available in the downloads section, below.
Contents
Introduction
Getting Started
Step 1: Building wolfSSL for Yocto
Step 2: Installing wolfSSL On Galileo
Step 3: Modifying the Compile Patterns for the Arduino IDE
Step 4: Installing the wolfSSL Build Files on the Arduino IDE System
Example Sketches
Notices
Downloads
Introduction
The Intel® Galileo development board is an Arduino*-certified development and prototyping board. Built on the Yocto 1.4 Poky Linux* release, Galileo merges an Arduino development environment with a complete Linux-based computer system allowing enthusiasts to incorporate Linux system calls and OS-provided services in their Ardunio sketches.
One long-standing limitation in the Arduino platform has been a lack of SSL support. Without SSL Arduino-based devices are incapable of securely transmitting data using HTTPS, and are thus forced to communicate insecurely using plain HTTP. In order to work around this limitation, devices that participate in the build out of the Internet of Things must rely on secondary devices which serve as bridges to the internet. The Arduino device communicates using HTTP to the bridge, which in turn communicates to the internet-based service using HTTPS.
This solution works well for devices that have a fixed network location, but it does require additional hardware and introduces a concentration point for multiple devices that itself may be vulnerable to attack. For mobile devices that may occasionally rely on public wireless networks, this approach can be entirely impractical. The best level of protection for connected devices is achieved with SSL support directly on the device itself.
On Galileo an Arduino sketch is just a C++ program that is cross-compiled into machine code and executed as a process that is managed by the operating system. That means that it has access to the same system resources as any other compiled program, and specifically that program can be linked against arbitrary, compiled libraries. The implication here is that adding SSL support is as simple as linking the Arduino sketch to an existing SSL library.
This paper examines two methods for adding SSL support to Arduino sketches running on Galileo via the wolfSSL library from wolfSSL, Inc.* (formerly named the CyaSSL library). The wolfSSL library is a lightweight SSL/TLS library that is designed for resource-constrained environments and embedded applications, and is distributed under the GPLv2 license.
Getting Started
This paper looks at two methods for linking the wolfSSL library to an Arduino sketch, but both of them follow the same basic steps:
1. Build wolfSSL for Yocto
2. Install the wolfSSL shared library onto your Galileo image
3. Modify the compile patterns for the Arduino IDE for Galileo
4. Install the wolfSSL build files onto the system hosting the Arduino IDE
This procedure is moderately complex and does require a firm grasp of the Linux environment, shell commands, software packages and software build procedures, as well as methods of transferring files to and from a Linux system. While this paper does go into some detail on specific Linux commands, it is not a step-by-step instruction manual and it assumes that the reader knows how to manipulate files on a Linux system.
These procedures should work on both Galileo and Galileo 2 boards.
Method 1: Dynamic linking
In the dynamic linking method the Arduino sketch is dynamically linked with the shared object library, libwolfssl.so. This method is the easiest to program for since the sketch just calls the library functions directly.
There are disadvantages to this approach, however:
- The Arduino IDE for Galileo uses a single configuration for compiling all sketches, so the linker will put a reference to libwolfssl.so in the resulting executable whether or not it’s needed by a sketch. This is not a problem if the target Galileo system has the wolfSSL library installed on it, but if any sketch is compiled for another system that does not have the library then those sketches will not execute.
- The system hosting the Arduino IDE for Galileo must have the cross-compiled wolfSSL library installed into the Arduino IDE build tree.
Method 2: Dynamic loading
In the dynamic loading method the Arduino sketch is linked with the dynamic linking loader library, libdl. The wolfSSL library and its symbols are loaded dynamically during execution using dlopen() and dlsym(). This method is more tedious to program for since the function names cannot be resolved directly by the linker and must be explicitly loaded by the code and saved as function pointers.
The advantages over the dynamic linking method are:
- libdl is part of the Galileo SD card image, so arbitrary sketches compiled by the modified IDE will still run on other Galileo systems.
- The system hosting the Arduino IDE for Galileo only needs to have the wolfSSL header files installed into the build tree.
- Any dynamic library is available to the Arduino sketch with just this single modification.
Step 1: Building wolfSSL for Yocto
The first step in bringing SSL support to the Arduino environment is to build the wolfSSL library for Yocto using uClibc as the C library. This is accomplished using the cross compiler that is bundled with Intel’s Arduino IDE for Linux. This step must be performed on a Linux system.
There have been multiple releases of the IDE since the original Galileo release and any of them will do, but because path names have changed from release to release this document assumes that you will be using the latest build as of this writing, which is the Intel bundle version 1.0.4 with Arduino IDE version 1.6.0.
Choose the 32-bit or 64-bit archive, whichever is correct for your Linux distribution.
Configuring the cross-compiler
If you have already used this version of the IDE to build sketches for your Galileo device then it has already been configured properly and you can skip this task.
If you have not built a sketch with it yet, then you will need to run the installation script in order to correctly set the path names in the package configuration files. This script, install_script.sh, is located in the hardware/tools/i586 directory inside the root of your IDE package. Run it with no arguments:
~/galileo/arduino-1.6.0+Intel/hardware/tools/i586$ ./install_script.sh
Setting it up…/tmp/tmp.7FGQfwEaNz/relocate_sdk.sh /nfs/common/galileo/arduino-1.6.0+Intel/hardware/tools/i586/relocate_sdk.sh
link:/nfs/common/galileo/arduino-1.6.0+Intel/hardware/tools/i586/sysroots/x86_64-pokysdk-linux/lib/ld-linux-x86-64.so.2
link:/nfs/common/galileo/arduino-1.6.0+Intel/hardware/tools/i586/sysroots/x86_64-pokysdk-linux/lib/libpthread.so.0
link:/nfs/common/galileo/arduino-1.6.0+Intel/hardware/tools/i586/sysroots/x86_64-pokysdk-linux/lib/libnss_compat.so.2
link:/nfs/common/galileo/arduino-1.6.0+Intel/hardware/tools/i586/sysroots/x86_64-pokysdk-linux/lib/librt.so.1
link:/nfs/common/galileo/arduino-
1.6.0+Intel/hardware/tools/i586/sysroots/x86_64-pokysdk-linux/lib/libresolv.so.2
…
SDK has been successfully set up and is ready to be used.
The cross-compiler is now ready for use.
Downloading the wolfSSL source
To build the wolfSSL library for Galileo you need to download the source code from wolfSSL, Inc. As of this writing, the latest version is 3.4.0 and is distributed as a Zip archive. Unzip the source into a directory of your choosing.
Building the library
In order to build the library, you must first set up your shell environment to reference the cross compiler. The environment setup files assume a Bourne shell environment so you must perform these steps in an appropriate and compatible shell such as sh or bash. Starting from a clean shell environment is strongly recommended.
First, source the environment setup file from the Intel Arduino IDE. Be sure to use the path to your Intel Arduino IDE instead of the path given in the example:
~/src/wolfssl-3.4.0$ . ~/galileo/arduino-1.6.0+Intel/hardware/tools/i586/environment-setup-i586-poky-linux-uclibc
This step will not generate any output.
number of options in order to properly initialize it for a cross compile.
~/src/wolfssl-3.4.0$ ./configure –prefix=$HOME/wolfssl –host=i586-poky-linux-uclibc \
–target=i586-poky-linux-uclibc
Note that you must supply absolute paths to the configure script, and cannot use ~ as a shortcut for your home directory. Use the $HOME shell variable instead.
The –prefix option tells build system where to install the library. Since you won’t actually be installing the library on this system, any directory will do. This example shows it going in $HOME/wolfssl.
The –host and –target options tell the build system that this will be a cross-compile, targeting the architecture identified as i586-poky-linux-uclibc.
The configure script will generate a lot of output. When it finishes, assuming there are no errors, you can build the software using “make”.
~/src/wolfssl-3.4.0$ make
make[1]: Entering directory `/nfs/users/johnm/src/wolfssl-3.4.0'
CC wolfcrypt/test/testsuite_testsuite_test-test.o
CC examples/client/testsuite_testsuite_test-client.o
CC examples/server/testsuite_testsuite_test-server.o
CC examples/client/tests_unit_test-client.o
CC examples/server/tests_unit_test-server.o
CC wolfcrypt/src/src_libwolfssl_la-hmac.lo
CC wolfcrypt/src/src_libwolfssl_la-random.lo
…
CCLD examples/client/client
CCLD examples/echoserver/echoserver
CCLD testsuite/testsuite.test
CCLD tests/unit.test
make[1]: Leaving directory `/nfs/users/johnm/src/wolfssl-3.4.0'
And then install it to the local/temporary location via “make install”:
~/src/wolfssl-3.4.0$ make install
Your library will now be in the directory you specified to the –prefix option of configure, in the lib subdirectory:
~/src/wolfssl-3.4.0$ cd $HOME/wolfssl/lib
~/wolfssl/lib$ ls -CFs
total 188
4 libwolfssl.la* 0 libwolfssl.so.0@ 4 pkgconfig/
0 libwolfssl.so@ 180 libwolfssl.so.0.0.0*
You’re now ready to install the wolfSSL library onto Galileo.
Step 2: Installing wolfSSL On Galileo
There are two general approaches for installing the wolfSSL package onto Galileo: the first is to copy the files directly to the Galileo filesystem image, and the second is to copy the files onto a running Galileo system over a network connection. In either case, however, you do need to know which image you are running on your system, the SD-Card Linux image, or the IoT Developer Kit image.
For Galileo running the SD-Card Linux image
The SD-Card Linux image is the original system image for Galileo boards. It is a very minimal system image which is less than 312 MB in size. It lacks development tools (e.g., there is no compiler) and advanced Linux utilities. As of this writing, the latest version of the SD-Card image is 1.0.4.
Both installation methods are discussed below, but installing directly to the Galileo filesystem image is preferred because you have more powerful utilities at your disposal.
Installing wolfSSL to the filesystem image
This method is easier and less error-prone than the other since you have file synchronization tools available to you, and you don’t have the added complexities of networking. All that is necessary is to mount the Galileo filesystem image as a filesystem on the build machine and then you can use rsync to copy the wolfSSL package into place. You can either copy this file to your build system, or mount the microSD card with the image directly on your Linux system using a card reader.
In the Galileo SD Card file system tree, the main Galileo filesystem image is called image-full-galileo-clanton.ext3 and it can be mounted using the loop device. Create a mount point (directory) on your build system—the example below uses /mnt/galileo—and then use the mount command to mount it:
~/wolfssl$ cd /mnt
/mnt$ sudo mkdir galileo
/mnt$ mount –t ext3 –o loop /path/to/image-full-galileo-clanton.ext3 /mnt/galileo
The Galileo filesystem should now be visible as /mnt/galileo.
Use rsync to copy the shared library and its symlinks into place. They should be installed into /usr/lib on your Galileo system:
/mnt$ rsync –a $HOME/wolfssl/lib/lib* /mnt/galileo/usr/lib
Be sure to replace $HOME/wolfSSL with the actual location of your local wolfSSL build.
Installing wolfSSL over the network
For this method, the Galileo system must be up and running with an active network connection and you will need to know its IP address. Because Galileo lacks file synchronization utilities such as rsync, files will have to be copied using tar to ensure that symbolic links are handled correctly.
First, use cd to switch to the lib subdirectory of your local wolfSSL build.
~/wolfssl$ cd $HOME/wolfssl/lib
Now use tar to create an archive of the shared library and its symlinks, and the copy it to Galileo with scp.
~/wolfssl/lib$ tar cf /tmp/wolfssl.tar lib*
~/wolfssl/lib$ cd /tmp
/tmp$ scp wolfssl.tar root@192.168.1.2:/tmp
root@192.168.1.2’s password:
Be sure to enter the IP address of your Galileo instead of the example.
Now log in to your Galileo device and untar the archive:
/tmp$ ssh root@192.168.1.2
root@192.168.1.2’s password:
root@clanton:~# cd /usr/lib
root@clanton:/usr/lib# tar xf /tmp/wolfssl.tar
For Galileo running the IoT Developer Kit image
The IoT Developer Kit image is a much larger and more traditional Linux system image which includes developer tools and many useful system utilities and daemons. It is distributed as a raw disk image which includes both FAT32 and ext3 disk partitions, and it must be direct-written to an SD card.
Both installation methods are discussed below.
As of this writing, you also need to replace the uClibc library on your Developer Kit image with the one bundled with your Intel Arduino IDE. Due to differences in the build procedure used for these two copies of the library, not all of the symbols that are exported in the IDE version are present in the Developer Kit version and that can lead to runtime crashes of Arduino sketches. The wolfSSL library, in particular, introduces a dependency on one of these symbols that is missing from the Developer Kit’s build of uClibc, and if you do not replace the library on the Galileo system attempts to use libwolfssl will fail.
Installing wolfSSL to the filesystem image
This method is easiest if you connect an SD card reader to your Linux system. Since the Developer Kit image contains an ext3 partition, most Linux distributions will automatically mount it for you, typically under /media or /mnt. Use the df command with the -T option to help you determine the mount point.
~$ df -T | grep ext3
/dev/sde2 ext3 991896 768032 172664 82% /media/johnm/048ce1b1-be13-4a5d-8352-2df03c0d9ed8
In this case, the mount point is /media/johnm/048ce1b1-be13-4a5d-8352-2df03c0d9ed8:
~$ /bin/ls -CFs /media/johnm/048ce1b1-be13-4a5d-8352-2df03c0d9ed8
total 96
4 bin/ 4 home/ 4 media/ 4 proc/ 4 sys/ 4 www/
4 boot/ 4 lib/ 4 mnt/ 4 run/ 4 tmp/
4 dev/ 4 lib32/ 4 node_app_slot/ 4 sbin/ 4 usr/
4 etc/ 16 lost+found/ 4 opt/ 4 sketch/ 4 var/
The libraries used by Arduino sketches are kept in /lib32. Use cd to change to that directory and copy the wolfSSL shared libraries and their symlinks into this directory using rsync in order to preserve the symbolic links.
~/wolfssl$ cd /path-to-mountpoint/lib32
lib32$ rsync –a $HOME/wolfssl/lib/lib* .
Be sure to replace path-to-mountpoint with the actual mount point for your SD card’s Galileo filesystem.
Now, you need to replace the Developer Kit’s uClibc library with the one from your Intel Arduino IDE package. Instead of removing it or overwriting it, the following procedure will simply rename it, effectively disabling the original copy of the library but without permanently deleting it:
lib32$ mv libuClibc-0.9.34-git.so libuClibc-0.9.34-git.so.dist
lib32$ cp ~/galileo/arduino-1.6.0+Intel/hardware/tools/i586/sysroots/i586-poky-linux-uclibc/lib/libuClibc-0.9.34-git.so .
Remember to use your actual path to your Intel Arduino IDE in place of the example one.
Installing wolfSSL over the network
For this method, the Galileo system must be up and running with an active network connection and you will need to know its IP address. Because Galileo lacks file synchronization utilities such as rsync, files will have to be copied using tar to ensure that symbolic links are handled correctly.
First, use cd to switch to the lib subdirectory of your local wolfSSL build.
Now use tar to create an archive of the shared library and its symlinks, and the copy it to Galileo with scp.
~/wolfssl/lib$ tar cf /tmp/wolfssl.tar lib*
~/wolfssl/lib$ cd /tmp
/tmp$ scp wolfssl.tar root@192.168.1.2:/tmp
root@192.168.1.2’s password:
Be sure to enter the IP address of your Galileo instead of the example.
Now log in to your Galileo device and untar the archive:
/tmp$ ssh root@192.168.1.2
root@192.168.1.2’s password:
root@quark:~# cd /lib32
root@quark:/lib32# tar xf /tmp/wolfssl.tar
Next, you need to replace the Developer Kit’s uClibc library with the one from your Intel Arduino IDE package. Instead of removing it or overwriting it, the following procedure will simply rename it, effectively disabling the original copy of the library but without permanently deleting it (this will also prevent the actively running sketch from crashing):
root@quark:/lib32$ mv libuClibc-0.9.34-git.so libuClibc-0.9.34-git.so.dist
Log out of your Galileo system and use scp to copy the library from your Intel Arduino IDE to your Galileo:
~$ scp ~/galileo/arduino-1.6.0+Intel/hardware/tools/i586/sysroots/i586-poky-linux-uclibc/lib/libuClibc-0.9.34-git.so root@192.168.1.2:/lib32
Remember to use your actual path to your Intel Arduino IDE in place of the example one, and your Galileo’s IP address.
Step 3: Modifying the Compile Patterns for the Arduino IDE
To compile sketches that want to use the wolfSSL library you need to modify the compile patterns for the Arduino IDE for Galileo. The specific modification that is necessary depends on the method you have chosen for linking to libwolfssl, but no matter the method compile patters live inside of hardware/intel/i586-uclibc for the Intel 1.0.4 with Arduino IDE 1.5.3 and later.
Modifying the compile patterns
The file that holds your compile patterns is named platform.txt.
You will be editing the line “recipe.c.combine.pattern”, which looks similar to this:
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -march={build.mcu} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm -lpthread
Dynamic linking
If you are using the dynamic linking method, then you need to tell the linker to add libwolfssl to the list of libraries when linking the executable. Add -lwolfssl to the end of the line.
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -march={build.mcu} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm –lpthread -lwolfssl
Be sure not to add any line breaks.
Dynamic loading
In the dynamic loading method, you need to tell the linker to add the dynamic loader library to the list of libraries. Add -ldl to the end of the line.
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}"
{compiler.c.elf.flags} -march={build.mcu} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm -ldl
Be sure not to add any line breaks.
Step 4: Installing the wolfSSL Build Files on the Arduino IDE System
The last step before you can compile sketches is to install the wolfSSL build files into the Arduino IDE for Galileo build tree. For the 1.6.0 release, the build tree is in hardware/tools/i586/i586-poky-linux-uclibc. In there you will find a UNIX-like directory structure containing directories etc, lib, usr, and var.
Installing the wolfSSL header files
Whether you are using the dynamic loading or dynamic linking method you will need to have the wolfSSL header files installed where the Arduino IDE can find them so that you can include them in your sketches with:
#include <wolfssl/ssl.h>
You can find the header files in the local installation of wolfSSL that you created in Step 1, in include subdirectory. For backwards compatability reasons, the wolfSSL distribution includes header files in include/cyassl and include/wolfssl.
The wolfSSL header files must but installed into usr/include:
Installing the wolfSSL libraries
If you are using the dynamic linking method, then you must also install the cross-compiled libraries into usr/lib. You can skip this step if you are using the dynamic loading method.
The libraries are in the local installation that was created in Step 1, inside the lib directory. From there copy:
libwolfssl.la
libwolfssl.so
libwolfssl.so.*
All but one of the shared object files will be symlinks, but it is okay for them to be copied as just regular files.
Example Sketches
The following example sketches show how to interact with the wolfSSL library using both the dynamic linking and dynamic loading methods. They perform the same function: connect to a target web server and fetch a web page using SSL. The page source is printed to the Arduino IDE for Galileo’s serial console.
These sketches are licensed under the Intel Sample Source Code license. In addition to browsing the source here, you can download them directly.
Note: Be sure to change the server name and, if necessary, the page URL to fetch.
Dynamic linking example
001 /*
002 Copyright 2015 Intel Corporation All Rights Reserved.
003
004 The source code, information and material ("Material") contained herein is owned
005 by Intel Corporation or its suppliers or licensors, and title to such Material
006 remains with Intel Corporation or its suppliers or licensors. The Material
007 contains proprietary information of Intel or its suppliers and licensors. The
008 Material is protected by worldwide copyright laws and treaty provisions. No part
009 of the Material may be used, copied, reproduced, modified, published, uploaded,
010 posted, transmitted, distributed or disclosed in any way without Intel's prior
011 express written permission. No license under any patent, copyright or other
012 intellectual property rights in the Material is granted to or conferred upon
013 you, either expressly, by implication, inducement, estoppel or otherwise. Any
014 license under such intellectual property rights must be express and approved by
015 Intel in writing.
016
017 Include any supplier copyright notices as supplier requires Intel to use.
018
019 Include supplier trademarks or logos as supplier requires Intel to use,
020 preceded by an asterisk. An asterisked footnote can be added as follows: *Third
021 Party trademarks are the property of their respective owners.
022
023 Unless otherwise agreed by Intel in writing, you may not remove or alter this
024 notice or any other notice embedded in Materials by Intel or Intel's suppliers
025 or licensors in any way.
026 */
027
028 #include <LiquidCrystal.h>
029 #include <dlfcn.h>
030 #include <wolfssl/ssl.h>
031 #include <Ethernet.h>
032 #include <string.h>
033
034 const char server[]= "www.example.com"; // Set this to a web server of your choice
035 const char req[]= "GET / HTTP/1.0\r\n\r\n"; // Get the root page
036
037 int repeat;
038
039 int wolfssl_init ();
040 int client_send (WOLFSSL *, char *, int, void *);
041 int client_recv (WOLFSSL *, char *, int, void *);
042
043 LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
044 void *handle;
045
046 EthernetClient client;
047
048
049 WOLFSSL_CTX *ctx= NULL;
050 WOLFSSL *ssl= NULL;
051 WOLFSSL_METHOD *method= NULL;
052
053 void setup() {
054 Serial.begin(9600);
055 Serial.println("Initializing");
056
057 lcd.begin(16,2);
058 lcd.clear();
059
060 if ( wolfssl_init() == 0 ) goto fail;
061
062 Serial.println("OK");
063
064 // Set the repeat count to a maximum of 5 times so that we aren't
065 // fetching the same URL over and over forever.
066
067 repeat= 5;
068 return;
069
070 fail:
071 Serial.print("wolfSSL setup failed");
072 repeat= 0;
073 }
074
075 int wolfssl_init ()
076 {
077 char err[17];
078
079 // Create our SSL context
080
081 method= wolfTLSv1_2_client_method();
082 ctx= wolfSSL_CTX_new(method);
083 if ( ctx == NULL ) return 0;
084
085 // Don't do certification verification
086 wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
087
088 // Specify callbacks for reading to/writing from the socket (EthernetClient
089 // object).
090
091 wolfSSL_SetIORecv(ctx, client_recv);
092 wolfSSL_SetIOSend(ctx, client_send);
093
094 return 1;
095 }
096
097 int client_recv (WOLFSSL *_ssl, char *buf, int sz, void *_ctx)
098 {
099 int i= 0;
100
101 // Read a byte while one is available, and while our buffer isn't full.
102
103 while ( client.available() > 0 && i < sz) {
104 buf[i++]= client.read();
105 }
106
107 return i;
108 }
109
110 int client_send (WOLFSSL *_ssl, char *buf, int sz, void *_ctx)
111 {
112 int n= client.write((byte *) buf, sz);
113 return n;
114 }
115
116 void loop() {
117 char errstr[81];
118 char buf[256];
119 int err;
120
121 // Repeat until the repeat count is 0.
122
123 if (repeat) {
124 if ( client.connect(server, 443) ) {
125 int bwritten, bread, totread;
126
127 Serial.print("Connected to ");
128 Serial.println(server);
129
130 ssl= wolfSSL_new(ctx);
131 if ( ssl == NULL ) {
132 err= wolfSSL_get_error(ssl, 0);
133
wolfSSL_ERR_error_string_n(err, errstr, 80);
134
Serial.print("wolfSSL_new: ");
135
Serial.println(errstr);
136
}
137
138
Serial.println(req);
139
bwritten= wolfSSL_write(ssl, (char *) req, strlen(req));
140
Serial.print("Bytes written= ");
141
Serial.println(bwritten);
142
143
if ( bwritten > 0 ) {
144
totread= 0;
145
146
while ( client.available() || wolfSSL_pending(ssl) ) {
147
bread= wolfSSL_read(ssl, buf, sizeof(buf)-1);
148
totread+= bread;
149
150
if ( bread > 0 ) {
151
buf[bread]= '\0';
152
Serial.print(buf);
153
} else {
154
Serial.println();
155
Serial.println("Read error");
156
}
157
}
158
159
Serial.print("Bytes read= ");
160
Serial.println(bread);
161
}
162
163
if ( ssl != NULL ) wolfSSL_free(ssl);
164
165
client.stop();
166
Serial.println("Connection closed");
167
}
168
169
–repeat;
170
}
171
172
// Be polite by sleeping between iterations
173
174
delay(5000);
175
}
Dynamic loading example
view sourceprint?
001 /*
002 Copyright 2015 Intel Corporation All Rights Reserved.
003
004 The source code, information and material ("Material") contained herein is owned
005 by Intel Corporation or its suppliers or licensors, and title to such Material
006 remains with Intel Corporation or its suppliers or licensors. The Material
007 contains proprietary information of Intel or its suppliers and licensors. The
008 Material is protected by worldwide copyright laws and treaty provisions. No part
009 of the Material may be used, copied, reproduced, modified, published, uploaded,
010 posted, transmitted, distributed or disclosed in any way without Intel's prior
011 express written permission. No license under any patent, copyright or other
012 intellectual property rights in the Material is granted to or conferred upon
013 you, either expressly, by implication, inducement, estoppel or otherwise. Any
014 license under such intellectual property rights must be express and approved by
015 Intel in writing.
016
017 Include any supplier copyright notices as supplier requires Intel to use.
018
019 Include supplier trademarks or logos as supplier requires Intel to use,
020 preceded by an asterisk. An asterisked footnote can be added as follows: *Third
021 Party trademarks are the property of their respective owners.
022
023 Unless otherwise agreed by Intel in writing, you may not remove or alter this
024 notice or any other notice embedded in Materials by Intel or Intel's suppliers
025 or licensors in any way.
026 */
027
028 #include <dlfcn.h>
029 #include <wolfssl/ssl.h>
030 #include <Ethernet.h>
031 #include <string.h>
032
033 /*
034 Set this to the location of your wolfssl shared library. By default you
035 shouldn't need to specify a path unless you put it somewhere other than
036
/usr/lib (SD-Card image) or /lib32 (IoT Developer Kit image).
037
*/
038 #define WOLFSSL_SHLIB_PATH "libwolfssl.so"
039
040 const char server[]= "www.example.com"; // Set this to a web server of your choice
041 const char req[]= "GET / HTTP/1.0\r\n\r\n"; // Get the root page
042 int repeat;
043
044 int wolfssl_dlload ();
045 int wolfssl_init ();
046 int client_send (WOLFSSL *, char *, int, void *);
047 int client_recv (WOLFSSL *, char *, int, void *);
048
049 void *handle;
050
051 EthernetClient client;
052
053
054 WOLFSSL_CTX *ctx= NULL;
055 WOLFSSL *ssl= NULL;
056 WOLFSSL_METHOD *method= NULL;
057
058 typedef struct wolfssl_handle_struct {
059 WOLFSSL_METHOD *(*wolfTLSv1_2_client_method)();
060
WOLFSSL_CTX *(*wolfSSL_CTX_new)(WOLFSSL_METHOD *);
061 void (*wolfSSL_CTX_set_verify)(WOLFSSL_CTX *, int , VerifyCallback);
062 int (*wolfSSL_connect)(WOLFSSL *);
063
int (*wolfSSL_shutdown)(WOLFSSL *);
064int (*wolfSSL_get_error)(WOLFSSL *, int);
065 void (*wolfSSL_ERR_error_string_n)(unsigned long, char *, unsigned long);
066 WOLFSSL *(*wolfSSL_new)(WOLFSSL_CTX *);
067 void (*wolfSSL_free)(WOLFSSL *);
068 void (*wolfSSL_SetIORecv)(WOLFSSL_CTX *, CallbackIORecv);
069 void (*wolfSSL_SetIOSend)(WOLFSSL_CTX *, CallbackIORecv);
070 int (*wolfSSL_read)(WOLFSSL *, void *, int);
071 int (*wolfSSL_write)(WOLFSSL *, void *, int);
072 int (*wolfSSL_pending)(WOLFSSL *);
073 } wolfssl_t;
074
075 wolfssl_t wolf;
076
077 void setup() {
078
Serial.begin(9600);
079 Serial.println("Initializing");
080
081 if ( wolfssl_dlload() == 0 ) goto fail;
082 if ( wolfssl_init() == 0 ) goto fail;
083
084 // Set the repeat count to a maximum of 5 times so that we aren't
085 // fetching the same URL over and over forever.
086
087 repeat= 5;
088 return;
089
090 fail:
091 Serial.print("wolfSSL setup failed");
092 repeat= 0;
093 }
094
095 int wolfssl_init ()
096 {
097 char err[17];
098
099 // Create our SSL context
100
101 method= wolf.wolfTLSv1_2_client_method();
102 ctx= wolf.wolfSSL_CTX_new(method);
103 if ( ctx == NULL ) return 0;
104
105 // Don't do certification verification
106 wolf.wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
107
108 // Specify callbacks for reading to/writing from the socket (EthernetClient
109 // object).
110
111 wolf.wolfSSL_SetIORecv(ctx, client_recv);
112 wolf.wolfSSL_SetIOSend(ctx, client_send);
113
114 return 1;
115 }
116
117
118 {
119 // Dynamically load our symbols from libwolfssl.so
120
121 char *err;
122
123 // goto is useful for constructs like this, where we need everything to succeed or
124 // it's an overall failure and we abort. If just one of these fails, print an error
125 // message and return 0.
126
127 handle= dlopen(WOLFSSL_SHLIB_PATH, RTLD_NOW);
128 if ( handle == NULL ) {
129 err= dlerror();
130 goto fail;
131 }
132
133 wolf.wolfTLSv1_2_client_method= (WOLFSSL_METHOD *(*)()) dlsym(handle, "wolfTLSv1_2_client_method");
134 if ( (err= dlerror()) != NULL ) goto fail;
135
136 wolf.wolfSSL_CTX_new= (WOLFSSL_CTX *(*)(WOLFSSL_METHOD *)) dlsym(handle, "wolfSSL_CTX_new");
137 if ( (err= dlerror()) != NULL ) goto fail;
138
139 wolf.wolfSSL_CTX_set_verify= (void (*)(WOLFSSL_CTX* , int , VerifyCallback)) dlsym(handle, "wolfSSL_CTX_set_verify");
140 if ( (err= dlerror()) != NULL ) goto fail;
141
142 wolf.wolfSSL_connect= (int (*)(WOLFSSL *)) dlsym(handle, "wolfSSL_connect");
143 if ( (err= dlerror()) != NULL ) goto fail;
144
145 wolf.wolfSSL_get_error= (int (*)(WOLFSSL *, int)) dlsym(handle, "wolfSSL_get_error");
146 if ( (err= dlerror()) != NULL ) goto fail;
147
148 wolf.wolfSSL_ERR_error_string_n= (void (*)(unsigned long, char *, unsigned long)) dlsym(handle, "wolfSSL_ERR_error_string_n");
149 if ( (err= dlerror()) != NULL ) goto fail;
150
151 wolf.wolfSSL_new= (WOLFSSL *(*)(WOLFSSL_CTX *)) dlsym(handle, "wolfSSL_new");
152 if ( (err= dlerror()) != NULL ) goto fail;
153
154 wolf.wolfSSL_free= (void (*)(WOLFSSL *)) dlsym(handle, "wolfSSL_free");
155 if ( (err= dlerror()) != NULL ) goto fail;
156
157 wolf.wolfSSL_SetIORecv= (void (*)(WOLFSSL_CTX *, CallbackIORecv)) dlsym(handle, "wolfSSL_SetIORecv");
158 if ( (err= dlerror()) != NULL ) goto fail;
159
160 wolf.wolfSSL_SetIOSend= (void (*)(WOLFSSL_CTX *, CallbackIORecv)) dlsym(handle, "wolfSSL_SetIOSend");
161 if ( (err= dlerror()) != NULL ) goto fail;
162
163 wolf.wolfSSL_read= (int (*)(WOLFSSL *, void *, int)) dlsym(handle, "wolfSSL_read");
164 if ( (err= dlerror()) != NULL ) goto fail;
165
166 wolf.wolfSSL_write= (int (*)(WOLFSSL *, void *, int)) dlsym(handle, "wolfSSL_write");
167 if ( (err= dlerror()) != NULL ) goto fail;
168
169 wolf.wolfSSL_pending= (int (*)(WOLFSSL *)) dlsym(handle, "wolfSSL_pending");
170 if ( (err= dlerror()) != NULL ) goto fail;
171
172 Serial.println("OK");
173
174
return 1;
175
176 fail:
177 Serial.println(err);
178 return 0;
179}
180
181 int client_recv (WOLFSSL *_ssl, char *buf, int sz, void *_ctx)
182{
183 int i= 0;
184
185 // Read a byte while one is available, and while our buffer isn't full.
186
187 while ( client.available() > 0 && i < sz) {
188 buf[i++]= client.read();
189 }
190
191 return i;
192}
193
194 int client_send (WOLFSSL *_ssl, char *buf, int sz, void *_ctx)
195 {
196 int n= client.write((byte *) buf, sz);
197 return n;
198 }
199
200 void loop() {
201 char errstr[81];
202 char buf[256];
203 int err;
204
205 // Repeat until the repeat count is 0.
206
207 if (repeat) {
208 if ( client.connect(server, 443) ) {
209 int bwritten, bread, totread;
210
211 Serial.print("Connected to ");
212 Serial.println(server);
213
214 ssl= wolf.wolfSSL_new(ctx);
215 if ( ssl == NULL ) {
216 err= wolf.wolfSSL_get_error(ssl, 0);
217 wolf.wolfSSL_ERR_error_string_n(err, errstr, 80);
218 Serial.print("wolfSSL_new: ");
219 Serial.println(errstr);
220 }
221
222 Serial.println(req);
223 bwritten= wolf.wolfSSL_write(ssl, (char *) req, strlen(req));
224 Serial.print("Bytes written= ");
225 Serial.println(bwritten);
226
227 if ( bwritten > 0 ) {
228 totread= 0;
229
230 while ( client.available() || wolf.wolfSSL_pending(ssl) ) {
231bread= wolf.wolfSSL_read(ssl, buf, sizeof(buf)-1);
232 totread+= bread;
233
234 if ( bread > 0 ) {
235 buf[bread]= '\0';
236 Serial.print(buf);
237 } else {
238 Serial.println();
239 Serial.println("Read error");
240 }
241 }
242
243
Serial.print("Bytes read= ");
244 Serial.println(totread);
245 }
246
247if ( ssl != NULL ) wolf.wolfSSL_free(ssl);
248
249 client.stop();
250 Serial.println("Connection closed");
251 }
252
253 –repeat;
254 }
255
256 // Be polite by sleeping between iterations
257
258 delay(5000);
259 }
Notices
INFORMATION IN THIS DOCUMENT IS PROVIDED IN CONNECTION WITH INTEL PRODUCTS. NO LICENSE, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, TO ANY INTELLECTUAL PROPERTY RIGHTS IS GRANTED BY THIS DOCUMENT. EXCEPT AS PROVIDED IN INTEL'S TERMS AND CONDITIONS OF SALE FOR SUCH PRODUCTS, INTEL ASSUMES NO LIABILITY WHATSOEVER AND INTEL DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY, RELATING TO SALE AND/OR USE OF INTEL PRODUCTS INCLUDING LIABILITY OR WARRANTIES RELATING TO FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR INFRINGEMENT OF ANY PATENT, COPYRIGHT OR OTHER INTELLECTUAL PROPERTY RIGHT.
UNLESS OTHERWISE AGREED IN WRITING BY INTEL, THE INTEL PRODUCTS ARE NOT DESIGNED NOR INTENDED FOR ANY APPLICATION IN WHICH THE FAILURE OF THE INTEL PRODUCT COULD CREATE A SITUATION WHERE PERSONAL INJURY OR DEATH MAY OCCUR.
Intel may make changes to specifications and product descriptions at any time, without notice. Designers must not rely on the absence or characteristics of any features or instructions marked "reserved" or "undefined." Intel reserves these for future definition and shall have no responsibility whatsoever for conflicts or incompatibilities arising from future changes to them. The information here is subject to change without notice. Do not finalize a design with this information.
The products described in this document may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request.
Contact your local Intel sales office or your distributor to obtain the latest specifications and before placing your product order.
Copies of documents which have an order number and are referenced in this document, or other Intel literature, may be obtained by calling 1-800-548-4725 FREE, or go to: http://www.intel.com/design/literature.html
Intel, the Intel logo, VTune, Cilk and Xeon are trademarks of Intel Corporation in the U.S. and other countries.