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