Updated version of gost engine.
[openssl.git] / engines / ccgost / gost_pmeth.c
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 <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include "gost_params.h"
17 #include "gost_lcl.h"
18 #include "e_gost_err.h"
19 /*-------init, cleanup, copy - uniform for all algs  ---------------*/
20 /* Allocates new gost_pmeth_data structure and assigns it as data */
21 static int pkey_gost_init(EVP_PKEY_CTX *ctx)
22         {
23         struct gost_pmeth_data *data;
24         data = OPENSSL_malloc(sizeof(struct gost_pmeth_data));
25         if (!data) return 0;
26         memset(data,0,sizeof(struct gost_pmeth_data));
27         EVP_PKEY_CTX_set_data(ctx,data);
28         return 1;
29         }
30
31 /* Copies contents of gost_pmeth_data structure */
32 static int pkey_gost_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
33         {
34         struct gost_pmeth_data *dst_data,*src_data;
35         if (!pkey_gost_init(dst))
36                 {
37                 return 0;
38                 }
39         src_data = EVP_PKEY_CTX_get_data(src);
40         dst_data = EVP_PKEY_CTX_get_data(dst);
41         *dst_data = *src_data;
42         if (src_data -> eph_seckey)
43                 {
44                 dst_data ->eph_seckey = NULL;
45                 }       
46         return 1;
47         }
48
49 /* Frees up gost_pmeth_data structure */
50 static void pkey_gost_cleanup (EVP_PKEY_CTX *ctx)
51         {
52         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
53         if (data->eph_seckey) EVP_PKEY_free(data->eph_seckey);
54         OPENSSL_free(data);
55         }       
56
57 /* --------------------- control functions  ------------------------------*/
58 static int pkey_gost_ctrl (EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
59         {
60         struct gost_pmeth_data *pctx = (struct gost_pmeth_data*)EVP_PKEY_CTX_get_data(ctx);
61         switch (type)
62                 {
63                 case EVP_PKEY_CTRL_MD:
64                 {
65                 if (EVP_MD_type((const EVP_MD *)p2) != NID_id_GostR3411_94)
66                         {
67                         GOSTerr(GOST_F_PKEY_GOST_CTRL, GOST_R_INVALID_DIGEST_TYPE);
68                         return 0;
69                         }
70                 pctx->md = (EVP_MD *)p2;
71                 return 1;
72                 }
73                 break;
74
75                 case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
76                 case EVP_PKEY_CTRL_PKCS7_DECRYPT:
77                 case EVP_PKEY_CTRL_PKCS7_SIGN:
78                         return 1;
79
80                 case EVP_PKEY_CTRL_GOST_PARAMSET:
81                         pctx->sign_param_nid = (int)p1;
82                         return 1;
83                         
84                 }
85         return -2;
86         }
87
88 static int pkey_gost_ctrl94cc_str(EVP_PKEY_CTX *ctx,
89         const char *type, const char *value)
90         {
91         if(!strcmp(type, param_ctrl_string))
92                 {
93                 return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
94                         NID_id_GostR3410_94_CryptoPro_A_ParamSet,
95                         NULL);
96                 }
97         return -2;
98         }
99
100 static int pkey_gost_ctrl01cc_str(EVP_PKEY_CTX *ctx,
101         const char *type, const char *value)
102         {
103         if(!strcmp(type, param_ctrl_string))
104                 {
105                 return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
106                         NID_id_GostR3410_2001_ParamSet_cc,NULL);
107                 }
108         return -2;
109         }
110
111 static int pkey_gost_ctrl94_str(EVP_PKEY_CTX *ctx,
112         const char *type, const char *value)
113         {
114         int param_nid=0;
115         if(!strcmp(type, param_ctrl_string))
116                 {
117                 if (!value)
118                         {
119                         return 0;
120                         }
121                 if (strlen(value) == 1)
122                         {
123                         switch(toupper(value[0]))
124                                 {
125                                 case 'A':
126                                         param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet;
127                                         break;
128                                 case 'B':
129                                         param_nid = NID_id_GostR3410_94_CryptoPro_B_ParamSet;
130                                         break;
131                                 case 'C':
132                                         param_nid = NID_id_GostR3410_94_CryptoPro_C_ParamSet;
133                                         break;
134                                 case 'D':
135                                         param_nid = NID_id_GostR3410_94_CryptoPro_D_ParamSet;
136                                         break;
137                                 default:
138                                         return 0;
139                                         break;
140                                 }
141                         }
142                 else if ((strlen(value) == 2) && (toupper(value[0]) == 'X'))
143                         {
144                         switch (toupper(value[1]))
145                                 {
146                                 case 'A':
147                                         param_nid = NID_id_GostR3410_94_CryptoPro_XchA_ParamSet;
148                                         break;
149                                 case 'B':
150                                         param_nid = NID_id_GostR3410_94_CryptoPro_XchB_ParamSet;
151                                         break;
152                                 case 'C':
153                                         param_nid = NID_id_GostR3410_94_CryptoPro_XchC_ParamSet;
154                                         break;
155                                 default:
156                                         return 0;
157                                         break;
158                                 }
159                         }
160                 else
161                         {
162                         R3410_params *p = R3410_paramset;
163                         param_nid = OBJ_txt2nid(value);
164                         if (param_nid == NID_undef)
165                                 {
166                                 return 0;
167                                 }
168                         for (;p->nid != NID_undef;p++)
169                                 {
170                                 if (p->nid == param_nid) break;
171                                 }
172                         if (p->nid == NID_undef)
173                                 {
174                                 GOSTerr(GOST_F_PKEY_GOST_CTRL94_STR,
175                                         GOST_R_INVALID_PARAMSET);
176                                 return 0;
177                                 }
178                         }
179
180                 return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
181                         param_nid, NULL);
182                 }
183         return -2;
184         }
185
186 static int pkey_gost_ctrl01_str(EVP_PKEY_CTX *ctx,
187         const char *type, const char *value)
188         {
189         int param_nid=0;
190         if(!strcmp(type, param_ctrl_string))
191                 {
192                 if (!value)
193                         {
194                         return 0;
195                         }
196                 if (strlen(value) == 1)
197                         {
198                         switch(toupper(value[0]))
199                                 {
200                                 case 'A':
201                                         param_nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet;
202                                         break;  
203                                 case 'B':
204                                         param_nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet;
205                                         break;
206                                 case 'C':
207                                         param_nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet;
208                                         break;
209                                 case '0':
210                                         param_nid = NID_id_GostR3410_2001_TestParamSet;
211                                         break;
212                                 default:
213                                         return 0;
214                                         break;
215                                 }
216                         }
217                 else if ((strlen(value) == 2) && (toupper(value[0]) == 'X'))
218                         {
219                         switch (toupper(value[1]))
220                                 {
221                                 case 'A':
222                                         param_nid = NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet;
223                                         break;
224                                 case 'B':
225                                         param_nid = NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet;
226                                         break;
227                                 default:
228                                         return 0;
229                                         break;
230                                 }
231                         }
232                 else
233                         {
234                         R3410_2001_params *p = R3410_2001_paramset;
235                         param_nid = OBJ_txt2nid(value);
236                         if (param_nid == NID_undef)
237                                 {
238                                 return 0;
239                                 }
240                         for (;p->nid != NID_undef;p++)
241                                 {
242                                 if (p->nid == param_nid) break;
243                                 }
244                         if (p->nid == NID_undef)
245                                 {
246                                 GOSTerr(GOST_F_PKEY_GOST_CTRL01_STR,
247                                         GOST_R_INVALID_PARAMSET);
248                                 return 0;
249                                 }
250                         }
251
252                 return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET,
253                         param_nid, NULL);
254                 }
255         return -2;
256         }
257
258 /* --------------------- key generation  --------------------------------*/
259 /* Generates GOST 94 key and assigns it setting specified type */
260 static int pkey_gost94_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey,int type)
261         {
262         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
263         DSA *dsa=NULL;
264         if (data->sign_param_nid == NID_undef)
265                 {
266                 if (type== NID_id_GostR3410_94_cc)
267                         {
268                         data->sign_param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet;
269                         }
270                 else
271                         {
272                         GOSTerr(GOST_F_PKEY_GOST94_KEYGEN,
273                                 GOST_R_NO_PARAMETERS_SET);
274                         return 0;
275                         }       
276                 }
277         dsa = DSA_new();
278         if (!fill_GOST94_params(dsa,data->sign_param_nid))
279                 {
280                 DSA_free(dsa);
281                 return 0;
282                 }
283         gost_sign_keygen(dsa);
284         EVP_PKEY_assign(pkey,type,dsa);
285         return 1;
286         }
287
288 /* Generates Gost_R3410_94_cc key */
289 static int pkey_gost94cc_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
290         {
291         return pkey_gost94_keygen(ctx,pkey,NID_id_GostR3410_94_cc);
292         }
293
294 /* Generates Gost_R3410_94_cp key */
295 static int pkey_gost94cp_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
296         {
297         return pkey_gost94_keygen(ctx,pkey,NID_id_GostR3410_94);
298         }
299
300 /* Generates GOST_R3410 2001 key and assigns it using specified type */
301 static int pkey_gost01_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey,int type)
302         {
303         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
304         EC_KEY *ec=NULL;
305         if (data->sign_param_nid == NID_undef)
306                 {
307                 if (type == NID_id_GostR3410_2001_cc)
308                         {
309                         data->sign_param_nid = NID_id_GostR3410_2001_ParamSet_cc;
310                         }
311                 else {  
312                         GOSTerr(GOST_F_PKEY_GOST01_KEYGEN,
313                                 GOST_R_NO_PARAMETERS_SET);
314                         return 0;
315                         }
316                 }
317         ec = EC_KEY_new();
318         if (!fill_GOST2001_params(ec,data->sign_param_nid))
319                 {
320                 EC_KEY_free(ec);
321                 return 0;
322                 }
323         gost2001_keygen(ec);
324
325         EVP_PKEY_assign(pkey,type,ec);
326         return 1;
327         }
328
329 /* Generates GOST R3410 2001_cc key */
330 static int pkey_gost01cc_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
331         {
332         return pkey_gost01_keygen(ctx,pkey,NID_id_GostR3410_2001_cc);
333         }
334
335 /* Generates GOST R3410 2001_cp key */
336 static int pkey_gost01cp_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
337         {
338         return pkey_gost01_keygen(ctx,pkey,NID_id_GostR3410_2001);
339         }
340
341 /* ----------- sign callbacks --------------------------------------*/
342 static int pkey_gost94_cc_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
343         const unsigned char *tbs, size_t tbs_len)
344         {
345         DSA_SIG *unpacked_sig=NULL;
346         EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
347         if (!siglen) return 0;
348         if (!sig)
349                 {
350                 *siglen= 64; /* better to check size of pkey->pkey.dsa-q */
351                 return 1;
352                 }       
353         unpacked_sig = gost_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
354         if (!unpacked_sig)
355                 {
356                 return 0;
357                 }
358         return pack_sign_cc(unpacked_sig,32,sig,siglen);
359         }
360
361 static int pkey_gost94_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
362         const unsigned char *tbs, size_t tbs_len)
363         {
364         DSA_SIG *unpacked_sig=NULL;
365         EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
366         if (!siglen) return 0;
367         if (!sig)
368                 {
369                 *siglen= 64; /* better to check size of pkey->pkey.dsa-q */
370                 return 1;
371                 }       
372         unpacked_sig = gost_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
373         if (!unpacked_sig)
374                 {
375                 return 0;
376                 }
377         return pack_sign_cp(unpacked_sig,32,sig,siglen);
378         }
379
380 static int pkey_gost01_cc_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
381         const unsigned char *tbs, size_t tbs_len)
382         {
383         DSA_SIG *unpacked_sig=NULL;
384         EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
385         if (!siglen) return 0;
386         if (!sig)
387                 {
388                 *siglen= 64; /* better to check size of curve order*/
389                 return 1;
390                 }       
391         unpacked_sig = gost2001_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
392         if (!unpacked_sig)
393                 {
394                 return 0;
395                 }
396         return pack_sign_cc(unpacked_sig,32,sig,siglen);
397         }
398
399 static int pkey_gost01_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
400         const unsigned char *tbs, size_t tbs_len)
401         {
402         DSA_SIG *unpacked_sig=NULL;
403         EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
404         if (!siglen) return 0;
405         if (!sig)
406                 {
407                 *siglen= 64; /* better to check size of curve order*/
408                 return 1;
409                 }       
410         unpacked_sig = gost2001_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey));
411         if (!unpacked_sig)
412                 {
413                 return 0;
414                 }
415         return pack_sign_cp(unpacked_sig,32,sig,siglen);
416         }
417
418 /* ------------------- verify callbacks ---------------------------*/
419 static int pkey_gost94_cc_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
420         size_t siglen, const unsigned char *tbs, size_t tbs_len)
421         {
422         int ok = 0;
423         EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
424         DSA_SIG *s=unpack_cc_signature(sig,siglen);
425         if (!s) return 0;
426         if (pub_key) ok = gost_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
427         DSA_SIG_free(s);
428         return ok;
429         }
430
431 static int pkey_gost94_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
432         size_t siglen, const unsigned char *tbs, size_t tbs_len)
433         {
434         int ok = 0;
435         EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
436         DSA_SIG *s=unpack_cp_signature(sig,siglen);
437         if (!s) return 0;
438         if (pub_key) ok = gost_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
439         DSA_SIG_free(s);
440         return ok;
441         }
442
443 static int pkey_gost01_cc_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
444         size_t siglen, const unsigned char *tbs, size_t tbs_len)
445         {
446         int ok = 0;
447         EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
448         DSA_SIG *s=unpack_cc_signature(sig,siglen);
449         fprintf(stderr,"R=");
450         BN_print_fp(stderr,s->r);
451         fprintf(stderr,"\nS=");
452         BN_print_fp(stderr,s->s);
453         fprintf(stderr,"\n");
454         if (!s) return 0;
455         if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
456         DSA_SIG_free(s);
457         return ok;
458         }
459
460 static int pkey_gost01_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
461         size_t siglen, const unsigned char *tbs, size_t tbs_len)
462         {
463         int ok = 0;
464         EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx);
465         DSA_SIG *s=unpack_cp_signature(sig,siglen);
466         if (!s) return 0;
467         fprintf(stderr,"R=");
468         BN_print_fp(stderr,s->r);
469         fprintf(stderr,"\nS=");
470         BN_print_fp(stderr,s->s);
471         fprintf(stderr,"\n");
472         if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key));
473         DSA_SIG_free(s);
474         return ok;
475         }
476
477 /* ------------- encrypt init -------------------------------------*/
478 /* Generates ephermeral key */
479 static int pkey_gost_encrypt_init(EVP_PKEY_CTX *ctx)
480         {
481         struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
482         EVP_PKEY *eph_key = EVP_PKEY_new();
483         EVP_PKEY *old_key =EVP_PKEY_CTX_get0_pkey(ctx);
484
485         if (data->eph_seckey) EVP_PKEY_free(data->eph_seckey);
486         EVP_PKEY_assign(eph_key,EVP_PKEY_base_id(old_key),NULL);
487         if (!EVP_PKEY_copy_parameters(eph_key,old_key)) return 0;
488         switch (EVP_PKEY_base_id(old_key))
489                 {
490                 case NID_id_GostR3410_2001:
491                 case NID_id_GostR3410_2001_cc:
492                         gost2001_keygen(EVP_PKEY_get0(eph_key));
493                         break;
494                 case NID_id_GostR3410_94:
495                 case NID_id_GostR3410_94_cc:
496                         gost_sign_keygen(EVP_PKEY_get0(eph_key));
497                         break;
498         
499                         
500                 }
501
502         
503         data->eph_seckey=eph_key;
504         return 1;
505         }
506
507 /* ----------------------------------------------------------------*/
508 int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth,int flags)
509         {
510         *pmeth = EVP_PKEY_meth_new(id, flags);
511         if (!*pmeth) return 0;
512
513         switch (id)
514                 {
515                 case NID_id_GostR3410_94_cc:
516                         EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl94cc_str);
517                         EVP_PKEY_meth_set_keygen(*pmeth,NULL,pkey_gost94cc_keygen);
518                         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cc_sign);
519                         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cc_verify);
520                         EVP_PKEY_meth_set_encrypt(*pmeth,
521                                 pkey_gost_encrypt_init, pkey_GOST94cc_encrypt);
522                         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cc_decrypt);
523                         break;
524                 case NID_id_GostR3410_94:
525                         EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl94_str);
526                         EVP_PKEY_meth_set_keygen(*pmeth,NULL,pkey_gost94cp_keygen);
527                         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cp_sign);
528                         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cp_verify);
529                         EVP_PKEY_meth_set_encrypt(*pmeth,
530                                 pkey_gost_encrypt_init, pkey_GOST94cp_encrypt);
531                         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cp_decrypt);
532
533         
534                         break;
535                 case NID_id_GostR3410_2001_cc:
536                         EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl01cc_str);
537                         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost01_cc_sign);
538                         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost01_cc_verify);
539
540                         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost01cc_keygen);
541
542                         EVP_PKEY_meth_set_encrypt(*pmeth,
543                                 pkey_gost_encrypt_init, pkey_GOST01cc_encrypt);
544                         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST01cc_decrypt);
545                         break;
546                         /* There is intentionally no break here */
547                 case NID_id_GostR3410_2001:
548                         EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl01_str);
549                         EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost01_cp_sign);
550                         EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost01_cp_verify);
551
552                         EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost01cp_keygen);
553
554                         EVP_PKEY_meth_set_encrypt(*pmeth,
555                                 pkey_gost_encrypt_init, pkey_GOST01cp_encrypt);
556                         EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST01cp_decrypt);
557                         break;
558                 default: //Unsupported method
559                         return 0;
560                 }
561         EVP_PKEY_meth_set_init(*pmeth, pkey_gost_init);
562         EVP_PKEY_meth_set_cleanup(*pmeth, pkey_gost_cleanup);
563
564         EVP_PKEY_meth_set_copy(*pmeth, pkey_gost_copy);
565         //FIXME derive etc...
566         
567         return 1;
568         }
569