Chapter 178. OpenSSL eCos Support

178.1. Introduction

The eCosPro-SecureSockets package is a port of OpenSSL to eCos. It currently comprises a port of version 1.0.1u, but eCosCentric will issue updates from time to time after new releases become avaliable.

178.1.1. Licensing, Copyrights and Patents

OpenSSL is distributed under a BSD-style Open Source license. The user is referred to the file LICENSE in the OpenSSL release for details, and is responsible for complying with the conditions therein.

The following text on the subject of patents is adapted from text in the README file in the OpenSSL release:

Various companies hold various patents for various algorithms in various locations around the world. YOU are responsible for ensuring that your use of any algorithms is legal by checking if there are any patents in your country. The following are some of the patents that we know about or are rumoured to exist. This is not a definitive list.

  • RSA Security holds software patents on the RC5 algorithm. If you intend to use this cipher, you must contact RSA Security for licensing conditions. Their web page is http://www.rsasecurity.com/.
  • RC4 is a trademark of RSA Security, so use of this label should perhaps only be used with RSA Security's permission.
  • The IDEA algorithm used to be patented by Ascom, but as of 2012, there are no longer any valid patents remaining so it may now be used patent-free.

To ensure that these patents are not accidentally violated, these algorithms are disabled by default and must be enabled explicitly by the user to be included.

Part of the conditions of using OpenSSL is that the following acknowledgment be displayed and applies not only to us, here, now, but to you as well:

This product includes cryptographic software written by Eric Young (eay@cryptsoft.com).

178.2. Configuration

OpenSSL is designed to work in large, fully featured operating systems. It expects to find a filesystem, a networking stack and a full C library. All of these things are available in eCos. However, a full configuration of this sort can be very large, both in terms of the link library generated and the size of executables. This may not be appropriate for an embedded system with limited memory availability. To mitigate these effects, the eCos port for OpenSSL has been adapted to work in three basic configurations. Users can then adapt these further to their own needs.

178.2.1. Full Configuration

Accessing the complete functionality of OpenSSL requires a fully configured version of eCos. This should be based on the net template together with a number of additional packages and configurations. These additions are contained in the openssl_full.ecm file in the package misc directory. This configuration may be built using the following sequence of shell commands.

$ mkdir openssl_full
$ cd openssl_full
$ ecosconfig new TARGET net
$ ecosconfig import $ECOS_REPOSITORY/services/openssl/VERSION/misc/openssl_full.ecm
$ ecosconfig resolve
$ ecosconfig tree
$ make

The same effect can be achieved from the graphical configtool by selecting the net template and then importing the ECM file.

178.2.2. Default Configuration

If no networking is available, openssl may still be built, but only the cryptographic and filesystem based functions may be used. This configuration is based on the default template which included file I/O functions and the C library, but no networking, plus the addition of an ECM file. This configuration may be built with the following sequence of commands, or the equivalent in the configtool:

$ mkdir openssl_default
$ cd openssl_default
$ ecosconfig new TARGET default
$ ecosconfig import $ECOS_REPOSITORY/services/openssl/VERSION/misc/openssl_default.ecm
$ ecosconfig resolve
$ ecosconfig tree
$ make

178.2.3. Kernel Configuration

OpenSSL will also build in a minimal kernel only configuration. This will be based on the kernel template plus an ECM file. This may be built with the following commands, or the equivalent in the configtool:

$ mkdir openssl_kernel
$ cd openssl_kernel
$ ecosconfig new TARGET kernel
$ ecosconfig import $ECOS_REPOSITORY/services/openssl/VERSION/misc/openssl_kernel.ecm
$ ecosconfig resolve
$ ecosconfig tree
$ make

This configuration is very basic, with no networking or file I/O, only the basic cryptographic functions will be available. The ECM file adds only STDLIB and Internationalization, mainly so that qsort() can be include; without this ASN1 support, and therefore most cryptographic components, cannot be built.

178.2.4. Serial Line Support

Some parts of the OpenSSL library read data from standard input; in particular some functions read passwords with echoing disabled. They achieve this by using TERMIOS functions on the device. For this to work correctly it is necessary to configure the standard I/O to use a serial driver, and to enable TERMIOS support on it. If you intend to use serial line 0 for this, then the following ECM fragment will set up the serial device correctly:

