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