LibreSSL vs OpenSSL: The fork origin

In April 2014, a new security bug was found on OpenSSL, codename: Heartbleed. A detailled explanation can be found on wikipedia . To sum up: the implementation of the Heartbeat extension for TLS and DTLS is bugged in OpenSSL. This bug, a missing buffer size check on user provided data, allows an attacker connected to a server running openssl to extract and receive memory values from possibly protected areas. It appears feasible to bring OpenSSL implementation to leak server secrets including keys, internal values ... This bug has been fixed sine OpenSSL version 1.0.1g.
   This bug, considered a critical vulnerability registered as CVE-2014-0160) is sometime considered the reason for forking OpenSSL to LibreSSL. In April 2014, after a sorrow code audit, some OpenBSD developers (among them Bob Beck and Ted Unangst) forked OpenSSL 1.0.1f into LibreSSL. They generally point the poor code quality of OpenSSL as the main reason for forking it and cleaning it.
Their work lead them to:
  • remove large parts of OpenSSL source , mostly for target support for architectures that very few people ever used
  • clean other parts: deleting the unnecessary complex and it seems pretty much broken OpenSSL memory allocation/deallocation system. They replaced it with standard libc call (e.g.  malloc/calloc/reallocarray). Using those functions makes it more easy for standard checking tools to verify memory allocation/free schemes while maintaining better properties (e.g. multiplication overflow checking for calloc vs malloc).