cdl_configuration eCos {
    package CYGPKG_IO_SERIAL current ;
};

# Enable serial device support
cdl_component CYGPKG_IO_SERIAL_DEVICES {
    user_value 1 ;
};

# Enable general TERMIOS support
cdl_component CYGPKG_IO_SERIAL_TERMIOS {
    user_value 1;
};

# Enable TERMIOS on serial 0
cdl_component CYGPKG_IO_SERIAL_TERMIOS_TERMIOS0 {
    user_value 1;
};

# Switch standard I/O to TERMIOS device 0
cdl_option CYGDAT_LIBC_STDIO_DEFAULT_CONSOLE {
    user_value "\"/dev/termios0\"";
};

Substitute a different serial device number for 0 in the above where necessary.

178.2.5. File System Dependencies

Much of OpenSSL can function without access to a filesystem. However, there are parts that expect to load or store data to or from files. If your application already uses a filesystem for other purposes (for example JFFS2 or YAFFS), then is should be easy to store OpenSSL's files there.

Where no external file store is available, the RAM filesystem can be used for temporary storage. The RAM filesystem can be mounted on system startup, and can be populated with files from data stored in memory. The following code shows how this might be done:

#define SERVER_CERT "/ram/server.pem"
static const char server_pem[] {
    ….
};

void init_ramfs( void )
{
    int fd;
    int err;
    size_t done;

    // Mount the RAM filesystem
    err = mount( "", "/ram", "ramfs" );
    if( err != 0 )
        diag_printf("RAMFS mount failed\n");

    // Write server.pem to RAM filesystem
    fd = open( SERVER_CERT, O_WRONLY|O_CREAT );
    done = write( fd, server_pem, sizeof(server_pem) );
    if( done != sizeof(server_pem) )
        diag_printf("server_pem write failed\n");
    close(fd);
}

Constant files can also be stored in the ROM filesystem, using mkromfs to create a file tree that can then be mounted and read.

178.2.6. Configuring OpenSSL

In addition to configuring eCos for OpenSSL, OpenSSL also contains a number of configuration points. The OpenSSL sources have been separated into a number of components, mainly corresponding to specific cryptographic algorithms and other components. Each of these is controlled by its own CDL option. By default only a subset of components are enabled. Other components may be enabled individually and alternatively all components may be enabled by setting CYGPKG_OPENSSL_ALL.

Various components of OpenSSL depend on different sets of operating system functionality, such as networking or file I/O. OpenSSL has internal configuration options to control the inclusion of different functional elements. In general we try to use those to control the build process. We have also encoded some dependencies in the CDL, both internal and external, to control the inclusion of entire components. However, the OpenSSL code is not normally compiled in systems with missing functionality, so even if the CDL and OpenSSL dependencies are correct, it is still possible for builds to fail with compile or link errors.

178.3. openssl Command Tool

The OpenSSL package contains a command line tool, openssl, that can be used to test the openssl package and to generate keys and certificates. This command can either execute a single command at a time, or run in interactive mode where successive commands are issued to a prompt. Under eCos it only runs in interactive mode, taking commands and issuing responses to the serial console.

The openssl tool will only build and run in the full configuration and additionally needs the RAM filesystem. If passwords are to be supplied, the serial line support described earlier should be enabled.

The command executable is created and saved in the INSTALL_DIR/bin directory. Both the original ELF file and an SREC file, openssl.srec are saved here. To run the command transfer the SREC file to your TFTP server and download and run it under RedBoot. You should see something similar to the following:

