1/**********************************************************************
2 *                          gost_pmeth.c                              *
3 *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4 *         This file is distributed under the same license as OpenSSL *
5 *                                                                    *
6 *   Implementation of RFC 4357 (GOST R 34.10) Publick key method     *
7 *       for OpenSSL                                                  *
8 *          Requires OpenSSL 0.9.9 for compilation                    *
9 **********************************************************************/
10#include <openssl/evp.h>
11#include <openssl/objects.h>
12#include <openssl/ec.h>
13#include <openssl/x509v3.h> /*For string_to_hex */
14#include <stdlib.h>
15#include <string.h>
16#include <ctype.h>
17#include "gost_params.h"
18#include "gost_lcl.h"
19#include "e_gost_err.h"
20/*-------init, cleanup, copy - uniform for all algs  ---------------*/
21/* Allocates new gost_pmeth_data structure and assigns it as data */
22static int pkey_gost_init(EVP_PKEY_CTX *ctx)
23	{
24	struct gost_pmeth_data *data;
25	EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
26	data = OPENSSL_malloc(sizeof(struct gost_pmeth_data));
27	if (!data) return 0;
28	memset(data,0,sizeof(struct gost_pmeth_data));
29	if (pkey && EVP_PKEY_get0(pkey))
30		{
31		switch (EVP_PKEY_base_id(pkey)) {
32		case NID_id_GostR3410_94:
33		  data->sign_param_nid = gost94_nid_by_params(EVP_PKEY_get0(pkey));
34		  break;
35		case NID_id_GostR3410_2001:
36		   data->sign_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)pkey)));
37		break;
38		default:
39			return 0;
40		}
41		}
42	EVP_PKEY_CTX_set_data(ctx,data);
43	return 1;
44	}
45
46/* Copies contents of gost_pmeth_data structure */
47static int pkey_gost_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
48	{
49	struct gost_pmeth_data *dst_data,*src_data;
50	if (!pkey_gost_init(dst))
51		{
52		return 0;
53		}
54	src_data = EVP_PKEY_CTX_get_data(src);
55	dst_data = EVP_PKEY_CTX_get_data(dst);
56	*dst_data = *src_data;
57	if (src_data -> shared_ukm) {
58		dst_data->shared_ukm=NULL;
59	}
60	return 1;
61	}
62
63/* Frees up gost_pmeth_data structure */
64static void pkey_gost_cleanup (EVP_PKEY_CTX *ctx)
65	{
66	struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
67	if (data->shared_ukm) OPENSSL_free(data->shared_ukm);
68	OPENSSL_free(data);
69	}
70
71/* --------------------- control functions  ------------------------------*/
72static int pkey_gost_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
73	{
74	struct gost_pmeth_data *pctx = (struct gost_pmeth_data*)EVP_PKEY_CTX_get_data(ctx);
75	switch (type)
76		{
77		case EVP_PKEY_CTRL_MD:
78		{
79		if (EVP_MD_type((const EVP_MD *)p2) != NID_id_GostR3411_94)
80			{
81			GOSTerr(GOST_F_PKEY_GOST_CTRL, GOST_R_INVALID_DIGEST_TYPE);
82			return 0;
83			}
84		pctx->md = (EVP_MD *)p2;
85		return 1;
86		}
87		break;
88
89		case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
90		case EVP_PKEY_CTRL_PKCS7_DECRYPT:
91		case EVP_PKEY_CTRL_PKCS7_SIGN:
92			return 1;
93
94		case EVP_PKEY_CTRL_GOST_PARAMSET:
95			pctx->sign_param_nid = (int)p1;
96			return 1;
97		case EVP_PKEY_CTRL_SET_IV:
98			pctx->shared_ukm=OPENSSL_malloc((int)p1);
99			memcpy(pctx->shared_ukm,p2,(int) p1);
100			return 1;
101		case EVP_PKEY_CTRL_PEER_KEY:
102			if (p1 == 0 || p1 == 1) /* call from EVP_PKEY_derive_set_peer */
103				return 1;
104			if (p1 == 2)		/* TLS: peer key used? */
105				return pctx->peer_key_used;
106			if (p1 == 3)		/* TLS: peer key used! */
107				return (pctx->peer_key_used = 1);
108			return -2;
109		}
110	return -2;
111	}
112
113
114static int pkey_gost_ctrl94_str(EVP_PKEY_CTX *ctx,
115	const char *type, const char *value)
116	{
117	int param_nid=0;
118	if(!strcmp(type, param_ctrl_string))
119		{
120		if (!value)
121			{
122			return 0;
123			}
124		if (strlen(value) == 1)
125			{
126			switch(toupper(value[0]))
127				{
128				case 'A':
129					param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet;
130					break;
131				case 'B':
132					param_nid = NID_id_GostR3410_94_CryptoPro_B_ParamSet;
133					break;
134				case 'C':
135					param_nid = NID_id_GostR3410_94_CryptoPro_C_ParamSet;
136					break;
137				case 'D':
138					param_nid = NID_id_GostR3410_94_CryptoPro_D_ParamSet;
139					break;
140				default:
141					return 0;
142					break;
143				}
144			}
145		else if ((strlen(value) == 2) && (toupper(value[0]) == 'X'))
146			{
147			switch (toupper(value[1]))
148				{
149				case 'A':
150					param_nid = NID_id_GostR3410_94_CryptoPro_XchA_ParamSet;
151					break;
152				case 'B':
153					param_nid = NID_id_GostR3410_94_CryptoPro_XchB_ParamSet;
154					break;
155				case 'C':
156					param_nid = NID_id_GostR3410_94_CryptoPro_XchC_ParamSet;
157					break;
158				default:
159					return 0;
160					break;
161				}
162			}
163		else
164			{
165			R3410_params *p = R3410_paramset;
166			param_nid = OBJ_txt2nid(value);
167			if (param_nid == NID_undef)
168				{
169				return 0;
170				}
171			for (;p->nid != NID_undef;p++)
172				{
173				if (p->nid == param_nid) break;
174				}
175			if (p->nid == NID_undef)
176				{
177				GOSTerr(GOST_F_PKEY_GOST_CTRL94_STR,
178					GOST_R_INVALID_PARAMSET);
179				return 0;
180				}
181			}
182
183		return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
184			param_nid, NULL);
185		}
186	return -2;
187	}
188
189static int pkey_gost_ctrl01_str(EVP_PKEY_CTX *ctx,
190	const char *type, const char *value)
191	{
192	int param_nid=0;
193	if(!strcmp(type, param_ctrl_string))
194		{
195		if (!value)
196			{
197			return 0;
198			}
199		if (strlen(value) == 1)
200			{
201			switch(toupper(value[0]))
202				{
203				case 'A':
204					param_nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet;
205					break;
206				case 'B':
207					param_nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet;
208					break;
209				case 'C':
210					param_nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet;
211					break;
212				case '0':
213					param_nid = NID_id_GostR3410_2001_TestParamSet;
214					break;
215				default:
216					return 0;
217					break;
218				}
219			}
220		else if ((strlen(value) == 2) && (toupper(value[0]) == 'X'))
221			{
222			switch (toupper(value[1]))
223				{
224				case 'A':
225					param_nid = NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet;
226					break;
227				case 'B':
228					param_nid = NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet;
229					break;
230				default:
231					return 0;
232					break;
233				}
234			}
235		else
236			{
237			R3410_2001_params *p = R3410_2001_paramset;
238			param_nid = OBJ_txt2nid(value);
239			if (param_nid == NID_undef)
240				{
241				return 0;
242				}
243			for (;p->nid != NID_undef;p++)
244				{
245				if (p->nid == param_nid) break;
246				}
247			if (p->nid == NID_undef)
248				{
249				GOSTerr(GOST_F_PKEY_GOST_CTRL01_STR,
250					GOST_R_INVALID_PARAMSET);
251				return 0;
252				}
253			}
254
255		return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
256			param_nid, NULL);
257		}
258	return -2;
259	}
260
261/* --------------------- key generation  --------------------------------*/
262
263static int pkey_gost_paramgen_init(EVP_PKEY_CTX *ctx) {
264	return 1;
265}
266static int pkey_gost94_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
267	{
268	struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
269	DSA *dsa=NULL;
270	if (data->sign_param_nid == NID_undef)
271		{
272			GOSTerr(GOST_F_PKEY_GOST94_PARAMGEN,
273				GOST_R_NO_PARAMETERS_SET);
274			return 0;
275		}
276	dsa = DSA_new();
277	if (!fill_GOST94_params(dsa,data->sign_param_nid))
278		{
279		DSA_free(dsa);
280		return 0;
281		}
282	EVP_PKEY_assign(pkey,NID_id_GostR3410_94,dsa);
283	return 1;
284	}
285static int pkey_gost01_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
286	{
287	struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
288	EC_KEY *ec=NULL;
289
290	if (data->sign_param_nid == NID_undef)
291		{
292			GOSTerr(GOST_F_PKEY_GOST01_PARAMGEN,
293				GOST_R_NO_PARAMETERS_SET);
294			return 0;
295		}
296	if (!ec)
297		ec = EC_KEY_new();
298	if (!fill_GOST2001_params(ec,data->sign_param_nid))
299		{
300		EC_KEY_free(ec);
301		return 0;
302		}
303	EVP_PKEY_assign(pkey,NID_id_GostR3410_2001,ec);
304	return 1;
305	}
306
307/* Generates Gost_R3410_94_cp key */
308static int pkey_gost94cp_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
309	{
310	DSA *dsa;
311	if (!pkey_gost94_paramgen(ctx,pkey)) return 0;
312	dsa = EVP_PKEY_get0(pkey);
313	gost_sign_keygen(dsa);
314	return 1;
315	}
316
317/* Generates GOST_R3410 2001 key and assigns it using specified type */
318static int pkey_gost01cp_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
319	{
320	EC_KEY *ec;
321    if (!pkey_gost01_paramgen(ctx,pkey)) return 0;
322	ec = EVP_PKEY_get0(pkey);
323	gost2001_keygen(ec);
324	return 1;
325	}
326
327
328
329/* ----------- sign callbacks --------------------------------------*/
330
331static int pkey_gost94_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
332	const unsigned char *tbs, size_t tbs_len)
333	{
334	DSA_SIG *unpacked_sig=NULL;
335	EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
336	if (!siglen) return 0;
337	if (!sig)
338		{
339		*siglen= 64; /* better to check size of pkey->pkey.dsa-q */
340		return 1;
341		}
342	unpacked_sig = gost_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
343	if (!unpacked_sig)
344		{
345		return 0;
346		}
347	return pack_sign_cp(unpacked_sig,32,sig,siglen);
348	}
349
350static int pkey_gost01_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
351	const unsigned char *tbs, size_t tbs_len)
352	{
353	DSA_SIG *unpacked_sig=NULL;
354	EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
355	if (!siglen) return 0;
356	if (!sig)
357		{
358		*siglen= 64; /* better to check size of curve order*/
359		return 1;
360		}
361	unpacked_sig = gost2001_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
362	if (!unpacked_sig)
363		{
364		return 0;
365		}
366	return pack_sign_cp(unpacked_sig,32,sig,siglen);
367	}
368
369/* ------------------- verify callbacks ---------------------------*/
370
371static int pkey_gost94_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
372	size_t siglen, const unsigned char *tbs, size_t tbs_len)
373	{
374	int ok = 0;
375	EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
376	DSA_SIG *s=unpack_cp_signature(sig,siglen);
377	if (!s) return 0;
378	if (pub_key) ok = gost_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
379	DSA_SIG_free(s);
380	return ok;
381	}
382
383
384static int pkey_gost01_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
385	size_t siglen, const unsigned char *tbs, size_t tbs_len)
386	{
387	int ok = 0;
388	EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
389	DSA_SIG *s=unpack_cp_signature(sig,siglen);
390	if (!s) return 0;
391#ifdef DEBUG_SIGN
392	fprintf(stderr,"R=");
393	BN_print_fp(stderr,s->r);
394	fprintf(stderr,"\nS=");
395	BN_print_fp(stderr,s->s);
396	fprintf(stderr,"\n");
397#endif
398	if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
399	DSA_SIG_free(s);
400	return ok;
401	}
402
403/* ------------- encrypt init -------------------------------------*/
404/* Generates ephermeral key */
405static int pkey_gost_encrypt_init(EVP_PKEY_CTX *ctx)
406	{
407	return 1;
408	}
409/* --------------- Derive init ------------------------------------*/
410static int pkey_gost_derive_init(EVP_PKEY_CTX *ctx)
411{
412	return 1;
413}
414/* -------- PKEY_METHOD for GOST MAC algorithm --------------------*/
415static int pkey_gost_mac_init(EVP_PKEY_CTX *ctx)
416	{
417	struct gost_mac_pmeth_data *data;
418	data = OPENSSL_malloc(sizeof(struct gost_mac_pmeth_data));
419	if (!data) return 0;
420	memset(data,0,sizeof(struct gost_mac_pmeth_data));
421	EVP_PKEY_CTX_set_data(ctx,data);
422	return 1;
423	}
424static void pkey_gost_mac_cleanup (EVP_PKEY_CTX *ctx)
425	{
426	struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
427	OPENSSL_free(data);
428	}
429static int pkey_gost_mac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
430	{
431	struct gost_mac_pmeth_data *dst_data,*src_data;
432	if (!pkey_gost_mac_init(dst))
433		{
434		return 0;
435		}
436	src_data = EVP_PKEY_CTX_get_data(src);
437	dst_data = EVP_PKEY_CTX_get_data(dst);
438	*dst_data = *src_data;
439	return 1;
440	}
441
442static int pkey_gost_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
443	{
444	struct gost_mac_pmeth_data *data =
445(struct gost_mac_pmeth_data*)EVP_PKEY_CTX_get_data(ctx);
446
447	switch (type)
448		{
449		case EVP_PKEY_CTRL_MD:
450		{
451		if (EVP_MD_type((const EVP_MD *)p2) != NID_id_Gost28147_89_MAC)
452			{
453			GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL, GOST_R_INVALID_DIGEST_TYPE);
454			return 0;
455			}
456		data->md = (EVP_MD *)p2;
457		return 1;
458		}
459		break;
460
461		case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
462		case EVP_PKEY_CTRL_PKCS7_DECRYPT:
463		case EVP_PKEY_CTRL_PKCS7_SIGN:
464			return 1;
465		case EVP_PKEY_CTRL_SET_MAC_KEY:
466			if (p1 != 32)
467				{
468				GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,
469					GOST_R_INVALID_MAC_KEY_LENGTH);
470				return 0;
471				}
472
473			memcpy(data->key,p2,32);
474			data->key_set = 1;
475			return 1;
476		case EVP_PKEY_CTRL_DIGESTINIT:
477			{
478			EVP_MD_CTX *mctx = p2;
479			void *key;
480			if (!data->key_set)
481				{
482				EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
483				if (!pkey)
484					{
485					GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,GOST_R_MAC_KEY_NOT_SET);
486					return 0;
487					}
488				key = EVP_PKEY_get0(pkey);
489				if (!key)
490					{
491					GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,GOST_R_MAC_KEY_NOT_SET);
492					return 0;
493					}
494				} else {
495				key = &(data->key);
496				}
497			return mctx->digest->md_ctrl(mctx,EVP_MD_CTRL_SET_KEY,32,key);
498			}
499		}
500	return -2;
501	}
502static int pkey_gost_mac_ctrl_str(EVP_PKEY_CTX *ctx,
503	const char *type, const char *value)
504	{
505	if (!strcmp(type, key_ctrl_string))
506		{
507		if (strlen(value)!=32)
508			{
509			GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR,
510				GOST_R_INVALID_MAC_KEY_LENGTH);
511			return 0;
512			}
513		return pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY,
514			32,(char *)value);
515		}
516	if (!strcmp(type, hexkey_ctrl_string))
517		{
518			long keylen; int ret;
519			unsigned char *keybuf=string_to_hex(value,&keylen);
520			if (keylen != 32)
521				{
522				GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR,
523					GOST_R_INVALID_MAC_KEY_LENGTH);
524				return 0;
525				}
526			ret= pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY,
527				32,keybuf);
528			OPENSSL_free(keybuf);
529			return ret;
530
531		}
532	return -2;
533	}
534
535static int pkey_gost_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
536	{
537		struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
538		unsigned char *keydata;
539		if (!data->key_set)
540		{
541			GOSTerr(GOST_F_PKEY_GOST_MAC_KEYGEN,GOST_R_MAC_KEY_NOT_SET);
542			return 0;
543		}
544		keydata = OPENSSL_malloc(32);
545		memcpy(keydata,data->key,32);
546		EVP_PKEY_assign(pkey, NID_id_Gost28147_89_MAC, keydata);
547		return 1;
548	}
549
550static int pkey_gost_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
551	{
552	return 1;
553}
554
555static int pkey_gost_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx)
556	{
557		unsigned int tmpsiglen=*siglen; /* for platforms where sizeof(int)!=sizeof(size_t)*/
558		int ret;
559		if (!sig)
560			{
561			*siglen = 4;
562			return 1;
563			}
564		ret=EVP_DigestFinal_ex(mctx,sig,&tmpsiglen);
565		*siglen = tmpsiglen;
566		return ret;
567	}
568/* ----------------------------------------------------------------*/
569int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth,int flags)
570	{
571	*pmeth = EVP_PKEY_meth_new(id, flags);
572	if (!*pmeth) return 0;
573
574	switch (id)
575		{
576		case NID_id_GostR3410_94:
577			EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl94_str);
578			EVP_PKEY_meth_set_keygen(*pmeth,NULL,pkey_gost94cp_keygen);
579			EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cp_sign);
580			EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cp_verify);
581			EVP_PKEY_meth_set_encrypt(*pmeth,
582				pkey_gost_encrypt_init, pkey_GOST94cp_encrypt);
583			EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cp_decrypt);
584			EVP_PKEY_meth_set_derive(*pmeth,
585				pkey_gost_derive_init, pkey_gost94_derive);
586			EVP_PKEY_meth_set_paramgen(*pmeth, pkey_gost_paramgen_init,pkey_gost94_paramgen);
587			break;
588		case NID_id_GostR3410_2001:
589			EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl01_str);
590			EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost01_cp_sign);
591			EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost01_cp_verify);
592
593			EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost01cp_keygen);
594
595			EVP_PKEY_meth_set_encrypt(*pmeth,
596				pkey_gost_encrypt_init, pkey_GOST01cp_encrypt);
597			EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST01cp_decrypt);
598			EVP_PKEY_meth_set_derive(*pmeth,
599				pkey_gost_derive_init, pkey_gost2001_derive);
600			EVP_PKEY_meth_set_paramgen(*pmeth, pkey_gost_paramgen_init,pkey_gost01_paramgen);
601			break;
602		case NID_id_Gost28147_89_MAC:
603			EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_mac_ctrl, pkey_gost_mac_ctrl_str);
604			EVP_PKEY_meth_set_signctx(*pmeth,pkey_gost_mac_signctx_init, pkey_gost_mac_signctx);
605			EVP_PKEY_meth_set_keygen(*pmeth,NULL, pkey_gost_mac_keygen);
606			EVP_PKEY_meth_set_init(*pmeth,pkey_gost_mac_init);
607			EVP_PKEY_meth_set_cleanup(*pmeth,pkey_gost_mac_cleanup);
608			EVP_PKEY_meth_set_copy(*pmeth,pkey_gost_mac_copy);
609			return 1;
610		default: /*Unsupported method*/
611			return 0;
612		}
613	EVP_PKEY_meth_set_init(*pmeth, pkey_gost_init);
614	EVP_PKEY_meth_set_cleanup(*pmeth, pkey_gost_cleanup);
615
616	EVP_PKEY_meth_set_copy(*pmeth, pkey_gost_copy);
617	/*FIXME derive etc...*/
618
619	return 1;
620	}
621
622