Building and Using Themis in PNaCl

Intro

Native Client (NaCl) allows browser applications to launch a native low-level code in an isolated environment. Thanks to this, some code, performance code parts can be rewritten in C or C++ easily. Until recent time, NaCl could work on x86-compatible systems only, yet supporting ARM platform becomes very important, because a huge variety of devices (especially the newest Chrome OS laptops), are built on ARM architecture.

All you need to compile the code for ARM is located in the latest Native Client SDK. However, using NaCl forces developers to include support for all used architectures. This is achieved by building NaCl separately for all the architectures supported. Then the browser chooses the correct object to launch, basing on the architecture information.

Despite the fact that ARM architecture support in NaCl is rapidly improving, we should note that while Samsung Chromebooks remain being a primary objective for NaCl developers, it’s too early to talk about adequate ARM architecture support.

We find it more promising to use the next level of NaCl development - PNaCl (Portable Native Client) to bypass these difficulties. PNaCl is able to compile into LLVM bytecode, thus providing compatibility with all possible architectures, both the ones that currently exist and coming in the future.
The fact that NaCl is developed for a certain hardware architecture is the main reason for third-party developers’ concerns regarding this technology (as we know, Mozilla is not currently prioritizing NaCl compliance). This is the reason for PNaCl being better suited for developing new products.

Obviously, aside from PNaCl primary goal - performance improvement, having cross-platform executable bytecode coming from compiled C code is a way to run trusted code on multiple platforms during regular Web experience. This allows to avoid using often berated and totally insecure Java Applet technology to implement cryptographic features, at least in Google Chrome.

It’s self-explanatory that the main problem of porting any product to PNaCl is a limited support of third-party libraries, which developers use en masse, without even paying attention to their structure. Of course, major part of of standard libraries is ported to PNaCl already, yet that is not sufficient for comfortable development.

However, developing information protection systems on PNaCl involves certain difficulties, the main of which is porting certain crypto libraries to PNaCl. Such libraries usually have some code parts, which are conditionally-bound to the processor architecture. This is commonly done with a code like this one:

#if defined x86_arch
...
#elif defined amd64_arch

#else
#error "unsupported architecture"
#endif

It’s quite clear that the more polished a library is, the more elif’s it contains. Therefore, chances of modern developers facing the unsupported architecture error are quite low.  However, PNaCl architecture is yet to be defined and you should either choose one of the existing implementations or build your own, independent from any architecture and compatible with all of them.

The following post is an example of porting a C++ library to PNaCl, done for our Themis library.

CPP to PNaCl proting plan

The first thing you need to do is download and install the latest NaCl SDK. Considering you've done that, you might want to set the needed environment variables:

PNACL_ROOT=<NaCl SDK installation path>
PNACL_TOOLCHAIN=/toolchain/linux_pnacl
CC=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-clang
CXX=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-clang++
LD=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-ld
AR=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-ar
CFLAGS=-I$(PNACL_ROOT)/include/pnacl -I$(PNACL_ROOT)/usr/include/pnacl

Now, without further hesitation, let's try to build Themis for PNaCl. For further convenience and to avoid constant setup of environment variables, I created the following Makefile.pnacl:

PNACL_ROOT=<NaCl SDK installation path>
PNACL_TOOLCHAIN=/toolchain/linux_pnacl CC=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-clang CXX=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-clang++ LD=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-ld AR=$(PNACL_ROOT)$(PNACL_TOOLCHAIN)/bin/pnacl-ar CFLAGS=-I$(PNACL_ROOT)/include/pnacl -I$(PNACL_ROOT)/usr/include/pnacl
include Makefile

You can launch Themis build now:

make -f Makefile.pnacl static 

static parameter means we want to build a library that will provide static links, because our final product (PNaCl object) should be monolithic, if possible.

We received the following as a result:

src/soter/soter_container.c:25:13: error: implicit declaration of function 'htonl' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
           hdr->crc = htonl(soter_crc32(hdr, ntohl(hdr->size)));

The compiler could not find the `htonl` function, as it is one of architecture-dependent functions. We got lucky this time, because this function is already included into SDK for PNaCl. Browsing the source code showed us the file was located at `netinet/in.h` file, so we added it to `soter_container.c`. After repeating the compilation, we received the same error for `openssl/soter_ec_key.c`, `openssl/soter_rsa_key.c`, `secure_session_utils.c`, `secure_session.c`, `secure_session_serialize.c` files and added `#include <netinet/in.h>` to these files.

One more compilation:

src/themis/portable_endian.h:124:3: error: platform not supported
# error platform not supported
 ^
src/themis/secure_session_message.c:65:22: error: implicit declaration of function 'htobe64' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
       *((uint64_t *)ts) = htobe64(curr_time);

