summaryrefslogtreecommitdiffstats
path: root/engines/ccgost/gost94_keyx.c
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2007-10-26 12:06:36 +0000
committerDr. Stephen Henson <steve@openssl.org>2007-10-26 12:06:36 +0000
commit0e1dba934fa53e9736e9156b9e25bd1010290149 (patch)
treee52e12fa1147b634c215263e93d77c8c9830b39b /engines/ccgost/gost94_keyx.c
parent11d01d371f67a9cacfeccb1078669c595d65002f (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/gost94_keyx.c')
-rw-r--r--engines/ccgost/gost94_keyx.c374
1 files changed, 96 insertions, 278 deletions
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 = NULL;
unsigned char wrappedKey[44];
@@ -324,18 +214,28 @@ int pkey_GOST94cp_decrypt (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_le
return 1;
}
- dh->g = BN_dup(priv->pkey.dsa->g);
- dh->p = BN_dup(priv->pkey.dsa->p);
- dh->priv_key = BN_dup(priv->pkey.dsa->priv_key);
gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
in_len);
if (!gkt)
{
GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
- DH_free(dh);
return 0;
}
eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
+ /* No ephemeral key in the structure. Check peer key in the context
+ */
+ if (!eph_key) {
+ eph_key = EVP_PKEY_CTX_get0_peerkey(ctx);
+ 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(&cctx,param->sblock);
OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
@@ -344,7 +244,7 @@ int pkey_GOST94cp_decrypt (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_le
memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32);
OPENSSL_assert(gkt->key_info->imit->length==4);
memcpy(wrappedKey+40,gkt->key_info->imit->data,4);
- make_cp_exchange_key(dh,eph_key,sharedKey);
+ make_cp_exchange_key(gost_get0_priv_key(priv),eph_key,sharedKey);
if (!keyUnwrapCryptoPro(&cctx,sharedKey,wrappedKey,key))
{
GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,
@@ -354,92 +254,10 @@ int pkey_GOST94cp_decrypt (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_le
EVP_PKEY_free(eph_key);
GOST_KEY_TRANSPORT_free(gkt);
- DH_free(dh);
return 1;
err:
EVP_PKEY_free(eph_key);
GOST_KEY_TRANSPORT_free(gkt);
- DH_free(dh);
return -1;
}
-/* EVP_PKEY_METHOD callback decrypt for
- * GOST R 34.10-94 cryptocom modification
- */
-
-int pkey_GOST94cc_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 */
- 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;
- DH *dh = DH_new();
- EVP_PKEY *eph_key;
- EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
-
- if (!key)
- {
- *key_len = 32;
- return 1;
- }
- /* Construct DH structure from the our GOST private key */
- dh->g = BN_dup(priv->pkey.dsa->g);
- dh->p = BN_dup(priv->pkey.dsa->p);
- dh->priv_key = BN_dup(priv->pkey.dsa->priv_key);
- /* 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_GOST94CC_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
- DH_free(dh);
- 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 */
- i=make_gost_shared_key(dh,eph_key,shared_key);
- EVP_PKEY_free(eph_key);
- DH_free(dh);
- if (!i)
- {
- GOSTerr(GOST_F_PKEY_GOST94CC_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_GOST94CC_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_GOST94CC_DECRYPT,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH);
- return 0;
- }
- return 1;
- }