| /********************************************************************** |
| * gost_eng.c * |
| * Copyright (c) 2005-2006 Cryptocom LTD * |
| * This file is distributed under the same license as OpenSSL * |
| * * |
| * Main file of GOST engine * |
| * for OpenSSL * |
| * Requires OpenSSL 0.9.9 for compilation * |
| **********************************************************************/ |
| #include <string.h> |
| #include <openssl/crypto.h> |
| #include <openssl/err.h> |
| #include <openssl/evp.h> |
| #include <openssl/engine.h> |
| #include <openssl/obj_mac.h> |
| #include "e_gost_err.h" |
| #include "gost_lcl.h" |
| static const char *engine_gost_id = "gost"; |
| static const char *engine_gost_name = |
| "Reference implementation of GOST engine"; |
| |
| /* Symmetric cipher and digest function registrar */ |
| |
| static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher, |
| const int **nids, int nid); |
| |
| static int gost_digests(ENGINE *e, const EVP_MD **digest, |
| const int **nids, int ind); |
| |
| static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth, |
| const int **nids, int nid); |
| |
| static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth, |
| const int **nids, int nid); |
| |
| static int gost_cipher_nids[] = { NID_id_Gost28147_89, NID_gost89_cnt, 0 }; |
| |
| static int gost_digest_nids[] = |
| { NID_id_GostR3411_94, NID_id_Gost28147_89_MAC, 0 }; |
| |
| static int gost_pkey_meth_nids[] = { NID_id_GostR3410_94, |
| NID_id_GostR3410_2001, NID_id_Gost28147_89_MAC, 0 |
| }; |
| |
| static EVP_PKEY_METHOD *pmeth_GostR3410_94 = NULL, |
| *pmeth_GostR3410_2001 = NULL, *pmeth_Gost28147_MAC = NULL; |
| |
| static EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94 = NULL, |
| *ameth_GostR3410_2001 = NULL, *ameth_Gost28147_MAC = NULL; |
| |
| static int gost_engine_init(ENGINE *e) |
| { |
| return 1; |
| } |
| |
| static int gost_engine_finish(ENGINE *e) |
| { |
| return 1; |
| } |
| |
| static int gost_engine_destroy(ENGINE *e) |
| { |
| gost_param_free(); |
| |
| pmeth_GostR3410_94 = NULL; |
| pmeth_GostR3410_2001 = NULL; |
| pmeth_Gost28147_MAC = NULL; |
| ameth_GostR3410_94 = NULL; |
| ameth_GostR3410_2001 = NULL; |
| ameth_Gost28147_MAC = NULL; |
| return 1; |
| } |
| |
| static int bind_gost(ENGINE *e, const char *id) |
| { |
| int ret = 0; |
| if (id && strcmp(id, engine_gost_id)) |
| return 0; |
| if (ameth_GostR3410_94) { |
| printf("GOST engine already loaded\n"); |
| goto end; |
| } |
| |
| if (!ENGINE_set_id(e, engine_gost_id)) { |
| printf("ENGINE_set_id failed\n"); |
| goto end; |
| } |
| if (!ENGINE_set_name(e, engine_gost_name)) { |
| printf("ENGINE_set_name failed\n"); |
| goto end; |
| } |
| if (!ENGINE_set_digests(e, gost_digests)) { |
| printf("ENGINE_set_digests failed\n"); |
| goto end; |
| } |
| if (!ENGINE_set_ciphers(e, gost_ciphers)) { |
| printf("ENGINE_set_ciphers failed\n"); |
| goto end; |
| } |
| if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) { |
| printf("ENGINE_set_pkey_meths failed\n"); |
| goto end; |
| } |
| if (!ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) { |
| printf("ENGINE_set_pkey_asn1_meths failed\n"); |
| goto end; |
| } |
| /* Control function and commands */ |
| if (!ENGINE_set_cmd_defns(e, gost_cmds)) { |
| fprintf(stderr, "ENGINE_set_cmd_defns failed\n"); |
| goto end; |
| } |
| if (!ENGINE_set_ctrl_function(e, gost_control_func)) { |
| fprintf(stderr, "ENGINE_set_ctrl_func failed\n"); |
| goto end; |
| } |
| if (!ENGINE_set_destroy_function(e, gost_engine_destroy) |
| || !ENGINE_set_init_function(e, gost_engine_init) |
| || !ENGINE_set_finish_function(e, gost_engine_finish)) { |
| goto end; |
| } |
| |
| if (!register_ameth_gost |
| (NID_id_GostR3410_94, &ameth_GostR3410_94, "GOST94", |
| "GOST R 34.10-94")) |
| goto end; |
| if (!register_ameth_gost |
| (NID_id_GostR3410_2001, &ameth_GostR3410_2001, "GOST2001", |
| "GOST R 34.10-2001")) |
| goto end; |
| if (!register_ameth_gost(NID_id_Gost28147_89_MAC, &ameth_Gost28147_MAC, |
| "GOST-MAC", "GOST 28147-89 MAC")) |
| goto end; |
| |
| if (!register_pmeth_gost(NID_id_GostR3410_94, &pmeth_GostR3410_94, 0)) |
| goto end; |
| if (!register_pmeth_gost(NID_id_GostR3410_2001, &pmeth_GostR3410_2001, 0)) |
| goto end; |
| if (!register_pmeth_gost |
| (NID_id_Gost28147_89_MAC, &pmeth_Gost28147_MAC, 0)) |
| goto end; |
| if (!ENGINE_register_ciphers(e) |
| || !ENGINE_register_digests(e) |
| || !ENGINE_register_pkey_meths(e) |
| /* These two actually should go in LIST_ADD command */ |
| || !EVP_add_cipher(&cipher_gost) |
| || !EVP_add_cipher(&cipher_gost_cpacnt) |
| || !EVP_add_digest(&digest_gost) |
| || !EVP_add_digest(&imit_gost_cpa) |
| ) { |
| goto end; |
| } |
| |
| ERR_load_GOST_strings(); |
| ret = 1; |
| end: |
| return ret; |
| } |
| |
| #ifndef OPENSSL_NO_DYNAMIC_ENGINE |
| IMPLEMENT_DYNAMIC_BIND_FN(bind_gost) |
| IMPLEMENT_DYNAMIC_CHECK_FN() |
| #endif /* ndef OPENSSL_NO_DYNAMIC_ENGINE */ |
| static int gost_digests(ENGINE *e, const EVP_MD **digest, |
| const int **nids, int nid) |
| { |
| int ok = 1; |
| if (!digest) { |
| *nids = gost_digest_nids; |
| return 2; |
| } |
| /* |
| * printf("Digest no %d requested\n",nid); |
| */ |
| if (nid == NID_id_GostR3411_94) { |
| *digest = &digest_gost; |
| } else if (nid == NID_id_Gost28147_89_MAC) { |
| *digest = &imit_gost_cpa; |
| } else { |
| ok = 0; |
| *digest = NULL; |
| } |
| return ok; |
| } |
| |
| static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher, |
| const int **nids, int nid) |
| { |
| int ok = 1; |
| if (!cipher) { |
| *nids = gost_cipher_nids; |
| return 2; /* two ciphers are supported */ |
| } |
| |
| if (nid == NID_id_Gost28147_89) { |
| *cipher = &cipher_gost; |
| } else if (nid == NID_gost89_cnt) { |
| *cipher = &cipher_gost_cpacnt; |
| } else { |
| ok = 0; |
| *cipher = NULL; |
| } |
| return ok; |
| } |
| |
| static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth, |
| const int **nids, int nid) |
| { |
| if (!pmeth) { |
| *nids = gost_pkey_meth_nids; |
| return 3; |
| } |
| |
| switch (nid) { |
| case NID_id_GostR3410_94: |
| *pmeth = pmeth_GostR3410_94; |
| return 1; |
| case NID_id_GostR3410_2001: |
| *pmeth = pmeth_GostR3410_2001; |
| return 1; |
| case NID_id_Gost28147_89_MAC: |
| *pmeth = pmeth_Gost28147_MAC; |
| return 1; |
| default:; |
| } |
| |
| *pmeth = NULL; |
| return 0; |
| } |
| |
| static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth, |
| const int **nids, int nid) |
| { |
| if (!ameth) { |
| *nids = gost_pkey_meth_nids; |
| return 3; |
| } |
| switch (nid) { |
| case NID_id_GostR3410_94: |
| *ameth = ameth_GostR3410_94; |
| return 1; |
| case NID_id_GostR3410_2001: |
| *ameth = ameth_GostR3410_2001; |
| return 1; |
| case NID_id_Gost28147_89_MAC: |
| *ameth = ameth_Gost28147_MAC; |
| return 1; |
| |
| default:; |
| } |
| |
| *ameth = NULL; |
| return 0; |
| } |
| |
| #ifdef OPENSSL_NO_DYNAMIC_ENGINE |
| static ENGINE *engine_gost(void) |
| { |
| ENGINE *ret = ENGINE_new(); |
| if (!ret) |
| return NULL; |
| if (!bind_gost(ret, engine_gost_id)) { |
| ENGINE_free(ret); |
| return NULL; |
| } |
| return ret; |
| } |
| |
| void ENGINE_load_gost(void) |
| { |
| ENGINE *toadd; |
| if (pmeth_GostR3410_94) |
| return; |
| toadd = engine_gost(); |
| if (!toadd) |
| return; |
| ENGINE_add(toadd); |
| ENGINE_free(toadd); |
| ERR_clear_error(); |
| } |
| #endif |