Creating an OpenSSL Engine to use indigenous ECDH ECDSA and HASH Algorithms
Introduction[edit]
This tutorial is intended to provide an example implementation of an OpenSSL Engine such that indigenous cryptographic code for ECDSA and ECDH as well as some sha2 family algorithms can be used in OpenSSL for different purposes.
This guide will not provide the reader with implementation of actual cryptographic primitives but only with the necessary code to embed cryptographic software into OpenSSL as an engine.
To test our implementation we will also write a program “EngineTester” to see the that our engine is actually working.
Preparations[edit]
In this tutorial is done on an (X)Ubuntu 15.04, with custom compiled OpenSSL version 1.0.2d. The GCC version is: “gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2”
Note that the OpenSSL Engine has to be written in pure C, anything C++ related causes OpenSSL not to load the Engine. You can however embed C++ code, with some tricks see: #Using C++ Implementations. Also the OpenSSL Engine is a shared library object libXXXX.so.
If the compiler warns with something like “implicit declaration of …” then the engine will also not work, you have to use strictly C syntax. OpenSSL Engines are stored in /usr/lib/engines/ on the mentioned Ubuntu 15.04 System, others may vary. To make it easy we create a symbolic link in this directory pointing to our output shared library. When we call our engine oezganEngine and the shared library will be liboezganEngine.so, then we create our symbolic link with:
sudo ln –s ~/workspace/oezganEngine/Debug/liboezganengine.so liboezgan.so
You can also copy the compiled shared library into the /usr/lib/engines/ directory but this should be done when the engine is ready to be deployed.You can find the OpenSSL include files in /usr/include/openssl.
Beginning[edit]
We will start with implementing an engine which only has its name and nothing else. The oezganEngine.c file:
#include <openssl/engine.h> static const char *engine_oezgan_id = "oezgan"; static const char *engine_oezgan_name = "oezgan engine by Fraunhofer FKIE"; IMPLEMENT_DYNAMIC_CHECK_FN(); IMPLEMENT_DYNAMIC_BIND_FN(bind_helper); int oezgan_init(ENGINE *e) { printf("Oezgan Engine Initializatzion!\n"); return 786; } int bind_helper(ENGINE * e, const char *id) { if (!ENGINE_set_id(e, engine_oezgan_id) || !ENGINE_set_name(e, engine_oezgan_name) || !ENGINE_set_init_function(e,oezgan_init) ) return 0; return 1; }
and the tester oezganEngineTester.cc file:
#include <openssl/engine.h> #include <stdio.h> #include <string.h> int main(int argc, const char* argv[] ) { OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); ENGINE_load_dynamic(); ENGINE *oezgan_engine = ENGINE_by_id("oezgan"); if( oezgan_engine == NULL ) { printf("Could not Load Oezgan Engine!\n"); exit(1); } printf("Oezgan Engine successfully loaded\n"); int init_res = ENGINE_init(oezgan_engine); printf("Engine name: %s init result : %d \n",ENGINE_get_name(oezgan_engine), init_res); return 0; }
Note that we use a c++ file to test the engine. Running the tester gives us the following result:
oezgan@kehf-dev1:~/workspace3/oezganEngineTester/Debug$ ./oezganEngineTester Oezgan Engine successfully loaded Oezgan Engine Initializatzion! Engine name: oezgan engine by Fraunhofer FKIE init result : 786
Our engine is successfully loaded and when it`s asked it gives back its name. Now we proceed by implementing our own random function.
Cleanup memory leaks
For OpenSSL version prior to 1.1.0, users are required to call ENGINE_cleanup, EVP_cleanup, etc. to prevent memory leak. See Library Initialization page. For OpenSSL version 1.1.0 and 1.1.1, cleanup happens automatically, users should not worry about it. ENGINE_set_finish_function & ENGINE_set_destroy_function are still available to do implementation specific cleanup.
The Random Function[edit]
OpenSSL has its own method declarations which our engine has to comply with. In the header file ossl_typ.h we find the declaration s:
typedef struct rand_meth_st RAND_METHOD; typedef struct ecdh_method ECDH_METHOD; typedef struct ecdsa_method ECDSA_METHOD;
For now we are only interested in the RAND_METHOD declaration. The RAND_METHOD declaration is actually a macro for the rand_method_st declaration which can be found in rand.h of the OpenSSL includes. Here we see that the rand_method_st has the following format:
struct rand_meth_st { void (*seed) (const void *buf, int num); int (*bytes) (unsigned char *buf, int num); void (*cleanup) (void); void (*add) (const void *buf, int num, double entropy); int (*pseudorand) (unsigned char *buf, int num); int (*status) (void); };
Thus we see that the OpenSSL random method structure defines six functions where the headers of these functions have specific formats. For simplicity purposes we will only implement the “bytes” and the “status” methods. The status method should return an integer and takes no arguments. Presumably this method is used for indication of the state of the random machine. Our engine`s random machine has no states, therefore we only return a positive integer to indicate a thumbs up state. The random status method:
int oezgan_random_status(void) { return 1; }
Now we implement our own method for generating a number of random bytes as follows:
//new includes #include <string.h> #include <openssl/ossl_typ.h> int get_random_bytes(unsigned char *buffer, int num) { printf("oezgan engine random length %d\n", num); memset(buffer,1,num); return 99; }
This method will fill the given buffer with num many ones. Now we indicate our random machine structure as:
RAND_METHOD oezgan_random_method = { NULL, /* seed */ get_random_bytes, NULL, /* cleanup */ NULL, /* add */ NULL, oezgan_random_status };
We also modify the bind_helper function from above:
int bind_helper(ENGINE * e, const char *id) { if (!ENGINE_set_id(e, engine_oezgan_id) || !ENGINE_set_name(e, engine_oezgan_name) || !ENGINE_set_init_function(e, oezgan_init) || !ENGINE_set_RAND(e, &oezgan_random_method) ) return 0; return 1; }
In the tester we add the following lines:
ENGINE_set_default_RAND(oezgan_engine); unsigned char * rand_buf= new unsigned char[5]; int err = RAND_bytes(rand_buf,5); for(int i= 0; i < 5; i++) { printf("%x",rand_buf[i]); } printf("\n"); free(rand_buf);
The result is seen below:
oezgan@kehf-dev1:~/workspace3/oezganEngineTester/Debug$ ./oezganEngineTester Oezgan Engine successfully loaded Oezgan Engine Initializatzion! Engine name: oezgan engine by Fraunhofer FKIE init result : 786 oezgan engine random length 5 11111
We now successfully implemented an OpenSSL engine that gives always returns a lot of 1s as random values.
Digests[edit]
Now we want OpenSSL not only to use our own random function but also to use our sha2 family hash functions. We first implement a digest selector function, which tells OpenSSL which digests are available in our engine. This kind of implementation is adapted from the OpenSSL`s build-in engine ccghost. We will implement only one hash function namely SHA256. Following the the ossl_typ.h header to the evp.h header one can see that the Message Digest Structure is defined as follows:
struct env_md_st { int type; int pkey_type; int md_size; unsigned long flags; int (*init) (EVP_MD_CTX *ctx); int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); int (*final) (EVP_MD_CTX *ctx, unsigned char *md); int (*copy) (EVP_MD_CTX *to, const EVP_MD_CTX *from); int (*cleanup) (EVP_MD_CTX *ctx); /* FIXME: prototype these some day */ int (*sign) (int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, void *key); int (*verify) (int type, const unsigned char *m, unsigned int m_length, const unsigned char *sigbuf, unsigned int siglen, void *key); int required_pkey_type[5]; /* EVP_PKEY_xxx */ int block_size; int ctx_size; /* how big does the ctx->md_data need to be */ /* control function */ int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2); } /* EVP_MD */ ;
(Commentaries are original form OpenSSL code). From this we use our own message digest hash SHA256 declaration:
static EVP_MD oezgan_engine_sha256_method= { NID_sha256, NID_undef, 32, EVP_MD_FLAG_PKEY_METHOD_SIGNATURE, oezgan_engine_sha256_init, oezgan_engine_sha256_update, oezgan_engine_sha256_final, oezgan_engine_sha256_copy, oezgan_engine_sha256_cleanup, /* FIXME: prototype these some day */ NULL, NULL, {NID_undef, NID_undef, 0, 0, 0}, 64, /*Block Size*/ 32, /* how big does the ctx->md_data need to be */ /* control function */ NULL, } ;
SHA256 uses a block size of 512 Bit = 64 byte and resulting digest is 256 Bit = 32 byte long. You can also use your own block size and outcome size but for a realistic approach we stick to the original sha256 standard. Now we need to implement the init, update, final and copy functions for our own sha256 implementation. In our implementation the SHA256 Value is always 2222…
Note
Since 1.1.0, EVP_MD cannot be directly accessed. Users have to call EVP_MD_meth_new to get EVP_MD instance, and use EVP_MD_meth_set_* to set functions and properties list above.
OID and NID
In above example, we reused sha256's nid. For those who want to implement new algorithms, use OBJ_create to create new nid and OBJ_*2nid to translate names to nids.
static int oezgan_engine_sha256_init(EVP_MD_CTX *ctx) { ctx->update = &oezgan_engine_sha256_update; printf("initialized! SHA256\n"); return 1; } static int oezgan_engine_sha256_update(EVP_MD_CTX *ctx,const void *data,size_t count) { printf("SHA256 update \n"); unsigned char * digest256 = (unsigned char*) malloc(sizeof(unsigned char)*32); memset(digest256,2,32); count = 32; ctx->md_data = digest256; return 1; } static int oezgan_engine_sha256_final(EVP_MD_CTX *ctx,unsigned char *md) { printf("SHA256 final size of EVP_MD: %d\n", sizeof(EVP_MD)); memcpy(md,(unsigned char*)ctx->md_data,32); return 1; } int oezgan_engine_sha256_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) { printf("Copy SHA256\n"); if (to->md_data && from->md_data) { memcpy(to->md_data, from->md_data,sizeof(from->md_data)); } return 1; } static int oezgan_engine_sha256_cleanup(EVP_MD_CTX *ctx) { printf("SHA256 cleanup\n"); if (ctx->md_data) memset(ctx->md_data, 0, 32); return 1; }
Now we have to tell OpenSSL that whenever a SHA256 digest is requested use the engine implementation of sha256 this will be the digest selector function.
static int oezgan_digest_ids[] = {NID_sha256}; static int oezgan_engine_digest_selector(ENGINE *e, const EVP_MD **digest, const int **nids, int nid) { int ok = 1; if (!digest) { *nids = oezgan_digest_ids; printf("\n Digest is empty! Nid:%d\n", nid); return 2; } printf("Digest no %d requested\n",nid); if (nid == NID_sha256) { *digest = &oezgan_engine_sha256_method; } else { ok = 0; *digest = NULL; } return ok; }
We also need to modify the bind_helper function again:
int bind_helper(ENGINE * e, const char *id) { if (!ENGINE_set_id(e, engine_oezgan_id) || !ENGINE_set_name(e, engine_oezgan_name) || !ENGINE_set_RAND(e, &oezgan_random_method) || !ENGINE_set_init_function(e, oezgan_init) || !ENGINE_set_digests(e, &oezgan_engine_digest_selector) ) return 0; return 1; }
And we modify our tester to generate us a SHA256 Hash function.
char * str = "Fraunhofer FKIE Wachtberg!"; int str_len = 26; int er = ENGINE_set_default_digests(oezgan_engine); printf("ENGINE SETTING DEFAULT DIGESTS %d\n",er); unsigned char * digest = new unsigned char[32]; unsigned int digestSize = -1; EVP_MD_CTX *evp_ctx; evp_ctx = EVP_MD_CTX_create(); er = EVP_DigestInit_ex(evp_ctx, EVP_sha256(),oezgan_engine); printf("Digest INIT %d\n",er); er = EVP_DigestUpdate(evp_ctx, (unsigned char*)str, str_len); printf("Digest Update %d\n",er); er = EVP_DigestFinal(evp_ctx, digest, &digestSize); printf("Digest Final %d Digest size:%d\n",er,digestSize); for(int i= 0; i< digestSize; i++) { printf("%x", digest[i]); } printf("\n"); EVP_MD_CTX_destroy(evp_ctx);
The result is:
oezgan@kehf-dev1:~/workspace3/oezganEngineTester/Debug$ ./oezganEngineTester Oezgan Engine successfully loaded Oezgan Engine Initializatzion! Engine name: oezgan engine by Fraunhofer FKIE init result : 786 oezgan engine random length 5 11111 ENGINE SETTING DEFAULT DIGESTS 1 initialized! SHA256 Digest INIT 1 SHA256 update Digest Update 1 SHA256 final size of EVP_MD: 76 SHA256 cleanup Digest Final 1 Digest size:32 22222222222222222222222222222222
Similarly one can also implement other digest functions. Now we move on to more complicated things like the ECDSA or the ECDH algorithms.
ECDH[edit]
We now want to use our own Elliptic Curve Diffie-Hellman Key Agreement function. This is a little bit different from what we have seen above. We get us the definition of the ECDH method structe from the file crypto/ecdh/ecdh.h the definition which is provided in this file is not included in the OpenSSL headers, therefore we have to put it in a new header file which will be included in our engine.
The file oezganEngine.h:
#ifndef OEZGANENGINE_H_ #define OEZGANENGINE_H_ #ifdef __cplusplus extern "C" { #endif struct ecdh_method { const char *name; int (*compute_key) (void *key, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh, void *(*KDF) (const void *in, size_t inlen, void *out, size_t *outlen)); # if 0 int (*init) (EC_KEY *eckey); int (*finish) (EC_KEY *eckey); # endif int flags; char *app_data; }; #ifdef __cplusplus } #endif #endif /* OEZGANENGINE_H_ */
KDF is the Key Derivation Function which will be NULL here. Now we add the following declaration in to our oezganEngine.c file:
ECDH_METHOD oezgan_ecdh_method = { "Oezgan Engine ECDH Method", oezgan_engine_compute_ecdh_key, # if 0 NULL, NULL, # endif 0, NULL, };
And the implementation of the ECDH method:
static int oezgan_engine_compute_ecdh_key(void * key, size_t outlen, const EC_POINT *pubkey, EC_KEY *eckey, void *(*oezgan_ecdh_kdf) (const void *in, size_t inlen, void *out, size_t *outlen)) { printf("Oezgan Engine ECDH Method\n"); EC_GROUP *group = EC_KEY_get0_group(eckey); //convert pubkey int pubkey_len = EC_POINT_point2oct(group, pubkey, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); unsigned char * pubkey_buf = malloc(sizeof(unsigned char)*pubkey_len); pubkey_len = EC_POINT_point2oct(group, pubkey, POINT_CONVERSION_UNCOMPRESSED, pubkey_buf, pubkey_len, NULL); //convert private key const BIGNUM* prikey_bn = BN_new(); prikey_bn = EC_KEY_get0_private_key(eckey); int privkey_len = BN_num_bytes(prikey_bn); unsigned char * privkey_buf = malloc(sizeof(unsigned char)*privkey_len); BN_bn2bin(prikey_bn, privkey_buf); memset(key,3,pubkey_len); outlen = pubkey_len; free(privkey_buf); free(pubkey_buf); printf("Oezgan engine ECDH method End returning: %d!\n", outlen); return outlen; }
Our implementation of the ECDH Method copies the public key into an unsigned char array pubkey also the private key is converted into an unsigned char array for demonstration purposes since a real ECDH implementation has to calculate the from the values bP = B and aP=A the value abP where a and b are the secret keys of two users Aylin and Boris respectively and P is the base point on the elliptic curve. Again we modify our bind_helper method as follows:
int bind_helper(ENGINE * e, const char *id) { if (!ENGINE_set_id(e, engine_oezgan_id) || !ENGINE_set_name(e, engine_oezgan_name) || !ENGINE_set_RAND(e, &oezgan_random_method) || !ENGINE_set_init_function(e, oezgan_init) || !ENGINE_set_digests(e, &oezgan_engine_digest_selector) || !ENGINE_set_ECDH(e, &oezgan_engine_ecdh_method) ) return 0; return 1; }
To be able to test this we need a certificate file and the corresponding private key file. There are many guides in the internet how to generate such certificates and private key pairs. Later on we will need that certificate file to test our ECDSA methods. The test program will now read in a private key file “ownPrivkey.pem” and try to establish an ECDH key with its own public key. The result will be a lot of 3s, exactly as many as the length of the public key. In our certificate file we use a brainpoolP384r1 curve as well as for the ECDH. Beware that the brainpool curves are not supported in OpenSSL versions < 1.0.2. You can use default NIST Curves such as the secp384r1 instead. The following is added to the tester:
//includes #include <openssl/engine.h> #include <openssl/crypto.h> #include <openssl/evp.h> #include <openssl/pem.h> #include <stdio.h> #include <string.h> er = ENGINE_set_default_ECDH(oezgan_engine); printf(" %d\N ",er); FILE* fp = fopen("./ownPrivkey.pem", "r"); if (fp == NULL) { printf( "Could not open private key file\N"); exit(1); } EVP_PKEY *privateKey; privateKey= PEM_read_PrivateKey(fp, NULL, 0, NULL); if ((privateKey) == NULL) { printf("Could not extract private key from file\N"); exit(1); } fclose(fp); EC_KEY *eckey; eckey = EC_KEY_new(); ECDSA_SIG * ecdsa_sig; ecdsa_sig = ECDSA_SIG_new(); eckey = EVP_PKEY_get1_EC_KEY(privateKey); EC_GROUP *ec_group; ec_group = EC_GROUP_new_by_curve_name(NID_brainpoolP384r1); const EC_POINT* pub_key; pub_key = EC_KEY_get0_public_key(eckey); unsigned char agreed_value[200]; EC_KEY *ecdh; ecdh = EC_KEY_new(); EC_KEY_set_group(ecdh, ec_group); er = EC_KEY_set_private_key(ecdh, EC_KEY_get0_private_key(eckey)); int agreed_value_len = ECDH_compute_key(agreed_value, 200,pub_key, ecdh, NULL); printf("Oezgan engine Agreed Value: %d\n",agreed_value_len); for(int i= 0; i < agreed_value_len; i++) { printf("%x", agreed_value[i]); } printf("\n");
Running the tester results in:
oezgan@kehf-dev1:~/workspace3/oezganEngineTester/Debug$ ./oezganEngineTester Oezgan Engine successfully loaded Oezgan Engine Initializatzion! Engine name: oezgan engine by Fraunhofer FKIE init result : 786 oezgan engine random length 5 11111 ENGINE SETTING DEFAULT DIGESTS 1 initialized! SHA256 Digest INIT 1 SHA256 update Digest Update 1 SHA256 final size of EVP_MD: 76 SHA256 cleanup Digest Final 1 Digest size:32 22222222222222222222222222222222 ENGINE SETTING DEFAULT ECDH: 1 Oezgan Engine ECDH Method Oezgan engine ECDH method End returning: 97! Oezgan engine Agreed Value: 97 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
ECDSA[edit]
Now we implement our own ECDSA Algorithm in our engine. Similar to ECDH we need to copy a definition of the ECDSA Method structure. This method structure is found in the crypto/ecdsa/ecs_locl.h file. The Structure:
struct ecdsa_method { const char *name; ECDSA_SIG *(*ecdsa_do_sign) (const unsigned char *dgst, int dgst_len, EC_KEY *eckey); int (*ecdsa_sign_setup) (EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **r); int (*ecdsa_do_verify) (const unsigned char *dgst, int dgst_len, const ECDSA_SIG *sig, EC_KEY *eckey); # if 0 int (*init) (EC_KEY *eckey); int (*finish) (EC_KEY *eckey); # endif int flags; void *app_data; };
We add this declaration into the oezganEngine.h file. The complete .h file is shown below:
#ifndef OEZGANENGINE_H_ #define OEZGANENGINE_H_ #ifdef __cplusplus extern "C" { #endif struct ecdh_method { const char *name; int (*compute_key) (void *key, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh, void *(*KDF) (const void *in, size_t inlen, void *out, size_t *outlen)); # if 0 int (*init) (EC_KEY *eckey); int (*finish) (EC_KEY *eckey); # endif int flags; char *app_data; }; struct ecdsa_method { const char *name; ECDSA_SIG *(*ecdsa_do_sign) (const unsigned char *dgst, int dgst_len, EC_KEY *eckey); int (*ecdsa_sign_setup) (EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **r); int (*ecdsa_do_verify) (const unsigned char *dgst, int dgst_len, const ECDSA_SIG *sig, EC_KEY *eckey); # if 0 int (*init) (EC_KEY *eckey); int (*finish) (EC_KEY *eckey); # endif int flags; void *app_data; };
As we can see the ECDSA method structure needs at least 3 functions, the setup function the signing function and the verifying function. Similar to the ECDH section we define our methods in our oezganEngine.c file:
static ECDSA_METHOD oezgan_engine_ecdsa_method = { "Oezgan engine ECDSA method", oezgan_engine_ecdsa_sign, oezgan_engine_ecdsa_sign_setup, oezgan_engine_ecdsa_do_verify, # if 0 NULL, /* init */ NULL, /* finish */ # endif 0, /* flags */ NULL /* app_data */ }
We also add our signing, verifying and setup functions to the oezganEngine.c file:
int oezgan_engine_ecdsa_sign_setup (EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) { return 1; } static ECDSA_SIG *oezgan_engine_ecdsa_sign (const unsigned char *dgst, int dgst_len, const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *in_eckey) { printf("oezgan engine ecdsa sign digest \n"); unsigned char * out_sig; out_sig = malloc(sizeof(unsigned char)*64); int sig_len = 0; //convert privatekey int pkeyLen = i2d_ECPrivateKey(in_eckey,NULL); const BIGNUM* bignum = EC_KEY_get0_private_key(in_eckey); int pkeyLen; unsigned char *ucBuf, *uctempBuf; pkeyLen = BN_bn2mpi(bignum, NULL); ucBuf = (unsigned char *)malloc(pkeyLen+1); uctempBuf = ucBuf; //Note that this function modifies the uctempBuf as // uctempBuf = uctempBuf + pkeyLen BN_bn2mpi(bignum, uctempBuf); memset(ucBuf,4,pkeyLen); sig_len = pkeyLen; ECDSA_SIG * ret_sig; ret_sig = d2i_ECDSA_SIG(NULL,&out_sig,sig_len); out_sig -= sig_len; return ret_sig; } int oezgan_engine_ecdsa_do_verify (const unsigned char *digest, int digest_len, const ECDSA_SIG *ecdsa_sig, EC_KEY *eckey) { printf("oezgan engine verifying function\n"); int res = 0; int er = 0; //convert ECDSA_SIG to unsigned char int sig_len = i2d_ECDSA_SIG(ecdsa_sig,NULL); unsigned char * sign = malloc(sizeof(unsigned char)*sig_len); er = i2d_ECDSA_SIG(ecdsa_sig,&sign); sign -= sig_len; //convert EC_Key to unsigned char int pubkey_len = i2o_ECPublicKey(eckey,NULL); unsigned char* pubkey = malloc(sizeof(unsigned char)*pubkey_len); er = i2o_ECPublicKey(eckey,&pubkey); pubkey -= er; if(er == 0) { printf("\n Could not convert EC_KEY error:%d\n",er); return er; } res =99; printf("oezgan ecdsa verfiy end! result %d\n",res); return res; }
Our setup function does basically nothing. It always returns 1. You can also use the default implementation of the ECDSA sign setup method located in the file crypto/ecdsa/ecs_ossl.c in the source directory of OpenSSL. We can’t do much in our signing function without a proper signing algorithm, since the return value type ECDSA_SIG needs to be a DER encoded elliptic curve digital signature which consists of a pair (r,s). Therefore our ecdsa implementation returns 0 as the size of the signature and no signature at all. The verifying function always returns 99 independent of the data provided. The conversions in these methods are made for demonstration purposes, to give the reader a rough idea about implementing his or her own algorithms.
List of conversions done:
Finally we modify our bind_helper function again as follows:
int bind_helper(ENGINE * e, const char *id) { if (!ENGINE_set_id(e, engine_oezgan_id) || !ENGINE_set_name(e, engine_oezgan_name) || !ENGINE_set_RAND(e, &oezgan_random_method) || !ENGINE_set_init_function(e, oezgan_init) || !ENGINE_set_digests(e, &oezgan_engine_digest_selector) || !ENGINE_set_ECDH(e, &oezgan_engine_ecdh_method) || !ENGINE_set_ECDSA(e, &oezgan_engine_ecdsa_method) ) return 0; return 1;+ }
To test this we also need a certificate file noted here as “ownCert.pem”. Then we add the following lines to our test program:
er = ENGINE_set_default_ECDSA(oezgan_engine); printf("\nENGINE SETTING DEFAULT ECDSA:%d\n",er); unsigned char *sig = new unsigned char[256]; unsigned int sigsize; ECDSA_sign(0,digest,digestSize,sig,&sigsize,eckey); printf("Signature size:%d \n",sigsize); for(int i=0; i <sigsize;i++) { printf("%x",sig[i]); } printf("\n"); printf("Now verifying!\n"); BIO* bio_in; bio_in = BIO_new_file("./ownCert.pem", "r"); if (bio_in == NULL) { printf("could not read public key file\n"); exit(1); } X509 *certificate; certificate = X509_new(); if (PEM_read_bio_X509(bio_in, &certificate, 0, NULL) == NULL) { printf("could not read certificate from public key file\n"); exit(1); } EVP_PKEY *pubKey; pubKey = X509_get_pubkey(certificate); EC_KEY* eckey_pub; eckey_pub = EVP_PKEY_get1_EC_KEY(pubKey); int result = ECDSA_do_verify(digest, digestSize, ecdsa_sig, eckey_pub); printf("Verify result %d\n", result);
The resulting output is:
oezgan@kehf-dev1:~/workspace3/oezganEngineTester/Debug$ ./oezganEngineTester Oezgan Engine successfully loaded Oezgan Engine Initializatzion! Engine name: oezgan engine by Fraunhofer FKIE init result : 786 oezgan engine random length 5 11111 ENGINE SETTING DEFAULT DIGESTS 1 initialized! SHA256 Digest INIT 1 SHA256 update Digest Update 1 SHA256 final size of EVP_MD: 76 SHA256 cleanup Digest Final 1 Digest size:32 22222222222222222222222222222222 ENGINE SETTING DEFAULT ECDH: 1 ENGINE SETTING DEFAULT ECDSA:1 Oezgan Engine ECDH Method Oezgan engine ECDH method End returning: 97! Oezgan engine Agreed Value: 97 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 oezgan engine ecdsa sign digest 427abc1d0cb9498d5828fc228e3350da674afab9981f5b7c99c5ee1856e83379b89fa6566bf90144f955a2de1973b22138277efd8117e70c636dee84b3592b15b2abf479c7b1fa5db86f35d93fca1d918bbdcf815a82fd44b515cb58942 --- Signature size:0 Now verifying! oezgan engine verifying function oezgan ecdsa verfiy end! result 99 Verify result 99
Note about the ECDSA_METHOD structure[edit]
Instead of putting the definition of the ECDSA_METHOD in the header file we can alternatively use the build-in OpenSSL methods for acquiring the method structure. Actually this is encouraged with OpenSSL versions >= 1.0.2. This is done as follows:
static ECDSA_METHOD *oezgan_engine_ecdsa_method = NULL static int setup_ecdsa_method(void) { oezgan_engine_ecdsa_method = ECDSA_METHOD_new(NULL); if (oezgan_engine_ecdsa_method == NULL) return 0; ECDSA_METHOD_set_name(oezgan_engine_ecdsa_method, "Oezgan engine ECDSA method"); ECDSA_METHOD_set_sign(oezgan_engine_ecdsa_method, oezgan_engine_ecdsa_sign); ECDSA_METHOD_set_sign_setup(oezgan_engine_ecdsa_method, oezgan_engine_ecdsa_sign_setup); ECDSA_METHOD_set_verify(oezgan_engine_ecdsa_method, oezgan_engine_ecdsa_do_verify); return 1; }
and then in the bind_helper we have to do something like this:
int bind_helper(ENGINE * e, const char *id) { if (!ENGINE_set_id(e, engine_oezgan_id) || !ENGINE_set_name(e, engine_oezgan_name) || !setup_ecdsa_method() || !ENGINE_set_ECDSA(e, oezgan_engine_ecdsa_method) ) return 0; return 1; }
This is probably the smoother way to go.
Using C++ Implementations[edit]
In our engine implementation of random generation, sha256, ECDH and ECDSA we used strict C methods. In practice however it is easier to implement elliptic curve functionality in C++; at least this is the author’s perception. Let’s assume that we have some elliptic curve and sha256 implementation in C++. How can we use this implementation as an engine in OpenSSL? Consider the following diagram.
The engine is implemented in pure C; the wrapper which is kind of an interface to the C++ implementation is also implemented in C++. The header of the wrapper provides the engine with the necessary methods to be called; these are declared as extern c functions and have a C method signature. The actual implementations of these extern C functions can include C++ syntax and types. From these functions we use the C++ implementation of the elliptic curve libraries. The wrapper should be compiled a static library together with the elliptic curve C++ implementation.
The engine is implemented in pure C; the wrapper which is kind of an interface to the C++ implementation is also implemented in C++. The header of the wrapper provides the engine with the necessary methods to be called; these are declared as extern c functions and have a C method signature. The actual implementations of these extern C functions can include C++ syntax and types. From these functions we use the C++ implementation of the elliptic curve libraries. The wrapper should be compiled a static library together with the elliptic curve C++ implementation. Here is a simple with the random function. The wrapper.h file:
#ifndef WRAPPER_H_ #define WRAPPER_H_ #ifdef __cplusplus extern "C" { #endif extern void getRandomBytes_C(unsigned char* buffer, int length); #ifdef __cplusplus } #endif #endif /* WRAPPER_H_ */ And the wrapper.c file: #include <stdio.h> #include <string.h> #include <iostream> #include <fstream> #include <vector> #include "wrapper.h" using namespace std; typedef unsigned char byte; typedef std::vector<byte> ByteVector; void getRandomBytes_C(unsigned char* buffer, int numBytes) { string str = "oezgan engine wrapper getRandomBytes C++ method"; cout << str << "\n"; string fileName = "/dev/urandom"; ByteVector result; std::ifstream inFile(fileName.c_str()); std::filebuf* fileBuf = inFile.rdbuf(); result.resize(numBytes); fileBuf->sgetn(reinterpret_cast<char*>(&result[0]), numBytes); inFile.close(); memcpy(buffer,&result[0],numBytes); }
When we modify the Engine.c file as:
//new include #include "wrapper.h" int get_random_bytes(unsigned char *buf, int num) { printf("oezgan engine random length %d\n", num); getRandomBytes_C(buf, num); return 99; }
Note that the engine should be compiled with the
-Wl,-whole-archive -lwrapper -Wl,-no-whole-archive
linker flag, such that the wrapper is completely included in the engine. In eclipse you can define an environment variable for that.
To add the whole archive flag in eclipse you can go to
Project->Properties->C/C++ Build->Enviroment
And add a new environment variable WHOLELIB with the value:
-Wl,-whole-archive -lwrapper -Wl,-no-whole-archive
After that, go to:
Project->Properties->C/C++ Build->Setting->Tool Settings-> GCC C Linker
and add under expert settings at the end of the command line pattern (with an empty space between) ${WHOLELIB}.
Running the tester again results in:
oezgan@kehf-dev1:~/workspace3/oezganEngineTester/Debug$ ./oezganEngineTester Oezgan Engine successfully loaded Oezgan Engine Initializatzion! Engine name: oezgan engine by Fraunhofer FKIE init result : 786 oezgan engine random length 5 oezgan engine wrapper getRandomBytes C++ method dea695abdf …
As you can see the C++ random generation method is used, for other methods you can use a similar approach.
FILES[edit]
Complete source files
oezgan engine:
oezgan engine c++ wrapper:
oezgan engine tester:
Author[edit]
Tolgahan Jonas Oezgan