RedBoot> load openssl.srec
Using default protocol (TFTP)
Entry point: 0x20040040, address range: 0x20040000-0x201e76ec
RedBoot> go
[cyg_net_init] Init: mbinit(0x00000000)
[cyg_net_init] Init: cyg_net_init_devs(0x00000000)
Init device 'dm9000_eth0'
[cyg_net_init] Init: loopattach(0x00000000)
[cyg_net_init] Init: ifinit(0x00000000)
[cyg_net_init] Init: domaininit(0x00000000)
[cyg_net_init] Init: cyg_net_add_domain(0x201e51b0)
New domain internet at 0x00000000
[cyg_net_init] Init: cyg_net_add_domain(0x201e2c4c)
New domain route at 0x00000000
[cyg_net_init] Init: call_route_init(0x00000000)
[cyg_net_init] Done
mount /ram
set current directory to /ram
load openssl.cnf into /ram/openssl.cnf
initialise network interfaces
BOOTP[eth0] op: REPLY
       htype: Ethernet
        hlen: 6
        hops: 0
         xid: 0x0
        secs: 0
       flags: 0x0
       hw_addr: 00:03:47:df:32:a8
     client IP: 192.168.7.20
         my IP: 192.168.7.20
     server IP: 192.168.7.22
    gateway IP: 192.168.0.1
  options:
        subnet mask: 255.255.0.0
       IP broadcast: 192.168.255.255
            gateway: 192.168.0.1
[eth_drv_ioctl] Warning: Driver can't set multi-cast mode
[eth_drv_ioctl] Warning: Driver can't set multi-cast mode
[eth_drv_ioctl] Warning: Driver can't set multi-cast mode
Start OpenSSL
OpenSSL> version
OpenSSL 1.0.0c 2 Dec 2010
OpenSSL>

The RAM filesystem is mounted and /ram is set as the current directory. It is therefore possible to test the generation of keys and certificates into files:

OpenSSL> req -x509 -nodes -days 36500 \
            -subj "/C=GB/ST=England/L=Cambridge/O=eCosCentric/CN=ecoscentric.com" \
            -newkey rsa:1024 -keyout mycert.pem -out mycert.pem
Generating a 1024 bit RSA private key
…………........++++++
……..++++++
writing new private key to 'mycert.pem'
-----
OpenSSL>

If you want to enter passwords without reflection, you need to enable the TERMIOS support described above.

The eCos hosted openssl command serves as a test for OpenSSL functionality, and is a good check that the library is complete. However, it is of little practical use and has some limitations. While is possible to generate key files and certificates, it is not then easy to get then off the board for future use, unless they are stored to an external medium such as an SD card. It is recommended, instead, that a host based version of openssl be used to do this. Files may then be imported via removable media, or written to the RAM filesystem as described above. Another limitation is that if you run the s_server command, you cannot terminate it. Under Unix/Linux this command relies on catching the signal generated by a Ctrl-C to terminate; there is no support for this under eCos and the only way to terminate this command is to reboot and reload openssl.

178.4. Thread Safety

The OpenSSL library does not directly contain support for thread safe code. Instead it relies on application code to register some callbacks to perform the locking required. Under eCos there are two ways of doing this: through the POSIX compatibility package and directly using eCos APIs.

POSIX locking support is already available in OpenSSL. Example code is available in src/crypto/threads/th-lock.c, and similar code is tested in the mttest test program. However, this code will only work in threads that have been created using pthread_create(), or in the main() application thread.

eCos locking support uses lower level primitives and can be used from any kind of thread. In order to provide locking, an application must register two callbacks with the library, and set up an array of locks that the library will request it to lock and unlock. The following code does this:

// Forward definitions for callback functions.
void ecos_locking_callback(int mode, int type, char *file, int line);
unsigned long ecos_thread_id_callback(void);

// Pointer to array of locks.
static cyg_mutex_t *lock_cs;

// This function allocates and initializes the lock array
// and registers the callbacks. This should be called
// after the OpenSSL library has been initialized and
// before any new threads are created.
void thread_setup(void)
{
    int i;

    // Allocate lock array according to OpenSSL's requirements
    lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(cyg_mutex_t));

    // Initialize the locks
    for (i=0; i<CRYPTO_num_locks(); i++)
    {
        cyg_mutex_init(&(lock_cs[i]));
    }

    // Register callbacks
    CRYPTO_set_id_callback((unsigned long (*)())ecos_thread_id_callback);
    CRYPTO_set_locking_callback((void (*)())ecos_locking_callback);
}

// This function deallocates the lock array and deregisters the
// callbacks. It should be called after all threads have
// terminated.
void thread_cleanup(void)
{
    int i;

    // Deregister locking callback. No real need to
    // deregister id callback.
    CRYPTO_set_locking_callback(NULL);

    // Destroy the locks
    for (i=0; i<CRYPTO_num_locks(); i++)
    {
        cyg_mutex_destroy(&(lock_cs[i]));
    }

    // Release the lock array.
    OPENSSL_free(lock_cs);
}

