1238384Sjkim/********************************************************************** 2238384Sjkim * gost94_keyx.c * 3238384Sjkim * Copyright (c) 2005-2006 Cryptocom LTD * 4238384Sjkim * This file is distributed under the same license as OpenSSL * 5238384Sjkim * * 6238384Sjkim * Implements generation and parsing of GOST_KEY_TRANSPORT for * 7238384Sjkim * GOST R 34.10-94 algorithms * 8238384Sjkim * * 9238384Sjkim * Requires OpenSSL 0.9.9 for compilation * 10238384Sjkim **********************************************************************/ 11238384Sjkim#include <string.h> 12238384Sjkim#include <openssl/dh.h> 13238384Sjkim#include <openssl/rand.h> 14238384Sjkim#include <openssl/evp.h> 15238384Sjkim#include <openssl/objects.h> 16238384Sjkim 17238384Sjkim#include "gost89.h" 18238384Sjkim#include "gosthash.h" 19238384Sjkim#include "e_gost_err.h" 20238384Sjkim#include "gost_keywrap.h" 21238384Sjkim#include "gost_lcl.h" 22238384Sjkim/* Common functions for both 94 and 2001 key exchange schemes */ 23238384Sjkim/* Implementation of the Diffi-Hellman key agreement scheme based on 24238384Sjkim * GOST-94 keys */ 25238384Sjkim 26238384Sjkim/* Computes Diffie-Hellman key and stores it into buffer in 27238384Sjkim * little-endian byte order as expected by both versions of GOST 94 28238384Sjkim * algorithm 29238384Sjkim */ 30238384Sjkimstatic int compute_pair_key_le(unsigned char *pair_key,BIGNUM *pub_key,DH *dh) 31238384Sjkim { 32238384Sjkim unsigned char be_key[128]; 33238384Sjkim int i,key_size; 34238384Sjkim key_size=DH_compute_key(be_key,pub_key,dh); 35238384Sjkim if (!key_size) return 0; 36238384Sjkim memset(pair_key,0,128); 37238384Sjkim for (i=0;i<key_size;i++) 38238384Sjkim { 39238384Sjkim pair_key[i]=be_key[key_size-1-i]; 40238384Sjkim } 41238384Sjkim return key_size; 42238384Sjkim } 43238384Sjkim 44238384Sjkim/* 45238384Sjkim * Computes 256 bit Key exchange key as specified in RFC 4357 46238384Sjkim */ 47238384Sjkimstatic int make_cp_exchange_key(BIGNUM *priv_key,EVP_PKEY *pubk, unsigned char *shared_key) 48238384Sjkim { 49238384Sjkim unsigned char dh_key [128]; 50238384Sjkim int ret; 51238384Sjkim gost_hash_ctx hash_ctx; 52238384Sjkim DH *dh = DH_new(); 53238384Sjkim 54238384Sjkim if (!dh) 55238384Sjkim return 0; 56238384Sjkim memset(dh_key,0,128); 57238384Sjkim dh->g = BN_dup(pubk->pkey.dsa->g); 58238384Sjkim dh->p = BN_dup(pubk->pkey.dsa->p); 59238384Sjkim dh->priv_key = BN_dup(priv_key); 60238384Sjkim ret=compute_pair_key_le(dh_key,((DSA *)(EVP_PKEY_get0(pubk)))->pub_key,dh) ; 61238384Sjkim DH_free(dh); 62238384Sjkim if (!ret) return 0; 63238384Sjkim init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet); 64238384Sjkim start_hash(&hash_ctx); 65238384Sjkim hash_block(&hash_ctx,dh_key,128); 66238384Sjkim finish_hash(&hash_ctx,shared_key); 67238384Sjkim done_gost_hash_ctx(&hash_ctx); 68238384Sjkim return 1; 69238384Sjkim } 70238384Sjkim 71238384Sjkim/* EVP_PKEY_METHOD callback derive. Implements VKO R 34.10-94 */ 72238384Sjkim 73238384Sjkimint pkey_gost94_derive(EVP_PKEY_CTX *ctx,unsigned char *key,size_t *keylen) 74238384Sjkim { 75238384Sjkim EVP_PKEY *pubk = EVP_PKEY_CTX_get0_peerkey(ctx); 76238384Sjkim EVP_PKEY *mykey = EVP_PKEY_CTX_get0_pkey(ctx); 77238384Sjkim *keylen = 32; 78238384Sjkim if (key == NULL) return 1; 79238384Sjkim 80238384Sjkim return make_cp_exchange_key(gost_get0_priv_key(mykey), pubk, key); 81238384Sjkim } 82238384Sjkim 83238384Sjkim/* EVP_PKEY_METHOD callback encrypt for 84238384Sjkim * GOST R 34.10-94 cryptopro modification 85238384Sjkim */ 86238384Sjkim 87238384Sjkim 88238384Sjkimint pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len ) 89238384Sjkim { 90238384Sjkim GOST_KEY_TRANSPORT *gkt=NULL; 91238384Sjkim unsigned char shared_key[32], ukm[8],crypted_key[44]; 92238384Sjkim const struct gost_cipher_info *param=get_encryption_params(NULL); 93238384Sjkim EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx); 94238384Sjkim struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); 95238384Sjkim gost_ctx cctx; 96238384Sjkim int key_is_ephemeral=1; 97238384Sjkim EVP_PKEY *mykey = EVP_PKEY_CTX_get0_peerkey(ctx); 98238384Sjkim 99238384Sjkim /* Do not use vizir cipher parameters with cryptopro */ 100238384Sjkim if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS) && param == gost_cipher_list) 101238384Sjkim { 102238384Sjkim param= gost_cipher_list+1; 103238384Sjkim } 104238384Sjkim 105238384Sjkim if (mykey) 106238384Sjkim { 107238384Sjkim /* If key already set, it is not ephemeral */ 108238384Sjkim key_is_ephemeral=0; 109238384Sjkim if (!gost_get0_priv_key(mykey)) 110238384Sjkim { 111238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, 112238384Sjkim GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR); 113238384Sjkim goto err; 114238384Sjkim } 115238384Sjkim } 116238384Sjkim else 117238384Sjkim { 118238384Sjkim /* Otherwise generate ephemeral key */ 119238384Sjkim key_is_ephemeral = 1; 120238384Sjkim if (out) 121238384Sjkim { 122238384Sjkim mykey = EVP_PKEY_new(); 123238384Sjkim EVP_PKEY_assign(mykey, EVP_PKEY_base_id(pubk),DSA_new()); 124238384Sjkim EVP_PKEY_copy_parameters(mykey,pubk); 125238384Sjkim if (!gost_sign_keygen(EVP_PKEY_get0(mykey))) 126238384Sjkim { 127238384Sjkim goto err; 128238384Sjkim } 129238384Sjkim } 130238384Sjkim } 131238384Sjkim if (out) 132238384Sjkim make_cp_exchange_key(gost_get0_priv_key(mykey),pubk,shared_key); 133238384Sjkim if (data->shared_ukm) 134238384Sjkim { 135238384Sjkim memcpy(ukm,data->shared_ukm,8); 136238384Sjkim } 137238384Sjkim else if (out) 138238384Sjkim { 139238384Sjkim if (RAND_bytes(ukm,8)<=0) 140238384Sjkim { 141238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, 142238384Sjkim GOST_R_RANDOM_GENERATOR_FAILURE); 143238384Sjkim goto err; 144238384Sjkim } 145238384Sjkim } 146238384Sjkim 147238384Sjkim if (out) { 148238384Sjkim gost_init(&cctx,param->sblock); 149238384Sjkim keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key); 150238384Sjkim } 151238384Sjkim gkt = GOST_KEY_TRANSPORT_new(); 152238384Sjkim if (!gkt) 153238384Sjkim { 154238384Sjkim goto memerr; 155238384Sjkim } 156238384Sjkim if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, 157238384Sjkim ukm,8)) 158238384Sjkim { 159238384Sjkim goto memerr; 160238384Sjkim } 161238384Sjkim if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) 162238384Sjkim { 163238384Sjkim goto memerr; 164238384Sjkim } 165238384Sjkim if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) 166238384Sjkim { 167238384Sjkim goto memerr; 168238384Sjkim } 169238384Sjkim if (key_is_ephemeral) { 170238384Sjkim if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,out?mykey:pubk)) 171238384Sjkim { 172238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); 173238384Sjkim goto err; 174238384Sjkim } 175238384Sjkim if (out) EVP_PKEY_free(mykey); 176238384Sjkim } 177238384Sjkim ASN1_OBJECT_free(gkt->key_agreement_info->cipher); 178238384Sjkim gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid); 179238384Sjkim *outlen = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL); 180238384Sjkim if (*outlen <= 0) 181238384Sjkim { 182238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO); 183238384Sjkim goto err; 184238384Sjkim } 185238384Sjkim if (!key_is_ephemeral) 186238384Sjkim { 187238384Sjkim /* Set control "public key from client certificate used" */ 188238384Sjkim if (EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0) 189238384Sjkim { 190238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, 191238384Sjkim GOST_R_CTRL_CALL_FAILED); 192238384Sjkim goto err; 193238384Sjkim } 194238384Sjkim } 195238384Sjkim GOST_KEY_TRANSPORT_free(gkt); 196238384Sjkim return 1; 197238384Sjkim memerr: 198238384Sjkim if (key_is_ephemeral) { 199238384Sjkim EVP_PKEY_free(mykey); 200238384Sjkim } 201238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, 202238384Sjkim GOST_R_MALLOC_FAILURE); 203238384Sjkim err: 204238384Sjkim GOST_KEY_TRANSPORT_free(gkt); 205238384Sjkim return -1; 206238384Sjkim } 207238384Sjkim 208238384Sjkim 209238384Sjkim/* EVP_PLEY_METHOD callback decrypt for 210238384Sjkim * GOST R 34.10-94 cryptopro modification 211238384Sjkim */ 212238384Sjkimint pkey_GOST94cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len,const unsigned char *in, size_t in_len) { 213238384Sjkim const unsigned char *p = in; 214238384Sjkim GOST_KEY_TRANSPORT *gkt = NULL; 215238384Sjkim unsigned char wrappedKey[44]; 216238384Sjkim unsigned char sharedKey[32]; 217238384Sjkim gost_ctx cctx; 218238384Sjkim const struct gost_cipher_info *param=NULL; 219238384Sjkim EVP_PKEY *eph_key=NULL, *peerkey=NULL; 220238384Sjkim EVP_PKEY *priv= EVP_PKEY_CTX_get0_pkey(ctx); 221238384Sjkim 222238384Sjkim if (!key) 223238384Sjkim { 224238384Sjkim *key_len = 32; 225238384Sjkim return 1; 226238384Sjkim } 227238384Sjkim 228238384Sjkim gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, 229238384Sjkim in_len); 230238384Sjkim if (!gkt) 231238384Sjkim { 232238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); 233238384Sjkim return 0; 234238384Sjkim } 235238384Sjkim eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); 236238384Sjkim if (eph_key) 237238384Sjkim { 238238384Sjkim if (EVP_PKEY_derive_set_peer(ctx, eph_key) <= 0) 239238384Sjkim { 240238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, 241238384Sjkim GOST_R_INCOMPATIBLE_PEER_KEY); 242238384Sjkim goto err; 243238384Sjkim } 244238384Sjkim } 245238384Sjkim else 246238384Sjkim { 247238384Sjkim /* Set control "public key from client certificate used" */ 248238384Sjkim if (EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0) 249238384Sjkim { 250238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, 251238384Sjkim GOST_R_CTRL_CALL_FAILED); 252238384Sjkim goto err; 253238384Sjkim } 254238384Sjkim } 255238384Sjkim peerkey = EVP_PKEY_CTX_get0_peerkey(ctx); 256238384Sjkim if (!peerkey) 257238384Sjkim { 258238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, 259238384Sjkim GOST_R_NO_PEER_KEY); 260238384Sjkim goto err; 261238384Sjkim } 262238384Sjkim 263238384Sjkim param = get_encryption_params(gkt->key_agreement_info->cipher); 264238384Sjkim if(!param){ 265238384Sjkim goto err; 266238384Sjkim } 267238384Sjkim 268238384Sjkim gost_init(&cctx,param->sblock); 269238384Sjkim OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8); 270238384Sjkim memcpy(wrappedKey,gkt->key_agreement_info->eph_iv->data,8); 271238384Sjkim OPENSSL_assert(gkt->key_info->encrypted_key->length==32); 272238384Sjkim memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32); 273238384Sjkim OPENSSL_assert(gkt->key_info->imit->length==4); 274238384Sjkim memcpy(wrappedKey+40,gkt->key_info->imit->data,4); 275238384Sjkim make_cp_exchange_key(gost_get0_priv_key(priv),peerkey,sharedKey); 276238384Sjkim if (!keyUnwrapCryptoPro(&cctx,sharedKey,wrappedKey,key)) 277238384Sjkim { 278238384Sjkim GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, 279238384Sjkim GOST_R_ERROR_COMPUTING_SHARED_KEY); 280238384Sjkim goto err; 281238384Sjkim } 282238384Sjkim 283238384Sjkim EVP_PKEY_free(eph_key); 284238384Sjkim GOST_KEY_TRANSPORT_free(gkt); 285238384Sjkim return 1; 286238384Sjkimerr: 287238384Sjkim EVP_PKEY_free(eph_key); 288238384Sjkim GOST_KEY_TRANSPORT_free(gkt); 289238384Sjkim return -1; 290238384Sjkim } 291238384Sjkim 292