summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--CHANGES4
-rw-r--r--apps/s_client.c10
-rw-r--r--crypto/dsa/dsa_pmeth.c6
-rw-r--r--crypto/evp/evp.h6
-rw-r--r--crypto/evp/pmeth_fn.c4
-rw-r--r--crypto/evp/pmeth_lib.c5
-rw-r--r--crypto/hmac/hm_pmeth.c3
-rw-r--r--crypto/rsa/rsa_pmeth.c4
-rw-r--r--crypto/x509/x509type.c4
-rw-r--r--engines/ccgost/e_gost_err.c4
-rw-r--r--engines/ccgost/e_gost_err.h4
-rw-r--r--engines/ccgost/gost2001_keyx.c431
-rw-r--r--engines/ccgost/gost94_keyx.c374
-rw-r--r--engines/ccgost/gost_ameth.c73
-rw-r--r--engines/ccgost/gost_crypt.c80
-rw-r--r--engines/ccgost/gost_ctl.c14
-rw-r--r--engines/ccgost/gost_eng.c23
-rw-r--r--engines/ccgost/gost_lcl.h35
-rw-r--r--engines/ccgost/gost_md.c8
-rw-r--r--engines/ccgost/gost_pmeth.c203
-rw-r--r--ssl/d1_enc.c4
-rw-r--r--ssl/s3_clnt.c123
-rw-r--r--ssl/s3_lib.c58
-rw-r--r--ssl/s3_srvr.c95
-rw-r--r--ssl/ssl.h20
-rw-r--r--ssl/ssl_ciph.c6
-rw-r--r--ssl/ssl_err.c7
-rw-r--r--ssl/ssl_lib.c17
-rw-r--r--ssl/t1_enc.c8
-rw-r--r--ssl/t1_lib.c16
-rwxr-xr-xutil/libeay.num1
31 files changed, 699 insertions, 951 deletions
diff --git a/CHANGES b/CHANGES
index eccf5e23df..ab2ea4d6f3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
Changes between 0.9.8g and 0.9.9 [xx XXX xxxx]
+ *) Implement remaining functionality needed to support GOST ciphersuites.
+ Interop testing has been performed using CryptoPro implementations.
+ [Victor B. Wagner <vitus@cryptocom.ru>]
+
*) s390x assembler pack.
[Andy Polyakov]
diff --git a/apps/s_client.c b/apps/s_client.c
index 3ccaca3330..0c3545a4ca 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -1278,6 +1278,7 @@ SSL_set_tlsext_status_ids(con, ids);
if (cbuf_len != 0)
{
BIO_printf(bio_c_out,"shutdown\n");
+ ret = 0;
goto shut;
}
else
@@ -1320,6 +1321,7 @@ SSL_set_tlsext_status_ids(con, ids);
if (i <= 0)
{
BIO_printf(bio_c_out,"DONE\n");
+ ret = 0;
goto shut;
/* goto end; */
}
@@ -1374,10 +1376,12 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240
BIO_printf(bio_c_out,"read X BLOCK\n");
break;
case SSL_ERROR_SYSCALL:
- BIO_printf(bio_err,"read:errno=%d\n",get_last_socket_error());
+ ret=get_last_socket_error();
+ BIO_printf(bio_err,"read:errno=%d\n",ret);
goto shut;
case SSL_ERROR_ZERO_RETURN:
BIO_printf(bio_c_out,"closed\n");
+ ret=0;
goto shut;
case SSL_ERROR_SSL:
ERR_print_errors(bio_err);
@@ -1428,6 +1432,7 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240
if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q')))
{
BIO_printf(bio_err,"DONE\n");
+ ret=0;
goto shut;
}
@@ -1450,12 +1455,13 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240
read_tty=0;
}
}
+
+ ret=0;
shut:
if (in_init)
print_stuff(bio_c_out,con,full_log);
SSL_shutdown(con);
SHUTDOWN(SSL_get_fd(con));
- ret=0;
end:
if (con != NULL)
{
diff --git a/crypto/dsa/dsa_pmeth.c b/crypto/dsa/dsa_pmeth.c
index 935258b24d..646ef3f093 100644
--- a/crypto/dsa/dsa_pmeth.c
+++ b/crypto/dsa/dsa_pmeth.c
@@ -196,7 +196,11 @@ static int pkey_dsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
case EVP_PKEY_CTRL_PKCS7_SIGN:
return 1;
-
+
+ case EVP_PKEY_CTRL_PEER_KEY:
+ DSAerr(DSA_F_PKEY_DSA_CTRL,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
default:
return -2;
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
index 65538d4eac..acb55fafe8 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -1016,8 +1016,12 @@ void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth,
#define EVP_PKEY_CTRL_DIGESTINIT 7
+/* Used by GOST key encryption in TLS */
+#define EVP_PKEY_CTRL_SET_IV 8
+
#define EVP_PKEY_ALG_CTRL 0x1000
+
#define EVP_PKEY_FLAG_AUTOARGLEN 2
const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type);
@@ -1045,6 +1049,8 @@ void EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data);
void *EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx);
EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx);
+EVP_PKEY *EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx);
+
void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index d52dc43f07..7dd0f2083a 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -285,13 +285,13 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
{
int ret;
- if (!ctx || !ctx->pmeth || !ctx->pmeth->derive || !ctx->pmeth->ctrl)
+ if (!ctx || !ctx->pmeth || !(ctx->pmeth->derive||ctx->pmeth->encrypt) || !ctx->pmeth->ctrl)
{
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return -2;
}
- if (ctx->operation != EVP_PKEY_OP_DERIVE)
+ if (ctx->operation != EVP_PKEY_OP_DERIVE && ctx->operation != EVP_PKEY_OP_ENCRYPT)
{
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
EVP_R_OPERATON_NOT_INITIALIZED);
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index 6abb951d0c..764271a36d 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -390,6 +390,11 @@ EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx)
return ctx->pkey;
}
+EVP_PKEY *EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx)
+ {
+ return ctx->peerkey;
+ }
+
void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data)
{
ctx->app_data = data;
diff --git a/crypto/hmac/hm_pmeth.c b/crypto/hmac/hm_pmeth.c
index 27a5c8ea57..6355a44413 100644
--- a/crypto/hmac/hm_pmeth.c
+++ b/crypto/hmac/hm_pmeth.c
@@ -116,7 +116,8 @@ static void pkey_hmac_cleanup(EVP_PKEY_CTX *ctx)
HMAC_CTX_cleanup(&hctx->ctx);
if (hctx->ktmp.data)
{
- OPENSSL_cleanse(hctx->ktmp.data, hctx->ktmp.length);
+ if (hctx->ktmp.length)
+ OPENSSL_cleanse(hctx->ktmp.data, hctx->ktmp.length);
OPENSSL_free(hctx->ktmp.data);
hctx->ktmp.data = NULL;
}
diff --git a/crypto/rsa/rsa_pmeth.c b/crypto/rsa/rsa_pmeth.c
index 98a8ce44c3..de917c637a 100644
--- a/crypto/rsa/rsa_pmeth.c
+++ b/crypto/rsa/rsa_pmeth.c
@@ -436,6 +436,10 @@ static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
case EVP_PKEY_CTRL_PKCS7_DECRYPT:
case EVP_PKEY_CTRL_PKCS7_SIGN:
return 1;
+ case EVP_PKEY_CTRL_PEER_KEY:
+ RSAerr(RSA_F_PKEY_RSA_CTRL,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
default:
return -2;
diff --git a/crypto/x509/x509type.c b/crypto/x509/x509type.c
index 2cd994c5b0..3385ad3f67 100644
--- a/crypto/x509/x509type.c
+++ b/crypto/x509/x509type.c
@@ -91,6 +91,10 @@ int X509_certificate_type(X509 *x, EVP_PKEY *pkey)
break;
case EVP_PKEY_DH:
ret=EVP_PK_DH|EVP_PKT_EXCH;
+ break;
+ case NID_id_GostR3410_94:
+ case NID_id_GostR3410_2001:
+ ret=EVP_PKT_EXCH|EVP_PKT_SIGN;
break;
default:
break;
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)