// Locking callback. The type, file and line arguments are
// ignored. The file and line may be used to identify the site of the
// call in the OpenSSL library for diagnostic purposes if required.
void ecos_locking_callback(int mode, int type, char *file, int line)
{
    if (mode & CRYPTO_LOCK)
    {
        cyg_mutex_lock(&(lock_cs[type]));
    }
    else
    {
        cyg_mutex_unlock(&(lock_cs[type]));
    }
}

// Thread id callback.
unsigned long ecos_thread_id_callback(void)
{
    return (unsigned long)cyg_thread_get_id(cyg_thread_self());
}

Example code similar to this can be found in the mttest_ecos test program.

178.5. eCos Customization

The eCos port of OpenSSL contains a number of customizations to adapt OpenSSL to the eCos environment.

178.5.1. Random Number Support

To function correctly, OpenSSL requires a source of cryptographically strong random numbers. These are usually sourced either from operating system level entropy gathering or from a hardware random number generator. At present eCos does not have any entropy gathering mechanism so the only viable source is a hardware RNG. Without entropy gathering or hardware RNG use, some forms of encrypted data may be more vulnerable to attack. Contact eCosCentric if a solution is required for this.

OpenSSL gathers random numbers by calling RAND_poll() when necessary. This function is responsible for calling RAND_add() to mix new random data into OpenSSL's PRNG state. Application code can also call RAND_add() directly to add entropy from any source.

The source file src/ecos/rand_ecos.c contains an implementation of RAND_poll() that adds data from a static table whenever called. This is clearly not cryptographically strong, since the same random data will be added each time an application starts. This implementation is adequate for testing the library only and should not be used for real applications. The eCos port of OpenSSL does not automatically use a hardware RNG if present, and so application code is responsible for calling RAND_add() to incorporate random entropy from a hardware RNG into OpenSSL's PRNG.

178.5.2. BIO_diag

OpenSSL implements a general purpose data source/sink/filter object called a BIO. These may be attached to various sources and sinks such as C library FILEs, file descriptors and sockets. Many functions that need to output messages take a pointer to a BIO as an argument, which is typically attached to stdout or stderr. In certain eCos configurations these streams are not present, but we still want to use these functions and supply a BIO for output.

eCos implements a new BIO type, BIO_diag which outputs any data on the eCos diagnostic channel. It can be created using the new function BIO *BIO_new_diag(void), and can subsequently be used in place of any other output-only BIO. It may be freed in the usual way with BIO_free().

178.6. Tests

OpenSSL contains a number of test programs that validate the correctness of various cryptographic algorithms and test the functioning of the OpenSSL library. Most of these tests have been ported directly to eCos with only minor changes to allow them to function in the eCos test environment. Since all these tests expect to use C library standard I/O (STDIO) for output, they will only be built if that package is configured in.

A small number of encryption algorithm tests have been further adapted to function without needing STDIO. This has mainly involved replacing (f)printf with diag_printf, but also includes spawning a thread to run the test with sufficient stack. These tests are all named the same as the base OpenSSL test from which they were derived with the addition of _ecos to the file name.

The test program ssltest1 is the only purpose written SSL test program. It is a simple client that attempts to contact an SSL server and send it some data. The server it contacts is defined by the configuration options CYGDAT_OPENSSL_TESTS_SERVER_IP and CYGDAT_OPENSSL_TESTS_SERVER_PORT which are used to set IP address and port number of the server to contact. A suitable server can be run using the s_server command of the openssl tool on the host with the configured IP address. The shell script in misc/runtest within the eCos OpenSSL package in the package repository should do this correctly for any Linux host.

The test program openssl1 is a version of the openssl command line tool that runs a sequence of predefined commands to test the library as a whole. One of the commands that this test runs is a timing test against the same server that ssltest1 uses.

178.7. Limitations

OpenSSL includes files crypto/asn1/a_utctm.c and src/crypto/asn1/a_time.c which have hard-coded year limits of 2050. Use beyond that year is at present unsupported, although it is expected that upstream OpenSSL will resolve this at some point.