LibreSSL became the de facto implementation for TLS in OpenBSD and some Linux distribution (e.g. arch) and has gained some momentum since. New features (e.g. ciphers based on Bernstein's chacha and poly 1305 or ANSSI EC) and new API (e.g libTLS) have been developed.
   Along with Google own fork of OpenSSL (Boring SSL) LibreSSL seems like a great initiative to improve security and maintainability of ex-SSL/TLS implementations. The previous security vulnerabilities have shown that it is important to keep a readable code base which can be audited by large community of skilled developer and cryptographer.
  In Parallel, it seems that it did a lot of good to OpenSSL itself, more developpers have been hired to work full time on the library. Since 2014, the library has been actively extended (Lots of cleaning, Async, Pipelining ...). The new version 1.1, released on August 25th 2016 provided a lot of expected changes and looks much as a renewal.

References:


  1. Wikipedia's page on Heartbleed: https://en.wikipedia.org/wiki/Heartbleed
  2. Heartbleed description (from Codenomicon) http://heartbleed.com/
  3. Ted Unangst's article on the state of libreSSL fork from OpenSSL 30 days later: https://www.openbsd.org/papers/eurobsdcon2014-libressl.html
  4. Reddit discussion on the subject: https://www.reddit.com/r/crypto/comments/3o2zy5/openssl_vs_libressl/
  5. Bob Beck's slides on the new libTLS API for libreSSL http://www.openbsd.org/papers/libtls-fsec-2015/mgp00001.html
  6. Wikipedia's page on LibreSSL: https://en.wikipedia.org/wiki/LibreSSL
  7. LibreSSL website: http://www.libressl.org/
  8. Article on OpenSSL team meeting after Heartbleed: http://qz.com/286210/how-an-unprecedented-face-to-face-meeting-of-11-geeks-will-make-the-internet-more-secure/

Building an OpenSSL Engine: Part1

Let's start the engine

In Part 0, we learn how to developp a basic OpenSSL engine : a dynamic library which offloads cryptography computation from the crypto library.The second step is to use our engine.  

   OpenSSL is a complete solution, it provides:
  • libraries for cryptography (libcrypto), for secure connections management (libssl)
  • numerous command line utilities (e.g. certificate generations, encryption ..)
OpenSSL CLI (command line interface) is accessible through the "openssl" command. Three options to this command are of interest to us:
  • openssl engine which lists available engines or load a new engine
  • openssl dgst which computes a message digest from a given data source (stdin, input file ..)
  • openssl enc which encrypts or decrypts messages (which we will use in a later article)
We already saw in part 0 how to use openssl engine to check that our newly built engine could be loaded successfully. Let us now use it through openssl dgst .

$ echo abc | openssl dgst -sha1
(stdin)= 03cfd743661f07975fa2f1220c5194cbaff48451  

    This first example computes the SHA1 digest of the string "abc" using the standard implementation of the SHA1 algorithm provided by openssl. The string is forwarded through a pipe but it could have been read from a file (using -in <input filename> option ).
Let us now apply the same command with an extra -engine option to force openssl to rely on our own SHA1 implementation:

$ echo abc | openssl dgst -engine `pwd`/build/engine_ex.so -sha1 
engine "engineX" set. 
(stdin)= 03cfd743661f07975fa2f1220c5194cbaff48451  

Happilly the digests match. You can also notice that our engine was set which means the openssl registered it as requested. (Note: To make sure OpenSSL in indeed using your engine you can introduce a small error in the digest computed by the engine (e.g. in the function sha1_final in "e_ex.c" ) to make sure it is visible in the result).

Accessing our engine in a C program

OpenSSL CLI is a powerful tools but if you want to developp your own efficient cryptography application you may be more inclined to access OpenSSL capabilities through its C API.
   In the following sections we are going to look in details at the example tests/basic_digest.c, available on the article series github.
In those sections we will see several things: how to write an OpenSSL configuration file so OpenSSL can learn the existence of our engine and where to load it from, how to load this configuration file in a program using OpenSSL libraries (loading our engine with it), how to use explicit our engine as a digest implementation to compute a message digest and finally how to define our engine as the by default implementation of OpenSSL so each time a SHA1 digest is computed through the EVP API the computation is offloaded to our engine.


Writing an OpenSSL Configuration File

   A clean way to load an engine from within a C program is to integrate the engine description to an OpenSSL configuration file and to load the configuration file in your application.
   The following example is a configuration file which described how to load the engine built in the previous lesson:

openssl_conf            = openssl_def
[openssl_def]
engines = engine_section
[engine_section]
engine_x = engine_x_section
[engine_x_section]
engine_id = engineX
dynamic_path = ${ENV::PWD}/build/engine_ex.so 
init = 1

An interesting feature of OpenSSL configuration file is the possibility to include envrionemment (shell) variables with the ${ENV::<var name>} syntax.


Initializing OpenSSL and loading our engine

    There are several calls necessary to initialize OpenSSL properly, a detailed explaination can be found in OpenSSL wiki. In this example we will simply make the basic calls to enable engine load and use:

// initializing OpenSSL library
OPENSSL_load_builtin_modules();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
ENGINE_load_dynamic();

Once the library is initialized we may load the configuration file:

// building OpenSSL's configuration file path
char openssl_cnf_path[] = "./openssl.cnf"; 

// loading configuration
if (CONF_modules_load_file(openssl_cnf_path, "openssl_conf", 0) != 1) {
  fprintf(stderr, "OpenSSL failed to load required configuration\n");
  ERR_print_errors_fp(stderr);
  return 1;
}

The configuration loading will make the library load the engine described in "openssl.cnf". Thereafter, it may be accessed as follows:


ENGINE* eng = ENGINE_by_id("engineX");
if(NULL == eng) {
  printf("failed to retrieve engine by id (mppa)\n");
  return 1;
}

Forcing the use of our engine in an explicit digest call

The handle of type Engine* may be used in a EVP_DigestInit_ex call to force the use of the engine.


unsigned char digest[20];
// message digest context declaration
EVP_MD_CTX sctx;
EVP_MD_CTX* ctx = &sctx;
EVP_MD_CTX_init(ctx);
// declaring the use of SHA-1 and specifying the
// engine as the implementation to use
EVP_DigestInit_ex(ctx, EVP_sha1(), eng);
// updating digest with input data
EVP_DigestUpdate(ctx, data, len);
unsigned int dlen = -1;
// finishing and retrieving digest
EVP_DigestFinal(ctx, digest, &dlen);

The previous examples (basic_digest.c) is available on the article serie github. It must be linked with libcrypto and libssl (e.g. using -lcrypto and -lopenssl link options).

Configuring our engine to be used as default

OpenSSL provides through the ENGINE API some functions to bind an engine as the default method for any algorithm including digest:


// defining our engine as the default implementations
// for digest algorithms
ENGINE_set_default_digests(eng);


// Initializing a SHA-1 digest context
// without specifying an implementation,
// thus falling back on the default method
EVP_DigestInit(ctx, EVP_sha1());

An other way to define our engine as the default method for algorithms it supports, is to add the line "default_algorithms = ALL" to our engine section in openssl configuration file :


openssl_conf            = openssl_def
[openssl_def]
engines = engine_section
[engine_section]
engine_x = engine_x_section
[engine_x_section]
engine_id = engineX
dynamic_path = ${ENV::PWD}/build/engine_ex.so 
default_algorithms = ALL
init = 1

The "ALL" option value associates our engine as the default implementation for all algorithms (restrain to all the algorithm the engine supports). The other possible values are:  RSA, DSA, DH, EC, RAND, CIPHERS, DIGESTS, PKEY, PKEY_CRYPTO and PKEY_ASN1. As our engine only support a digest (SHA1), the values ALL and DIGESTS have the same outcome in our configuration : declaring our engine as the default implementation for SHA1.

Warning: some OpenSSL non standard methods (such as SHA256(...) ) bypass the EVP API and do not depend on the default implementation. Those methods only use the software implementation built-in OpenSSL and never the engines even if defined as default methods.

References 

  1. Wikipedia's page on SHA1  https://en.wikipedia.org/wiki/SHA-1
  2. OpenSSL manual page on Engine API https://wiki.openssl.org/index.php/Manual:Engine%283%29
  3. OpenSSL manual page on library initialization https://wiki.openssl.org/index.php/Library_Initialization
  4. External documentation / example of OpenSSL configuration files : file https://www.nlnetlabs.nl/downloads/publications/hsm/hsm_node18.html
  5. An other tutorial which talks about OpenSSL configuration files :  https://www.sinodun.com/2009/02/developing-an-engine-for-openssl/

Short note: consequence of arithmetic overflow

This is not a full length article but simply a short note.

I recently came across a very interesting post on OpenSSL blog which detailed how a "bad" use of pointer arithmetic lead to a possible low-level security breach in the library. I will let the interested reader go through the original post to understand all the technical details and I will focus on a short explanation. In C90 pointer arithmetic is only defined/specified for malloc-ed pointers with operands less than the malloc-ed size, everything else is undefined behavior.
  It means that in the following example, len must be less or equal to SIZE for the test to work as expected, which makes it pretty much completely useless since this code is supposed to test that specific condition.


/* implied */
char* p = malloc(SIZE);

// buffer overflow detection
if (p + len < limit) {
  // manage overflow case
}

    The reason is as follows: if len is superior to SIZE, then p + len may overflow from the memory bound and wrap, thus resulting in a lesser value which will then be wrongly compared as lesser than limit. In the case of OpenSSL it could leads to decryption or encryption outside the assumed area (at the least).
    This is a good example showing that arithmetic overflow (and pointer arithmetic) must be considered carefully, especially when security is a concern,

References

  1. https://www.openssl.org/blog/blog/2016/06/27/undefined-pointer-arithmetic/