The error here is caused by the fact that `htobe64` library is not supported for current architecture (in fact, for any, because there is none defined by PNaCl). However, this function is quite easy to implement: let’s replace contents of  `portable_endian.h` with:

```
#include <netinet/in.h>
uint64_t htobe64(uint64_t x) { return htons(1) == 1 ? x : (((uint64_t)htonl(x)) << 32) + htonl(x >> 32); }
uint64_t be64toh(uint64_t x) { return htons(1) == 1 ? x : (((uint64_t)ntohl(x)) << 32) + ntohl(x >> 32); }
```

The next compilation runs successfully.

As Themis depends on lower-level crypto libraries LibreSSL/OpenSSL, their compilation to run under PNaCl is also necessary and goes beyond the frames of this article.

Now we can begin building our web application using Themis.

Detailed ways of creating PNaCl objects are described in our documentation.

ThemisPP

As main PNaCl parts are objects still, using object-oriented paradigm seems absolutely logical when developing such web apps. We would also like to step away from using low-level C code while using Themis in PNaCl . ThemisPP - a high-level C++ add-on for Themis will help us do so.

ThemisPP is adapted for use with the main STL containers and includes the following types:

  • `themispp::secure_cell` for Secure Cell
    • `themispp::secure_cell_seal` for Seal mode
    • `themispp::secure_cell_token_protect` for Token Protect Mode
    • `themispp::secure_cell_context imprint` for Context Imprint Mode
  • `themispp::secure_message` for Secure Message
  • `themispp::secure_session` (along with themispp::secure_session_transport) used to establish a Secure Session
  • `themispp::key_pair_generator_t` Keypair generator for asymmetric encoding schemes
  • `themispp::secure_rand` Random byte sequence generator

Now we can begin building PNaCl objects directly.

WebThemis

Let’s take a look at an example of PNaCl object used for encoding and decoding lines using

`themispp::secure_cell_seal` type:

```
virtual void HandleMessage(const pp::Var& var_message) {
	if (!var_message.is_string()){
	   PostMessage("error unsupported format");
	}
	std::istringstream message(var_message.AsString());
	std::string operation, password, base64encoded_data;
	message>>operation>>password>>base64encoded_data;
	try{q
	   if(operation == "encrypt"){
	       themis::secure_cell_seal encrypter(std::vector<uint8_t>(password.data(), password.data()+password.length()));
	       PostMessage(std::string("encrypt:"+base64encode(encrypter.encrypt(data)));
	   }
	   else if (operation == "decrypt"){
	       themis::secure_cell_seal decrypter(std::vector<uint8_t>(password.data(), password.data()+password.length()));
	       PostMessage(std::string("decrypt "+decrypter.decrypt(base64decode(data))));
	   } else {
	       PostMessage("error unsupported operation");
	   }
	}catch(themispp::exception& e){
	   PostMessage(std::string("error "+ e.what()));
	}
}

```

We use only the `HandleMessage` method here, which is used for processing messages from the web page JS code. In this example our PNaCl object receives the message in such form:

<operation type: encrypt or decrypt> <operation password (without spaces)> <data in base64 encoding>

and returns such message:

<type of the data returned> <data>
    encrypt
    decrypt
	error

JS handler code will be the following:

function handleMessage(message_event) {
    msg=message_event.data;
    command=msg[0];
    args=msg.slice(1);
    if (command == "encrypt"){
	    document.getElementById('secret_text').value=args;
    } else if (command == "decrypt"){
	    document.getElementById('plain_text').value=btoa(args);
	} else if (command == 'error'){
	    document.getElementById('error_text').value=args;		
	} else {
	    document.getElementById('error_text').value="unsupported operation";		
    }
}

function encrypt(password, data){
    a=document.getElementById('themis_secure_cell_seal_encrypter');
    a.postMessage('encrypt '+password+" "+atob(data));
}

function decrypt(password, data){
    a=document.getElementById('themis_secure_cell_seal_encrypter');
    a.postMessage('decrypt '+password+" "+data);
}
...
...
    <div id="listener">
	<script type="text/javascript">
	    var listener = document.getElementById('listener');
	    listener.addEventListener('message', handleMessage, true);
	</script>
	<embed name="nacl_module"
	    id="themis_secure_cell_seal_encrypter"
	    width=0 height=0
	    src="themis_secure_cell_seal_encrypter.nmf"
	    type="application/x-pnacl" />
    </div>
```

Basically, all interactions are performed through postMessage / handleMessage pair of functions in both C++ and JS code.

Summary

In this brief tutorial we’ve outlined the ways you can port libraries and chunks of code to create Google Chrome PNaCl objects from them, usable in a web page.

Want more? Learn more about Themis and try WebThemis in practice.

Copyright © 2014-2017 Cossack Labs Limited
Cossack Labs is a privately-held British company with a team of data security experts based in Kyiv, Ukraine.