Files
GmSSL/engines/zeromem/cba_ecdh_engine.c
2017-03-23 20:50:15 +08:00

266 lines
6.1 KiB
C
Executable File

#include <stdio.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/dso.h>
#include <openssl/engine.h>
#include <openssl/ui.h>
#include <openssl/rand.h>
#ifndef OPENSSL_NO_RSA
#include <openssl/rsa.h>
#endif
#include <openssl/bn.h>
#include <openssl/ecdh.h>
#include "ec2m_kern.h"
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));
int flags;
char *app_data;
};
#ifndef OPENSSL_NO_HW
/* the header file of vender */
//#include "hwdevice.h"
/* Constants used when creating the ENGINE */
static const char *engine_hwdev_id = "cba_ecdh";
static const char *engine_hwdev_name = "cold boot resistant ECDH";
#ifndef OPENSSL_NO_DYNAMIC_ENGINE
/* Compatibility hack, the dynamic library uses this form in the path */
static const char *engine_hwdev_id_alt = "cba_ecdh";
#endif
static int compute_key(void *out, size_t outlen,
const EC_POINT *pub_key, EC_KEY *ecdh,
void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen))
{
const EC_GROUP* group;
int ret;
group = EC_KEY_get0_group(ecdh);
// only use our solution if the curve name is SECT163K1
if (EC_GROUP_get_curve_name(group) == NID_sect163k1) {
const BIGNUM* rkey;
BN_CTX *ctx;
BIGNUM* x, *y;
mm256_point_t p, q;
mm_256 mkey;
int r;
ctx = BN_CTX_new();
BN_CTX_start(ctx);
x = BN_CTX_get(ctx);
y = BN_CTX_get(ctx);
rkey = EC_KEY_get0_private_key(ecdh);
memset(&mkey, 0, sizeof(mkey));
memcpy(&mkey, rkey->d, sizeof(rkey->d[0]) * rkey->top);
ec2m_import_key(&mkey);
r = EC_POINT_get_affine_coordinates_GF2m(group, pub_key, x, y, ctx);
memset(&p, 0, sizeof(p));
memcpy(&p.x, x->d, sizeof(x->d[0]) * x->top);
memcpy(&p.y, y->d, sizeof(y->d[0]) * y->top);
p.z.iv[0] = 1;
r = ec2m_private_operation(&p, &q);
if (r < 0) {
fprintf(stderr, "invalid result: %d\n", r);
}
int xlen = (163 + 7) / 8;
if (KDF != 0)
{
if (KDF(&q.x, xlen, out, &outlen) == NULL)
{
return -1;
}
ret = outlen;
}
else
{
/* no KDF, just copy as much as we can */
if (outlen > xlen)
outlen = xlen;
memcpy(out, &q.x, outlen);
ret = outlen;
}
BN_CTX_end(ctx);
BN_CTX_free(ctx);
} else {
// use the default method
const ECDH_METHOD* meth = ECDH_OpenSSL();
return meth->compute_key(out, outlen, pub_key, ecdh, KDF);
}
return ret;
}
static ECDH_METHOD ecdh_meth = {
"CBA resistant ECDH method",
compute_key,
0,
NULL
};
static int hwdev_destroy(ENGINE *e)
{
fprintf(stderr, "arrive at hwdev_destroy\n");
return 1;
}
static int hwdev_init(ENGINE *e)
{
fprintf(stderr, "arrive at hwdev_init\n");
ec2m_kern_init();
return 1;
}
static int hwdev_finish(ENGINE *e)
{
fprintf(stderr, "arrive at hwdev_finish\n");
ec2m_kern_clean();
return 1;
}
/* The definitions for control commands specific to this engine */
#define HWDEV_CMD_INIT (ENGINE_CMD_BASE)
#define HWDEV_CMD_EXIT (ENGINE_CMD_BASE + 1)
#define HWDEV_CMD_TEST (ENGINE_CMD_BASE + 2)
static const ENGINE_CMD_DEFN hwdev_cmd_defns[] = {
{HWDEV_CMD_INIT,
"INIT",
"init the hardware device before using",
ENGINE_CMD_FLAG_STRING}, /* may be the password */
{HWDEV_CMD_EXIT,
"EXIT",
"exit the hardware device after using",
ENGINE_CMD_FLAG_NO_INPUT},
{HWDEV_CMD_TEST,
"TEST",
"run the test case of the hardware device",
ENGINE_CMD_FLAG_NUMERIC}, /* may be the number of test case */
{0, NULL, NULL, 0}
};
/* This internal function is used by ENGINE_chil() and possibly by the
* "dynamic" ENGINE support too */
static int hwdev_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
{
int to_return = 1;
switch(cmd) {
case HWDEV_CMD_INIT:
fprintf(stderr, "arrive at HWDEV_CMD_INIT, password: %s\n",
(const char *)p);
break;
case HWDEV_CMD_EXIT:
fprintf(stderr, "arrive at HWDEV_CMD_EXIT, no parameters\n");
break;
case HWDEV_CMD_TEST:
fprintf(stderr, "arrive at HWDEV_CMD_TEST, case id: %ld\n",
i);
break;
/* The command isn't understood by this engine */
default:
to_return = 0;
break;
}
return to_return;
}
static EVP_PKEY *hwdev_load_privkey(ENGINE *eng, const char *key_id,
UI_METHOD *ui_method, void *callback_data)
{
fprintf(stderr, "arrive at hwdev_load_privkey\n");
EVP_PKEY *res = NULL;
return res;
}
static EVP_PKEY *hwdev_load_pubkey(ENGINE *eng, const char *key_id,
UI_METHOD *ui_method, void *callback_data)
{
fprintf(stderr, "arrive at hwdev_load_pubkey\n");
EVP_PKEY *res = NULL;
return res;
}
static int bind_helper(ENGINE *e)
{
fprintf(stderr, "arrive at bind_helper\n");
if(!ENGINE_set_id(e, engine_hwdev_id) ||
!ENGINE_set_name(e, engine_hwdev_name) ||
!ENGINE_set_ECDH(e, &ecdh_meth) ||
!ENGINE_set_destroy_function(e, hwdev_destroy) ||
!ENGINE_set_init_function(e, hwdev_init) ||
!ENGINE_set_finish_function(e, hwdev_finish) ||
!ENGINE_set_ctrl_function(e, hwdev_ctrl) ||
!ENGINE_set_load_privkey_function(e, hwdev_load_privkey) ||
!ENGINE_set_load_pubkey_function(e, hwdev_load_pubkey) ||
!ENGINE_set_cmd_defns(e, hwdev_cmd_defns))
return 0;
return 1;
}
static ENGINE *engine_hwdev(void)
{
fprintf(stderr, "arrive at engine_test\n");
ENGINE *ret = ENGINE_new();
if(!ret) {
return NULL;
}
if(!bind_helper(ret)) {
ENGINE_free(ret);
return NULL;
}
return ret;
}
void ENGINE_load_test(void)
{
fprintf(stderr, "arrive at ENGINE_load_test\n");
/* Copied from eng_[openssl|dyn].c */
ENGINE *toadd = engine_hwdev();
if(!toadd) return;
ENGINE_add(toadd);
ENGINE_free(toadd);
ERR_clear_error();
}
//#endif
/* This stuff is needed if this ENGINE is being compiled into a self-contained
* shared-library. */
#ifndef OPENSSL_NO_DYNAMIC_ENGINE
static int bind_fn(ENGINE *e, const char *id)
{
fprintf(stderr, "arrive at bind_fn\n");
if(id && (strcmp(id, engine_hwdev_id) != 0) &&
(strcmp(id, engine_hwdev_id_alt) != 0))
return 0;
if(!bind_helper(e))
return 0;
return 1;
}
IMPLEMENT_DYNAMIC_CHECK_FN()
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
#endif /* OPENSSL_NO_DYNAMIC_ENGINE */
#endif /* !OPENSSL_NO_HW */