Engine building lesson 1: A minimum useless engine

In this lesson, we’re going to explore minimalism, in this case in the form of the most minimal engine possible (without obfuscating it).

The least boilerplate code for an engine looks like this:

#include <openssl/engine.h>

IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()

This example isn’t complete, it will not compile. However, it contains the absolute minimum required for those module to even be recognised as an OpenSSL engine.

When an engine is being loaded, the OpenSSL library will perform certain checks to see that the engine is compatible with this OpenSSL version, and finish up by calling the function whose name is given to IMPLEMENT_DYNAMIC_BIND_FN (bind in our case).

So, to complete the engine a bit more, we need to add the function bind, which should do all the final steps to tie this engine’s functionality with the calling OpenSSL.

#include <openssl/engine.h>

static int bind(ENGINE *e, const char *id)
{
  return 1;
}

IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()

This engine will simply load. Period.

At this point, we can build it. Let’s pretend we call it silly-engine.c and we’re running on Linux with some version of OpenSSL installed. Then, building is as simple as this:

$ gcc -fPIC -o silly-engine.o -c silly-engine.c
$ gcc -shared -o silly-engine.so -lcrypto silly-engine.o

Let’s try it out! Something to keep in mind is that if OpenSSL is just given an engine name, such as silly-engine, it will use platform specific library naming conventions to find the actual shareable name. So if given silly-engine as an engine name on Linux, it will try to find libsilly-engine.so, and that’s not at all what we’ve produced.

It is, however, also possible to give OpenSSL an absolute path for the engine, that’s what we’ll try out now.

$ openssl engine -t -c `pwd`/silly-engine.so
Segmentation fault

Uh-oh…

This happens to be a bug in OpenSSL, it should really report that the engine hasn’t self identified with an identity string and a longer name (can be used as a one line description).
[fix coming up]

So, let’s revisit the code one last time, and add some code in bind()

#include <stdio.h>

#include <openssl/engine.h>

static const char *engine_id = "silly";
static const char *engine_name = "A silly engine for demonstration purposes";

static int bind(ENGINE *e, const char *id)
{
  int ret = 0;

  if (!ENGINE_set_id(e, engine_id)) {
    fprintf(stderr, "ENGINE_set_id failed\n");
    goto end;
  }
  if (!ENGINE_set_name(e, engine_name)) {
    printf("ENGINE_set_name failed\n");
    goto end;
  }

  ret = 1;
 end:
  return ret;
}

IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()

Rebuilding and running gives us some nice output

$ gcc -fPIC -o silly-engine.o -c silly-engine.c 
$ gcc -shared -o silly-engine.so -lcrypto silly-engine.o
$ openssl engine -t -c `pwd`/silly-engine.so 
(/home/levitte/tmp/silly-engine/silly-engine.so) A silly engine for demonstration purposes
Loaded: (silly) A silly engine for demonstration purposes
     [ available ]

And voilà! A first engine, workable but entirely silly and useless.

If you’re interested, there’s a slightly more elaborated variant of this engine with configuration script and Makefile suitable for GNU auto* tools, libtool and automake for those who want to study that kind of setup closer.

Next lesson will be about adding a digest implementation.