diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2007-10-26 12:06:36 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2007-10-26 12:06:36 +0000 |
commit | 0e1dba934fa53e9736e9156b9e25bd1010290149 (patch) | |
tree | e52e12fa1147b634c215263e93d77c8c9830b39b /engines/ccgost | |
parent | 11d01d371f67a9cacfeccb1078669c595d65002f (diff) |
1. Changes for s_client.c to make it return non-zero exit code in case
of handshake failure
2. Changes to x509_certificate_type function (crypto/x509/x509type.c) to
make it recognize GOST certificates as EVP_PKT_SIGN|EVP_PKT_EXCH
(required for s3_srvr to accept GOST client certificates).
3. Changes to EVP
- adding of function EVP_PKEY_CTX_get0_peerkey
- Make function EVP_PKEY_derive_set_peerkey work for context with
ENCRYPT operation, because we use peerkey field in the context to
pass non-ephemeral secret key to GOST encrypt operation.
- added EVP_PKEY_CTRL_SET_IV control command. It is really
GOST-specific, but it is used in SSL code, so it has to go
in some header file, available during libssl compilation
4. Fix to HMAC to avoid call of OPENSSL_cleanse on undefined data
5. Include des.h if KSSL_DEBUG is defined into some libssl files, to
make debugging output which depends on constants defined there, work
and other KSSL_DEBUG output fixes
6. Declaration of real GOST ciphersuites, two authentication methods
SSL_aGOST94 and SSL_aGOST2001 and one key exchange method SSL_kGOST
7. Implementation of these methods.
8. Support for sending unsolicited serverhello extension if GOST
ciphersuite is selected. It is require for interoperability with
CryptoPro CSP 3.0 and 3.6 and controlled by
SSL_OP_CRYPTOPRO_TLSEXT_BUG constant.
This constant is added to SSL_OP_ALL, because it does nothing, if
non-GOST ciphersuite is selected, and all implementation of GOST
include compatibility with CryptoPro.
9. Support for CertificateVerify message without length field. It is
another CryptoPro bug, but support is made unconditional, because it
does no harm for draft-conforming implementation.
10. In tls1_mac extra copy of stream mac context is no more done.
When I've written currently commited code I haven't read
EVP_DigestSignFinal manual carefully enough and haven't noticed that
it does an internal digest ctx copying.
This implementation was tested against
1. CryptoPro CSP 3.6 client and server
2. Cryptopro CSP 3.0 server
Diffstat (limited to 'engines/ccgost')
-rw-r--r-- | engines/ccgost/e_gost_err.c | 4 | ||||
-rw-r--r-- | engines/ccgost/e_gost_err.h | 4 | ||||
-rw-r--r-- | engines/ccgost/gost2001_keyx.c | 431 | ||||
-rw-r--r-- | engines/ccgost/gost94_keyx.c | 374 | ||||
-rw-r--r-- | engines/ccgost/gost_ameth.c | 73 | ||||
-rw-r--r-- | engines/ccgost/gost_crypt.c | 80 | ||||
-rw-r--r-- | engines/ccgost/gost_ctl.c | 14 | ||||
-rw-r--r-- | engines/ccgost/gost_eng.c | 23 | ||||
-rw-r--r-- | engines/ccgost/gost_lcl.h | 35 | ||||
-rw-r--r-- | engines/ccgost/gost_md.c | 8 | ||||
-rw-r--r-- | engines/ccgost/gost_pmeth.c | 203 |
11 files changed, 339 insertions, 910 deletions
diff --git a/engines/ccgost/e_gost_err.c b/engines/ccgost/e_gost_err.c index 648a2d71e5..d483411fc2 100644 --- a/engines/ccgost/e_gost_err.c +++ b/engines/ccgost/e_gost_err.c @@ -97,6 +97,7 @@ static ERR_STRING_DATA GOST_str_functs[]= {ERR_FUNC(GOST_F_PKEY_GOST01CC_ENCRYPT), "pkey_GOST01cc_encrypt"}, {ERR_FUNC(GOST_F_PKEY_GOST01CP_ENCRYPT), "pkey_GOST01cp_encrypt"}, {ERR_FUNC(GOST_F_PKEY_GOST01_KEYGEN), "PKEY_GOST01_KEYGEN"}, +{ERR_FUNC(GOST_F_PKEY_GOST2001_DERIVE), "PKEY_GOST2001_DERIVE"}, {ERR_FUNC(GOST_F_PKEY_GOST94CC_DECRYPT), "pkey_GOST94cc_decrypt"}, {ERR_FUNC(GOST_F_PKEY_GOST94CC_ENCRYPT), "pkey_GOST94cc_encrypt"}, {ERR_FUNC(GOST_F_PKEY_GOST94CP_DECRYPT), "pkey_GOST94cp_decrypt"}, @@ -148,6 +149,8 @@ static ERR_STRING_DATA GOST_str_reasons[]= {ERR_REASON(GOST_R_NOT_ENOUGH_SPACE_FOR_KEY),"not enough space for key"}, {ERR_REASON(GOST_R_NO_MEMORY) ,"no memory"}, {ERR_REASON(GOST_R_NO_PARAMETERS_SET) ,"no parameters set"}, +{ERR_REASON(GOST_R_NO_PEER_KEY) ,"no peer key"}, +{ERR_REASON(GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR),"no private part of non ephemeral keypair"}, {ERR_REASON(GOST_R_PUBLIC_KEY_UNDEFINED) ,"public key undefined"}, {ERR_REASON(GOST_R_RANDOM_GENERATOR_ERROR),"random generator error"}, {ERR_REASON(GOST_R_RANDOM_GENERATOR_FAILURE),"random generator failure"}, @@ -155,6 +158,7 @@ static ERR_STRING_DATA GOST_str_reasons[]= {ERR_REASON(GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH),"session key mac does not match"}, {ERR_REASON(GOST_R_SIGNATURE_MISMATCH) ,"signature mismatch"}, {ERR_REASON(GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q),"signature parts greater than q"}, +{ERR_REASON(GOST_R_UKM_NOT_SET) ,"ukm not set"}, {ERR_REASON(GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND),"unsupported cipher ctl command"}, {ERR_REASON(GOST_R_UNSUPPORTED_PARAMETER_SET),"unsupported parameter set"}, {0,NULL} diff --git a/engines/ccgost/e_gost_err.h b/engines/ccgost/e_gost_err.h index 4fb5a985a3..a672ed9d8d 100644 --- a/engines/ccgost/e_gost_err.h +++ b/engines/ccgost/e_gost_err.h @@ -94,6 +94,7 @@ void ERR_GOST_error(int function, int reason, char *file, int line); #define GOST_F_PKEY_GOST01CC_ENCRYPT 129 #define GOST_F_PKEY_GOST01CP_ENCRYPT 137 #define GOST_F_PKEY_GOST01_KEYGEN 112 +#define GOST_F_PKEY_GOST2001_DERIVE 145 #define GOST_F_PKEY_GOST94CC_DECRYPT 125 #define GOST_F_PKEY_GOST94CC_ENCRYPT 123 #define GOST_F_PKEY_GOST94CP_DECRYPT 126 @@ -142,6 +143,8 @@ void ERR_GOST_error(int function, int reason, char *file, int line); #define GOST_R_NOT_ENOUGH_SPACE_FOR_KEY 125 #define GOST_R_NO_MEMORY 106 #define GOST_R_NO_PARAMETERS_SET 107 +#define GOST_R_NO_PEER_KEY 137 +#define GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR 139 #define GOST_R_PUBLIC_KEY_UNDEFINED 132 #define GOST_R_RANDOM_GENERATOR_ERROR 108 #define GOST_R_RANDOM_GENERATOR_FAILURE 133 @@ -149,6 +152,7 @@ void ERR_GOST_error(int function, int reason, char *file, int line); #define GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH 126 #define GOST_R_SIGNATURE_MISMATCH 110 #define GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q 111 +#define GOST_R_UKM_NOT_SET 138 #define GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND 112 #define GOST_R_UNSUPPORTED_PARAMETER_SET 113 diff --git a/engines/ccgost/gost2001_keyx.c b/engines/ccgost/gost2001_keyx.c index 3cef5f2e38..013659aa23 100644 --- a/engines/ccgost/gost2001_keyx.c +++ b/engines/ccgost/gost2001_keyx.c @@ -18,194 +18,7 @@ #include "gost_lcl.h" #include "gost2001_keyx.h" -/* Transform ECDH shared key into little endian as required by Cryptocom - * key exchange */ -static void *make_key_le(const void *in, size_t inlen, void *out, size_t *outlen) - { - const char* inbuf= in; - char* outbuf= out; - int i; - if (*outlen < inlen) - { - return NULL; - } - for (i=0;i<inlen;i++) - { - outbuf[inlen-1-i]=inbuf[i]; - } - *outlen = inlen; - return out; - } -/* Create gost 2001 ephemeral key with same parameters as peer key */ -static EC_KEY *make_ec_ephemeral_key(EC_KEY *peer_key,BIGNUM *seckey) - { - EC_KEY *out = EC_KEY_new(); - EC_KEY_copy(out,peer_key); - EC_KEY_set_private_key(out,seckey); - gost2001_compute_public(out); - return out; - } -/* Packs GOST elliptic curve key into EVP_PKEY setting same parameters - * as in passed pubkey - */ -static EVP_PKEY *ec_ephemeral_key_to_EVP(EVP_PKEY *pubk,int type,EC_KEY *ephemeral) - { - EVP_PKEY *newkey; - newkey = EVP_PKEY_new(); - EVP_PKEY_assign(newkey,type,ephemeral); - return newkey; - } - -/* - * EVP_PKEY_METHOD callback encrypt - * Implementation of GOST2001 key transport, cryptocom variation - */ - -int pkey_GOST01cc_encrypt (EVP_PKEY_CTX *pctx,unsigned char *out, - size_t *out_len, const unsigned char *key,size_t key_len) - { - EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx); - struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx); - GOST_KEY_TRANSPORT *gkt = NULL; - int ret=0; - const struct gost_cipher_info *cipher_info; - gost_ctx ctx; - EC_KEY *ephemeral=NULL; - const EC_POINT *pub_key_point=NULL; - unsigned char shared_key[32],encrypted_key[32],hmac[4], - iv[8]={0,0,0,0,0,0,0,0}; - ephemeral = make_ec_ephemeral_key(EVP_PKEY_get0(pubk), gost_get_priv_key(data->eph_seckey)); - if (!ephemeral) goto err; - /* compute shared key */ - pub_key_point=EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)); - if (!ECDH_compute_key(shared_key,32,pub_key_point,ephemeral,make_key_le)) - { - GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY); - goto err; - } - /* encrypt session key */ - cipher_info = get_encryption_params(NULL); - gost_init(&ctx, cipher_info->sblock); - gost_key(&ctx,shared_key); - encrypt_cryptocom_key(key,key_len,encrypted_key,&ctx); - /* compute hmac of session key */ - if (!gost_mac(&ctx,32,key,32,hmac)) - { - GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC); - return -1; - } - gkt = GOST_KEY_TRANSPORT_new(); - if (!gkt) - { - GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_NO_MEMORY); - return -1; - } - /* Store IV which is always zero in our case */ - if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8)) - { - GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_IV); - goto err; - } - if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4)) - { - GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_MAC); - goto err; - } - if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32)) - { - GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY); - goto err; - } - - if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) - { - GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); - goto err; - } - ASN1_OBJECT_free(gkt->key_agreement_info->cipher); - gkt->key_agreement_info->cipher = OBJ_nid2obj(cipher_info->nid); - if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,&out))>0) ret = 1; - ; - err: - if (gkt) GOST_KEY_TRANSPORT_free(gkt); - return ret; - } -/* - * EVP_PKEY_METHOD callback decrypt - * Implementation of GOST2001 key transport, cryptocom variation - */ -int pkey_GOST01cc_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, const unsigned char *in, size_t in_len) - { - /* Form DH params from compute shared key */ - EVP_PKEY *priv=EVP_PKEY_CTX_get0_pkey(pctx); - GOST_KEY_TRANSPORT *gkt = NULL; - const unsigned char *p=in; - unsigned char shared_key[32]; - unsigned char hmac[4],hmac_comp[4]; - unsigned char iv[8]; - int i; - const struct gost_cipher_info *cipher_info; - gost_ctx ctx; - const EC_POINT *pub_key_point; - EVP_PKEY *eph_key; - - if (!key) - { - *key_len = 32; - return 1; - } - /* Parse passed octet string and find out public key, iv and HMAC*/ - gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, - in_len); - if (!gkt) - { - GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); - return 0; - } - eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); - /* Initialization vector is really ignored here */ - OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8); - memcpy(iv,gkt->key_agreement_info->eph_iv->data,8); - /* HMAC should be computed and checked */ - OPENSSL_assert(gkt->key_info->imit->length==4); - memcpy(hmac,gkt->key_info->imit->data,4); - /* Compute shared key */ - pub_key_point=EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key)); - i=ECDH_compute_key(shared_key,32,pub_key_point,EVP_PKEY_get0(priv),make_key_le); - EVP_PKEY_free(eph_key); - if (!i) - { - GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY); - GOST_KEY_TRANSPORT_free(gkt); - return 0; - } - /* Decrypt session key */ - cipher_info = get_encryption_params(gkt->key_agreement_info->cipher); - gost_init(&ctx, cipher_info->sblock); - gost_key(&ctx,shared_key); - - if (!decrypt_cryptocom_key(key,*key_len,gkt->key_info->encrypted_key->data, - gkt->key_info->encrypted_key->length, &ctx)) - { - GOST_KEY_TRANSPORT_free(gkt); - return 0; - } - GOST_KEY_TRANSPORT_free(gkt); - /* check HMAC of session key*/ - if (!gost_mac(&ctx,32,key,32,hmac_comp)) - { - GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_COMPUTING_MAC); - return 0; - } - /* HMAC of session key is not correct */ - if (memcmp(hmac,hmac_comp,4)!=0) - { - GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH); - return 0; - } - return 1; - } /* Implementation of CryptoPro VKO 34.10-2001 algorithm */ static int VKO_compute_key(unsigned char *shared_key,size_t shared_key_size,const EC_POINT *pub_key,EC_KEY *priv_key,const unsigned char *ukm) @@ -254,110 +67,191 @@ static int VKO_compute_key(unsigned char *shared_key,size_t shared_key_size,cons return 32; } + +/* + * EVP_PKEY_METHOD callback derive. Implements VKO R 34.10-2001 + * algorithm + */ +int pkey_gost2001_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) +{ + /* Public key of peer in the ctx field peerkey + * Our private key in the ctx pkey + * ukm is in the algorithm specific context data + */ + EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx); + EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx); + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + + if (!data->shared_ukm) { + GOSTerr(GOST_F_PKEY_GOST2001_DERIVE, GOST_R_UKM_NOT_SET); + return 0; + } + + if (key == NULL) { + *keylen = 32; + return 32; + } + + *keylen=VKO_compute_key(key, 32, EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key)), + (EC_KEY *)EVP_PKEY_get0(my_key),data->shared_ukm); + return 1; +} + + + + +/* + * EVP_PKEY_METHOD callback encrypt + * Implementation of GOST2001 key transport, cryptocom variation + */ /* Generates ephemeral key based on pubk algorithm * computes shared key using VKO and returns filled up * GOST_KEY_TRANSPORT structure */ -/* Public, because it would be needed in SSL implementation */ -GOST_KEY_TRANSPORT *make_rfc4490_keytransport_2001(EVP_PKEY *pubk,BIGNUM *eph_key, - const unsigned char *key,size_t keylen, unsigned char *ukm, - size_t ukm_len) - { +/* + * EVP_PKEY_METHOD callback encrypt + * Implementation of GOST2001 key transport, cryptopo variation + */ + +int pkey_GOST01cp_encrypt (EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len, const unsigned char *key,size_t key_len) + { + GOST_KEY_TRANSPORT *gkt=NULL; + EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx); + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx); const struct gost_cipher_info *param=get_encryption_params(NULL); - EC_KEY *ephemeral = NULL; - GOST_KEY_TRANSPORT *gkt=NULL; - const EC_POINT *pub_key_point = EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)); - unsigned char shared_key[32],crypted_key[44]; - gost_ctx ctx; - EVP_PKEY *newkey=NULL; - - /* Do not use vizir cipher parameters with cryptopro */ + unsigned char ukm[8], shared_key[32], crypted_key[44]; + int ret=0; + int key_is_ephemeral=1; + gost_ctx cctx; + EVP_PKEY *sec_key=EVP_PKEY_CTX_get0_peerkey(pctx); + if (data->shared_ukm) + { + memcpy(ukm, data->shared_ukm,8); + } + else if (out) + { + + if (RAND_bytes(ukm,8)<=0) + { + GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT, + GOST_R_RANDOM_GENERATOR_FAILURE); + return 0; + } + } + /* Check for private key in the peer_key of context */ + if (sec_key) + { + key_is_ephemeral=0; + if (!gost_get0_priv_key(sec_key)) + { + GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT, + GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR); + goto err; + } + } + else + { + key_is_ephemeral=1; + if (out) + { + sec_key = EVP_PKEY_new(); + EVP_PKEY_assign(sec_key,EVP_PKEY_base_id(pubk),EC_KEY_new()); + EVP_PKEY_copy_parameters(sec_key,pubk); + if (!gost2001_keygen(EVP_PKEY_get0(sec_key))) + { + goto err; + } + } + } if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS) && param == gost_cipher_list) { param= gost_cipher_list+1; } - ephemeral = make_ec_ephemeral_key(EVP_PKEY_get0(pubk),eph_key); - VKO_compute_key(shared_key,32,pub_key_point,ephemeral,ukm); - gost_init(&ctx,param->sblock); - keyWrapCryptoPro(&ctx,shared_key,ukm,key,crypted_key); + if (out) + { + VKO_compute_key(shared_key,32,EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)),EVP_PKEY_get0(sec_key),ukm); + gost_init(&cctx,param->sblock); + keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key); + } gkt = GOST_KEY_TRANSPORT_new(); if (!gkt) { - goto memerr; + goto err; } if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, ukm,8)) { - goto memerr; + goto err; } if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) { - goto memerr; + goto err; } if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) { - goto memerr; - } - newkey = ec_ephemeral_key_to_EVP(pubk,NID_id_GostR3410_2001,ephemeral); - if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,newkey)) - { - GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); goto err; - } + } + if (key_is_ephemeral) { + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,out?sec_key:pubk)) + { + GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001, + GOST_R_CANNOT_PACK_EPHEMERAL_KEY); + goto err; + } + } ASN1_OBJECT_free(gkt->key_agreement_info->cipher); gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid); - EVP_PKEY_free(newkey); - return gkt; - memerr: - GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001, - GOST_R_MALLOC_FAILURE); - err: - GOST_KEY_TRANSPORT_free(gkt); - return NULL; - } - -/* - * EVP_PKEY_METHOD callback encrypt - * Implementation of GOST2001 key transport, cryptopo variation - */ - -int pkey_GOST01cp_encrypt (EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len, const unsigned char *key,size_t key_len) - { - GOST_KEY_TRANSPORT *gkt=NULL; - EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx); - struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx); - unsigned char ukm[8]; - int ret=0; - if (RAND_bytes(ukm,8)<=0) - { - GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT, - GOST_R_RANDOM_GENERATOR_FAILURE); - return 0; - } - - if (!(gkt=make_rfc4490_keytransport_2001(pubk,gost_get_priv_key(data->eph_seckey),key, key_len,ukm,8))) - { - goto err; - } - if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,&out))>0) ret =1; + if (key_is_ephemeral && sec_key) EVP_PKEY_free(sec_key); + if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL))>0) ret =1; GOST_KEY_TRANSPORT_free(gkt); return ret; err: + if (key_is_ephemeral && sec_key) EVP_PKEY_free(sec_key); GOST_KEY_TRANSPORT_free(gkt); return -1; } -/* Public, because it would be needed in SSL implementation */ -int decrypt_rfc4490_shared_key_2001(EVP_PKEY *priv,GOST_KEY_TRANSPORT *gkt, - unsigned char *key_buf,int key_buf_len) +/* + * EVP_PKEY_METHOD callback decrypt + * Implementation of GOST2001 key transport, cryptopo variation + */ +int pkey_GOST01cp_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_len, const unsigned char *in, size_t in_len) { + const unsigned char *p = in; + EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx); + GOST_KEY_TRANSPORT *gkt = NULL; + int ret=0; unsigned char wrappedKey[44]; unsigned char sharedKey[32]; gost_ctx ctx; const struct gost_cipher_info *param=NULL; EVP_PKEY *eph_key=NULL; - + + if (!key) + { + *key_len = 32; + return 1; + } + gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, + in_len); + if (!gkt) + { + GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); + return -1; + } + eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); + if (!eph_key) { + eph_key = EVP_PKEY_CTX_get0_peerkey(pctx); + if (! eph_key) { + GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, + GOST_R_NO_PEER_KEY); + goto err; + } + /* Increment reference count of peer key */ + CRYPTO_add(&(eph_key->references),1 ,CRYPTO_LOCK_EVP_PKEY); + } + param = get_encryption_params(gkt->key_agreement_info->cipher); gost_init(&ctx,param->sblock); OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8); @@ -368,7 +262,7 @@ int decrypt_rfc4490_shared_key_2001(EVP_PKEY *priv,GOST_KEY_TRANSPORT *gkt, memcpy(wrappedKey+40,gkt->key_info->imit->data,4); VKO_compute_key(sharedKey,32,EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key)), EVP_PKEY_get0(priv),wrappedKey); - if (!keyUnwrapCryptoPro(&ctx,sharedKey,wrappedKey,key_buf)) + if (!keyUnwrapCryptoPro(&ctx,sharedKey,wrappedKey,key)) { GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT, GOST_R_ERROR_COMPUTING_SHARED_KEY); @@ -376,35 +270,8 @@ int decrypt_rfc4490_shared_key_2001(EVP_PKEY *priv,GOST_KEY_TRANSPORT *gkt, } EVP_PKEY_free(eph_key); - return 32; - err: - EVP_PKEY_free(eph_key); - return -1; - } -/* - * EVP_PKEY_METHOD callback decrypt - * Implementation of GOST2001 key transport, cryptopo variation - */ -int pkey_GOST01cp_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_len, const unsigned char *in, size_t in_len) - { - const unsigned char *p = in; - EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx); - GOST_KEY_TRANSPORT *gkt = NULL; - int ret=0; - - if (!key) - { - *key_len = 32; - return 1; - } - gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, - in_len); - if (!gkt) - { - GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); - return -1; - } - ret = decrypt_rfc4490_shared_key_2001(priv,gkt,key,*key_len); GOST_KEY_TRANSPORT_free(gkt); + ret=1; +err: return ret; } diff --git a/engines/ccgost/gost94_keyx.c b/engines/ccgost/gost94_keyx.c index a7cdb2a26d..69c4a2271e 100644 --- a/engines/ccgost/gost94_keyx.c +++ b/engines/ccgost/gost94_keyx.c @@ -20,53 +20,6 @@ #include "gost_keywrap.h" #include "gost_lcl.h" /* Common functions for both 94 and 2001 key exchange schemes */ -int decrypt_cryptocom_key(unsigned char *sess_key,int max_key_len, - const unsigned char *crypted_key,int crypted_key_len, gost_ctx *ctx) - { - int i; - int j; - int blocks = crypted_key_len >>3; - unsigned char gamma[8]; - if (max_key_len <crypted_key_len) - { - GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_NOT_ENOUGH_SPACE_FOR_KEY); - return 0; - } - if ((crypted_key_len & 7) !=0) - { - GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_INVALID_ENCRYPTED_KEY_SIZE); - return 0; - } - for (i=blocks-1;i>0;i--) - { - gostcrypt(ctx,crypted_key+(i-1)*8,gamma); - for(j=0;j<8;j++) - { - sess_key[i*8+j]=gamma[j]^crypted_key[i*8+j]; - } - } - gostcrypt(ctx,sess_key+crypted_key_len-8,gamma); - for(j=0;j<8;j++) - { - sess_key[j]=gamma[j]^crypted_key[j]; - } - return 1; - } -int encrypt_cryptocom_key(const unsigned char *sess_key,int key_len, - unsigned char *crypted_key, gost_ctx *ctx) - { - int i; - int j; - unsigned char gamma[8]; - memcpy(gamma,sess_key+key_len-8,8); - for (i=0;i<key_len;i+=8) - { - gostcrypt(ctx,gamma,gamma); - for (j=0;j<8;j++) - gamma[j]=crypted_key[i+j]=sess_key[i+j]^gamma[j]; - } - return 1; - } /* Implementation of the Diffi-Hellman key agreement scheme based on * GOST-94 keys */ @@ -87,59 +40,24 @@ static int compute_pair_key_le(unsigned char *pair_key,BIGNUM *pub_key,DH *dh) } return key_size; } -/* - * Computes 256 bit key exchange key for CryptoCom variation of GOST 94 - * algorithm - */ -static int make_gost_shared_key(DH *dh,EVP_PKEY *pubk,unsigned char *shared_key) - { - unsigned char dh_key [128]; - int i; - /* Compute key */ - memset(dh_key,0,128); - if (!compute_pair_key_le(dh_key,((DSA *)EVP_PKEY_get0(pubk))->pub_key,dh)) return 0; - /* Fold it down to 256 bit */ - /* According to GOST either 2^1020<p<2^1024 or - * 2^509<p<2^512, so DH_size can be exactly 128 or exactly 64 only - */ - - if (DH_size(dh)==128) - { - for (i=0;i<64;i++) - { - dh_key[i]^=dh_key[64+i]; - } - } - for (i=0;i<32;i++) - { - shared_key[i]=dh_key[i]^dh_key[32+i]; - } - return 1; - } -static DH *make_ephemeral_key(EVP_PKEY *pubk,BIGNUM *ephemeral_key) - { - DH *dh = DH_new(); - dh->g = BN_dup(pubk->pkey.dsa->g); - dh->p = BN_dup(pubk->pkey.dsa->p); - dh->priv_key = BN_dup(ephemeral_key); - /* Generate ephemeral key pair */ - if (!DH_generate_key(dh)) - { - DH_free(dh); - return NULL; - } - return dh; - } /* * Computes 256 bit Key exchange key as specified in RFC 4357 */ -static int make_cp_exchange_key(DH *dh,EVP_PKEY *pubk, unsigned char *shared_key) +static int make_cp_exchange_key(BIGNUM *priv_key,EVP_PKEY *pubk, unsigned char *shared_key) { unsigned char dh_key [128]; + int ret; gost_hash_ctx hash_ctx; + DH *dh = DH_new(); + memset(dh_key,0,128); - if (!compute_pair_key_le(dh_key,((DSA *)(EVP_PKEY_get0(pubk)))->pub_key,dh)) return 0; + dh->g = BN_dup(pubk->pkey.dsa->g); + dh->p = BN_dup(pubk->pkey.dsa->p); + dh->priv_key = BN_dup(priv_key); + ret=compute_pair_key_le(dh_key,((DSA *)(EVP_PKEY_get0(pubk)))->pub_key,dh) ; + DH_free(dh); + if (!ret) return 0; init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet); start_hash(&hash_ctx); hash_block(&hash_ctx,dh_key,128); @@ -148,38 +66,87 @@ static int make_cp_exchange_key(DH *dh,EVP_PKEY *pubk, unsigned char *shared_key return 1; } +/* EVP_PKEY_METHOD callback derive. Implements VKO R 34.10-94 */ + +int pkey_gost94_derive(EVP_PKEY_CTX *ctx,unsigned char *key,size_t *keylen) + { + EVP_PKEY *pubk = EVP_PKEY_CTX_get0_peerkey(ctx); + EVP_PKEY *mykey = EVP_PKEY_CTX_get0_pkey(ctx); + *keylen = 32; + if (key == NULL) return 1; + + return make_cp_exchange_key(gost_get0_priv_key(mykey), pubk, key); + } + /* EVP_PKEY_METHOD callback encrypt for * GOST R 34.10-94 cryptopro modification */ + int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len ) { GOST_KEY_TRANSPORT *gkt=NULL; - DH *dh = NULL; unsigned char shared_key[32], ukm[8],crypted_key[44]; const struct gost_cipher_info *param=get_encryption_params(NULL); EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx); struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); int size=-1; gost_ctx cctx; + int key_is_ephemeral=1; + EVP_PKEY *mykey = EVP_PKEY_CTX_get0_peerkey(ctx); - if (!(data->eph_seckey)) + /* Do not use vizir cipher parameters with cryptopro */ + if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS) && param == gost_cipher_list) { - GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, - GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT); - return -1; + param= gost_cipher_list+1; } - dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey)); - gost_init(&cctx,param->sblock); - make_cp_exchange_key(dh,pubk,shared_key); - if (RAND_bytes(ukm,8)<=0) + if (mykey) { - GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, - GOST_R_RANDOM_GENERATOR_FAILURE); - return -1; + /* If key already set, it is not ephemeral */ + key_is_ephemeral=0; + if (!gost_get0_priv_key(mykey)) + { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR); + goto err; + } + } + else + { + /* Otherwise generate ephemeral key */ + key_is_ephemeral = 1; + if (out) + { + mykey = EVP_PKEY_new(); + EVP_PKEY_assign(mykey, EVP_PKEY_base_id(pubk),DSA_new()); + EVP_PKEY_copy_parameters(mykey,pubk); + if (!gost_sign_keygen(EVP_PKEY_get0(mykey))) + { + goto err; + } + } } - keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key); + if (out) + make_cp_exchange_key(gost_get0_priv_key(mykey),pubk,shared_key); + if (data->shared_ukm) + { + memcpy(ukm,data->shared_ukm,8); + } + else if (out) + { + if (RAND_bytes(ukm,8)<=0) + { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_RANDOM_GENERATOR_FAILURE); + goto err; + } + } + + if (out) { + gost_init(&cctx,param->sblock); + keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key); + } gkt = GOST_KEY_TRANSPORT_new(); if (!gkt) { @@ -198,117 +165,40 @@ int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, { goto memerr; } - if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) + if (key_is_ephemeral) { + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,out?mykey:pubk)) { GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); goto err; - } + } + if (out) EVP_PKEY_free(mykey); + } ASN1_OBJECT_free(gkt->key_agreement_info->cipher); gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid); - *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out); + *outlen = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL); if (!size) { GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO); size=-1; } GOST_KEY_TRANSPORT_free(gkt); - DH_free(dh); return 1; memerr: + if (key_is_ephemeral) { + EVP_PKEY_free(mykey); + } GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, GOST_R_MALLOC_FAILURE); err: GOST_KEY_TRANSPORT_free(gkt); - DH_free(dh); return -1; } -/* EVP_PKEY_METHOD callback encrypt for - * GOST R 34.10-94 cryptocom modification - */ - -int pkey_GOST94cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * key,size_t key_len) - { - EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx); - struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); - /* create DH structure filling parameters from passed pub_key */ - DH *dh = NULL; - GOST_KEY_TRANSPORT *gkt = NULL; - const struct gost_cipher_info *cipher_info; - gost_ctx cctx; - EVP_PKEY *newkey=NULL; - unsigned char shared_key[32],encrypted_key[32],hmac[4], - iv[8]={0,0,0,0,0,0,0,0}; - - if (! data->eph_seckey) - { - GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, - GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT); - return -1; - } - dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey)); - if (!dh) goto err; - /* compute shared key */ - if (!make_gost_shared_key(dh,pubk,shared_key)) - { - GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY); - goto err; - } - /* encrypt session key */ - cipher_info = get_encryption_params(NULL); - gost_init(&cctx, cipher_info->sblock); - gost_key(&cctx,shared_key); - encrypt_cryptocom_key(key,key_len,encrypted_key,&cctx); - /* compute hmac of session key */ - if (!gost_mac(&cctx,32,key,32,hmac)) - { - DH_free(dh); - GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC); - return -1; - } - gkt = GOST_KEY_TRANSPORT_new(); - if (!gkt) - { - DH_free(dh); - GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_NO_MEMORY); - return -1; - } - /* Store IV which is always zero in our case */ - if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8)) - { - GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_IV); - goto err; - } - if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4)) - { - GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_MAC); - goto err; - } - if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32)) - { - GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY); - goto err; - } - if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) - { - GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); - goto err; - } - ASN1_OBJECT_free(gkt->key_agreement_info->cipher); - gkt->key_agreement_info->cipher = OBJ_nid2obj(cipher_info->nid); - *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out); - err: - if (gkt) GOST_KEY_TRANSPORT_free(gkt); - if (dh) DH_free(dh); - if (newkey) EVP_PKEY_free(newkey); - return 1; - } /* EVP_PLEY_METHOD callback decrypt for * GOST R 34.10-94 cryptopro modification */ int pkey_GOST94cp_decrypt (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len,const unsigned char *in, size_t in_len) { - DH *dh = DH_new(); const unsigned char *p = in; GOST_KEY_TRANSPORT *gkt = |