#include <openssl/obj_mac.h>
#include "e_gost_err.h"
#include "gost_lcl.h"
+#include "gost-engine.h"
#include "gost_grasshopper_cipher.h"
static const char* engine_gost_name =
"Reference implementation of GOST engine";
+const ENGINE_CMD_DEFN gost_cmds[] = {
+ {GOST_CTRL_CRYPT_PARAMS,
+ "CRYPT_PARAMS",
+ "OID of default GOST 28147-89 parameters",
+ ENGINE_CMD_FLAG_STRING},
+ {GOST_CTRL_PBE_PARAMS,
+ "PBE_PARAMS",
+ "Shortname of default digest alg for PBE",
+ ENGINE_CMD_FLAG_STRING},
+ {GOST_CTRL_PK_FORMAT,
+ "GOST_PK_FORMAT",
+ "Private key format params",
+ ENGINE_CMD_FLAG_STRING},
+ {0, NULL, NULL, 0}
+};
+
/* Symmetric cipher and digest function registrar */
static int gost_ciphers(ENGINE* e, const EVP_CIPHER** cipher,
const int** nids, int nid);
static EVP_PKEY_METHOD* pmeth_GostR3410_2001 = NULL,
+ * pmeth_GostR3410_2001DH = NULL,
* pmeth_GostR3410_2012_256 = NULL,
* pmeth_GostR3410_2012_512 = NULL,
* pmeth_Gost28147_MAC = NULL, * pmeth_Gost28147_MAC_12 = NULL,
* pmeth_magma_mac_acpkm = NULL, * pmeth_grasshopper_mac_acpkm = NULL;
static EVP_PKEY_ASN1_METHOD* ameth_GostR3410_2001 = NULL,
+ * ameth_GostR3410_2001DH = NULL,
* ameth_GostR3410_2012_256 = NULL,
* ameth_GostR3410_2012_512 = NULL,
* ameth_Gost28147_MAC = NULL, * ameth_Gost28147_MAC_12 = NULL,
* ameth_magma_mac = NULL, * ameth_grasshopper_mac = NULL,
* ameth_magma_mac_acpkm = NULL, * ameth_grasshopper_mac_acpkm = NULL;
-static struct gost_digest_minfo {
- int nid;
- EVP_MD *(*digest)(void);
- void (*destroy)(void);
- const char *sn;
- const char *alias;
-} gost_digest_array[] = {
- {
- NID_id_GostR3411_94,
- digest_gost,
- digest_gost_destroy,
- },
- {
- NID_id_Gost28147_89_MAC,
- imit_gost_cpa,
- imit_gost_cpa_destroy,
- },
- {
- NID_id_GostR3411_2012_256,
- digest_gost2012_256,
- digest_gost2012_256_destroy,
- SN_id_GostR3411_2012_256,
- "streebog256",
- },
- {
- NID_id_GostR3411_2012_512,
- digest_gost2012_512,
- digest_gost2012_512_destroy,
- SN_id_GostR3411_2012_512,
- "streebog512",
- },
- {
- NID_gost_mac_12,
- imit_gost_cp_12,
- imit_gost_cp_12_destroy,
- },
- {
- NID_magma_mac,
- magma_omac,
- magma_omac_destroy,
- },
- {
- NID_grasshopper_mac,
- grasshopper_omac,
- grasshopper_omac_destroy,
- },
- {
- NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac,
- grasshopper_omac_acpkm,
- grasshopper_omac_acpkm_destroy,
- },
- { 0 },
+GOST_digest *gost_digest_array[] = {
+ &GostR3411_94_digest,
+ &Gost28147_89_MAC_digest,
+ &GostR3411_2012_256_digest,
+ &GostR3411_2012_512_digest,
+ &Gost28147_89_mac_12_digest,
+ &magma_mac_digest,
+ &grasshopper_mac_digest,
+ &kuznyechik_ctracpkm_omac_digest,
};
-static struct gost_cipher_minfo {
- int nid;
- const EVP_CIPHER *(*cipher)(void);
-} gost_cipher_array[] = {
- {
- NID_id_Gost28147_89,
- cipher_gost,
- },
- {
- NID_gost89_cnt,
- cipher_gost_cpacnt,
- },
- {
- NID_gost89_cnt_12,
- cipher_gost_cpcnt_12,
- },
- {
- NID_gost89_cbc,
- cipher_gost_cbc,
- },
- {
- NID_grasshopper_ecb,
- cipher_gost_grasshopper_ecb,
- },
- {
- NID_grasshopper_cbc,
- cipher_gost_grasshopper_cbc,
- },
- {
- NID_grasshopper_cfb,
- cipher_gost_grasshopper_cfb,
- },
- {
- NID_grasshopper_ofb,
- cipher_gost_grasshopper_ofb,
- },
- {
- NID_grasshopper_ctr,
- cipher_gost_grasshopper_ctr,
- },
- {
- NID_magma_cbc,
- cipher_magma_cbc,
- },
- {
- NID_magma_ctr,
- cipher_magma_ctr,
- },
- {
- NID_magma_ctr_acpkm,
- cipher_magma_ctr_acpkm,
- },
- {
- NID_magma_ctr_acpkm_omac,
- cipher_magma_ctr_acpkm_omac,
- },
- {
- NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm,
- cipher_gost_grasshopper_ctracpkm,
- },
- {
- NID_kuznyechik_ctr_acpkm_omac,
- cipher_gost_grasshopper_ctracpkm_omac,
- },
- {
- NID_magma_kexp15,
- cipher_magma_wrap,
- },
- {
- NID_kuznyechik_kexp15,
- cipher_kuznyechik_wrap,
- },
- { 0 },
+GOST_cipher *gost_cipher_array[] = {
+ &Gost28147_89_cipher,
+ &Gost28147_89_cnt_cipher,
+ &Gost28147_89_cnt_12_cipher,
+ &Gost28147_89_cbc_cipher,
+ &grasshopper_ecb_cipher,
+ &grasshopper_cbc_cipher,
+ &grasshopper_cfb_cipher,
+ &grasshopper_ofb_cipher,
+ &grasshopper_ctr_cipher,
+ &magma_ecb_cipher,
+ &grasshopper_mgm_cipher,
+ &magma_cbc_cipher,
+ &magma_ctr_cipher,
+ &magma_ctr_acpkm_cipher,
+ &magma_ctr_acpkm_omac_cipher,
+ &magma_mgm_cipher,
+ &grasshopper_ctr_acpkm_cipher,
+ &grasshopper_ctr_acpkm_omac_cipher,
+ &magma_kexp15_cipher,
+ &kuznyechik_kexp15_cipher,
};
static struct gost_meth_minfo {
"GOST2001",
"GOST R 34.10-2001",
},
+ {
+ NID_id_GostR3410_2001DH,
+ &pmeth_GostR3410_2001DH,
+ &ameth_GostR3410_2001DH,
+ "GOST2001 DH",
+ "GOST R 34.10-2001 DH",
+ },
{
NID_id_Gost28147_89_MAC,
&pmeth_Gost28147_MAC,
NID_grasshopper_mac,
&pmeth_grasshopper_mac,
&ameth_grasshopper_mac,
- "GRASSHOPPER-MAC",
+ "KUZNYECHIK-MAC",
"GOST R 34.13-2015 Grasshopper MAC",
},
{
# define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0]))
#endif
+static int known_digest_nids[OSSL_NELEM(gost_digest_array)];
+static int known_cipher_nids[OSSL_NELEM(gost_cipher_array)];
/* `- 1' because of terminating zero element */
-static int known_digest_nids[OSSL_NELEM(gost_digest_array) - 1];
-static int known_cipher_nids[OSSL_NELEM(gost_cipher_array) - 1];
static int known_meths_nids[OSSL_NELEM(gost_meth_array) - 1];
+/* ENGINE_DIGESTS_PTR callback installed by ENGINE_set_digests */
+static int gost_digests(ENGINE *e, const EVP_MD **digest,
+ const int **nids, int nid)
+{
+ int i;
+
+ if (!digest) {
+ int *n = known_digest_nids;
+
+ *nids = n;
+ for (i = 0; i < OSSL_NELEM(gost_digest_array); i++)
+ *n++ = gost_digest_array[i]->nid;
+ return i;
+ }
+
+ for (i = 0; i < OSSL_NELEM(gost_digest_array); i++)
+ if (nid == gost_digest_array[i]->nid) {
+ *digest = GOST_init_digest(gost_digest_array[i]);
+ return 1;
+ }
+ *digest = NULL;
+ return 0;
+}
+
+/* ENGINE_CIPHERS_PTR callback installed by ENGINE_set_ciphers */
+static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+ const int **nids, int nid)
+{
+ int i;
+
+ if (!cipher) {
+ int *n = known_cipher_nids;
+
+ *nids = n;
+ for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
+ *n++ = gost_cipher_array[i]->nid;
+ return i;
+ }
+
+ for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
+ if (nid == gost_cipher_array[i]->nid) {
+ *cipher = GOST_init_cipher(gost_cipher_array[i]);
+ return 1;
+ }
+ *cipher = NULL;
+ return 0;
+}
+
+static int gost_meth_nids(const int **nids)
+{
+ struct gost_meth_minfo *info = gost_meth_array;
+ int *n = known_meths_nids;
+
+ *nids = n;
+ for (; info->nid; info++)
+ *n++ = info->nid;
+ return OSSL_NELEM(known_meths_nids);
+}
+
+/* ENGINE_PKEY_METHS_PTR installed by ENGINE_set_pkey_meths */
+static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
+ const int **nids, int nid)
+{
+ struct gost_meth_minfo *info;
+
+ if (!pmeth)
+ return gost_meth_nids(nids);
+
+ for (info = gost_meth_array; info->nid; info++)
+ if (nid == info->nid) {
+ *pmeth = *info->pmeth;
+ return 1;
+ }
+ *pmeth = NULL;
+ return 0;
+}
+
+/* ENGINE_PKEY_ASN1_METHS_PTR installed by ENGINE_set_pkey_asn1_meths */
+static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
+ const int **nids, int nid)
+{
+ struct gost_meth_minfo *info;
+
+ if (!ameth)
+ return gost_meth_nids(nids);
+
+ for (info = gost_meth_array; info->nid; info++)
+ if (nid == info->nid) {
+ *ameth = *info->ameth;
+ return 1;
+ }
+ *ameth = NULL;
+ return 0;
+}
+
static int gost_engine_init(ENGINE* e) {
return 1;
}
return 1;
}
+static void free_NIDs();
+
static int gost_engine_destroy(ENGINE* e) {
- struct gost_digest_minfo *dinfo = gost_digest_array;
- for (; dinfo->nid; dinfo++) {
- if (dinfo->alias)
- EVP_delete_digest_alias(dinfo->alias);
- dinfo->destroy();
- }
+ int i;
- cipher_gost_destroy();
- cipher_gost_grasshopper_destroy();
- wrap_ciphers_destroy();
+ for (i = 0; i < OSSL_NELEM(gost_digest_array); i++)
+ GOST_deinit_digest(gost_digest_array[i]);
+ for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++)
+ GOST_deinit_cipher(gost_cipher_array[i]);
gost_param_free();
*minfo->ameth = NULL;
}
+ free_cached_groups();
+ free_NIDs();
+
+# ifndef BUILDING_GOST_PROVIDER
ERR_unload_GOST_strings();
+# endif
return 1;
}
-static int bind_gost(ENGINE* e, const char* id) {
+/*
+ * Following is the glue that populates the ENGINE structure and that
+ * binds it to OpenSSL libraries
+ */
+
+static GOST_NID_JOB *missing_NIDs[] = {
+ &kuznyechik_mgm_NID,
+ &magma_mgm_NID,
+};
+
+static int create_NIDs() {
+ int i;
+ int new_nid = OBJ_new_nid(OSSL_NELEM(missing_NIDs));
+ for (i = 0; i < OSSL_NELEM(missing_NIDs); i++) {
+ GOST_NID_JOB *job = missing_NIDs[i];
+ ASN1_OBJECT *obj =
+ ASN1_OBJECT_create(new_nid + i, NULL, 0, job->sn, job->ln);
+ job->asn1 = obj;
+ if (!obj || OBJ_add_object(obj) == NID_undef) {
+ OPENSSL_free(obj);
+ return 0;
+ }
+ (*missing_NIDs[i]->callback)(new_nid + i);
+ }
+ return 1;
+}
+
+static void free_NIDs() {
+ int i;
+ for (i = 0; i < OSSL_NELEM(missing_NIDs); i++) {
+ ASN1_OBJECT_free(missing_NIDs[i]->asn1);
+ }
+}
+
+# ifndef BUILDING_GOST_PROVIDER
+static
+# endif
+int populate_gost_engine(ENGINE* e) {
int ret = 0;
- if (id != NULL && strcmp(id, engine_gost_id) != 0)
- return 0;
- if (ameth_GostR3410_2001) {
- printf("GOST engine already loaded\n");
+
+ if (e == NULL)
goto end;
- }
if (!ENGINE_set_id(e, engine_gost_id)) {
- printf("ENGINE_set_id failed\n");
+ fprintf(stderr, "ENGINE_set_id failed\n");
goto end;
}
if (!ENGINE_set_name(e, engine_gost_name)) {
- printf("ENGINE_set_name failed\n");
+ fprintf(stderr, "ENGINE_set_name failed\n");
+ goto end;
+ }
+ if (!create_NIDs()) {
+ fprintf(stderr, "NID creation failed\n");
goto end;
}
if (!ENGINE_set_digests(e, gost_digests)) {
- printf("ENGINE_set_digests failed\n");
+ fprintf(stderr, "ENGINE_set_digests failed\n");
goto end;
}
if (!ENGINE_set_ciphers(e, gost_ciphers)) {
- printf("ENGINE_set_ciphers failed\n");
+ fprintf(stderr, "ENGINE_set_ciphers failed\n");
goto end;
}
if (!ENGINE_set_pkey_meths(e, gost_pkey_meths)) {
- printf("ENGINE_set_pkey_meths failed\n");
+ fprintf(stderr, "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");
+ fprintf(stderr, "ENGINE_set_pkey_asn1_meths failed\n");
goto end;
}
/* Control function and commands */
goto end;
}
+ /*
+ * "register" in "register_ameth_gost" and "register_pmeth_gost" is
+ * not registering in an ENGINE sense, where things are hooked into
+ * OpenSSL's library. "register_ameth_gost" and "register_pmeth_gost"
+ * merely allocate and populate the method structures of this engine.
+ */
struct gost_meth_minfo *minfo = gost_meth_array;
for (; minfo->nid; minfo++) {
goto end;
}
+ ret = 1;
+ end:
+ return ret;
+}
+
+#ifndef BUILDING_GOST_PROVIDER
+static int bind_gost_engine(ENGINE* e) {
+ int ret = 0;
+
if (!ENGINE_register_ciphers(e)
|| !ENGINE_register_digests(e)
|| !ENGINE_register_pkey_meths(e))
goto end;
- struct gost_cipher_minfo *cinfo = gost_cipher_array;
- for (; cinfo->nid; cinfo++)
- if (!EVP_add_cipher(cinfo->cipher()))
+ int i;
+ for (i = 0; i < OSSL_NELEM(gost_cipher_array); i++) {
+ if (!EVP_add_cipher(GOST_init_cipher(gost_cipher_array[i])))
goto end;
+ }
- struct gost_digest_minfo *dinfo = gost_digest_array;
- for (; dinfo->nid; dinfo++) {
- if (!EVP_add_digest(dinfo->digest()))
- goto end;
- if (dinfo->alias &&
- !EVP_add_digest_alias(dinfo->sn, dinfo->alias))
+ for (i = 0; i < OSSL_NELEM(gost_digest_array); i++) {
+ if (!EVP_add_digest(GOST_init_digest(gost_digest_array[i])))
goto end;
}
ERR_load_GOST_strings();
ret = 1;
- end:
+ end:
return ret;
}
-#ifndef OPENSSL_NO_DYNAMIC_ENGINE
-IMPLEMENT_DYNAMIC_BIND_FN(bind_gost)
- IMPLEMENT_DYNAMIC_CHECK_FN()
-#endif /* ndef OPENSSL_NO_DYNAMIC_ENGINE */
-
-/* ENGINE_DIGESTS_PTR callback installed by ENGINE_set_digests */
-static int gost_digests(ENGINE *e, const EVP_MD **digest,
- const int **nids, int nid)
+static int check_gost_engine(ENGINE* e, const char* id)
{
- struct gost_digest_minfo *info = gost_digest_array;
-
- if (!digest) {
- int *n = known_digest_nids;
-
- *nids = n;
- for (; info->nid; info++)
- *n++ = info->nid;
- return OSSL_NELEM(known_digest_nids);
- }
-
- for (; info->nid; info++)
- if (nid == info->nid) {
- *digest = info->digest();
- return 1;
- }
- *digest = NULL;
- return 0;
-}
-
-/* ENGINE_CIPHERS_PTR callback installed by ENGINE_set_ciphers */
-static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
- const int **nids, int nid)
-{
- struct gost_cipher_minfo *info = gost_cipher_array;
-
- if (!cipher) {
- int *n = known_cipher_nids;
-
- *nids = n;
- for (; info->nid; info++)
- *n++ = info->nid;
- return OSSL_NELEM(known_cipher_nids);
+ if (id != NULL && strcmp(id, engine_gost_id) != 0)
+ return 0;
+ if (ameth_GostR3410_2001) {
+ printf("GOST engine already loaded\n");
+ return 0;
}
-
- for (; info->nid; info++)
- if (nid == info->nid) {
- *cipher = info->cipher();
- return 1;
- }
- *cipher = NULL;
- return 0;
-}
-
-static int gost_meth_nids(const int **nids)
-{
- struct gost_meth_minfo *info = gost_meth_array;
- int *n = known_meths_nids;
-
- *nids = n;
- for (; info->nid; info++)
- *n++ = info->nid;
- return OSSL_NELEM(known_meths_nids);
+ return 1;
}
-/* ENGINE_PKEY_METHS_PTR installed by ENGINE_set_pkey_meths */
-static int gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth,
- const int **nids, int nid)
+static int make_gost_engine(ENGINE* e, const char* id)
{
- struct gost_meth_minfo *info;
-
- if (!pmeth)
- return gost_meth_nids(nids);
-
- for (info = gost_meth_array; info->nid; info++)
- if (nid == info->nid) {
- *pmeth = *info->pmeth;
- return 1;
- }
- *pmeth = NULL;
- return 0;
+ return check_gost_engine(e, id)
+ && populate_gost_engine(e)
+ && bind_gost_engine(e);
}
-/* ENGINE_PKEY_ASN1_METHS_PTR installed by ENGINE_set_pkey_asn1_meths */
-static int gost_pkey_asn1_meths(ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth,
- const int **nids, int nid)
-{
- struct gost_meth_minfo *info;
+#ifndef BUILDING_ENGINE_AS_LIBRARY
- if (!ameth)
- return gost_meth_nids(nids);
+/*
+ * When building gost-engine as a dynamically loadable module, these two
+ * lines do everything that's needed, and OpenSSL's libcrypto will be able
+ * to call its entry points, v_check and bind_engine.
+ */
- for (info = gost_meth_array; info->nid; info++)
- if (nid == info->nid) {
- *ameth = *info->ameth;
- return 1;
- }
- *ameth = NULL;
- return 0;
-}
+IMPLEMENT_DYNAMIC_BIND_FN(make_gost_engine)
+IMPLEMENT_DYNAMIC_CHECK_FN()
-#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;
-}
+#else
+/*
+ * When building gost-engine as a shared library, the application that uses
+ * it must manually call ENGINE_load_gost() for it to bind itself into the
+ * libcrypto libraries.
+ */
void ENGINE_load_gost(void) {
ENGINE* toadd;
- if (pmeth_GostR3410_2001)
- return;
- toadd = engine_gost();
- if (!toadd)
- return;
- ENGINE_add(toadd);
+ int ret = 0;
+
+ if ((toadd = ENGINE_new()) != NULL
+ && (ret = make_gost_engine(toadd, engine_gost_id)) > 0)
+ ENGINE_add(toadd);
ENGINE_free(toadd);
- ERR_clear_error();
+ if (ret > 0)
+ ERR_clear_error();
}
-
#endif
+#endif
+/* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */