提交 f0288f05 编写于 作者: D Dr. Stephen Henson

Submitted by: Artem Chuprina <ran@cryptocom.ru>

Reviewed by: steve@openssl.org

Various GOST ciphersuite and ENGINE fixes. Including...

Allow EVP_PKEY_set_derive_peerkey() in encryption operations.

New flag when certificate verify should be omitted in client key exchange.
上级 31db43df
......@@ -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->encrypt) || !ctx->pmeth->ctrl)
if (!ctx || !ctx->pmeth || !(ctx->pmeth->derive||ctx->pmeth->encrypt||ctx->pmeth->decrypt) || !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 && ctx->operation != EVP_PKEY_OP_ENCRYPT)
if (ctx->operation != EVP_PKEY_OP_DERIVE && ctx->operation != EVP_PKEY_OP_ENCRYPT && ctx->operation != EVP_PKEY_OP_DECRYPT)
{
EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER,
EVP_R_OPERATON_NOT_INITIALIZED);
......@@ -319,6 +319,11 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
return -1;
}
/* ran@cryptocom.ru: For clarity. The error is if parameters in peer are
* present (!missing) but don't match. EVP_PKEY_cmp_parameters may return
* 1 (match), 0 (don't match) and -2 (comparison is not defined). -1
* (different key types) is impossible here because it is checked earlier.
* -2 is OK for us here, as well as 1, so we can check for 0 only. */
if (!EVP_PKEY_missing_parameters(peer) &&
!EVP_PKEY_cmp_parameters(ctx->pkey, peer))
{
......@@ -327,6 +332,8 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
return -1;
}
if (ctx->peerkey)
EVP_PKEY_free(ctx->peerkey);
ctx->peerkey = peer;
ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
......
......@@ -37,7 +37,7 @@ EVP_PKEY_ctrl, EVP_PKEY_ctrl_str - algorithm specific control operations
=head1 DESCRIPTION
The function EVP_PKEY_CTX_ctrl() sends a control operation to the context
B<ctx>. The key type used must match B<keytype> if it is not zero. The parameter
B<ctx>. The key type used must match B<keytype> if it is not -1. The parameter
B<optype> is a mask indicating which operations the control can be applied to.
The control command is indicated in B<cmd> and any additional arguments in
B<p1> and B<p2>.
......
/* e_gost_err.c */
/* ====================================================================
* Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved.
* Copyright (c) 1999-2009 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -120,10 +120,12 @@ static ERR_STRING_DATA GOST_str_reasons[]=
{ERR_REASON(GOST_R_BAD_KEY_PARAMETERS_FORMAT),"bad key parameters format"},
{ERR_REASON(GOST_R_BAD_PKEY_PARAMETERS_FORMAT),"bad pkey parameters format"},
{ERR_REASON(GOST_R_CANNOT_PACK_EPHEMERAL_KEY),"cannot pack ephemeral key"},
{ERR_REASON(GOST_R_CTRL_CALL_FAILED) ,"ctrl call failed"},
{ERR_REASON(GOST_R_ERROR_COMPUTING_SHARED_KEY),"error computing shared key"},
{ERR_REASON(GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO),"error packing key transport info"},
{ERR_REASON(GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO),"error parsing key transport info"},
{ERR_REASON(GOST_R_INCOMPATIBLE_ALGORITHMS),"incompatible algorithms"},
{ERR_REASON(GOST_R_INCOMPATIBLE_PEER_KEY),"incompatible peer key"},
{ERR_REASON(GOST_R_INVALID_CIPHER_PARAMS),"invalid cipher params"},
{ERR_REASON(GOST_R_INVALID_CIPHER_PARAM_OID),"invalid cipher param oid"},
{ERR_REASON(GOST_R_INVALID_DIGEST_TYPE) ,"invalid digest type"},
......
......@@ -118,10 +118,12 @@ void ERR_GOST_error(int function, int reason, char *file, int line);
#define GOST_R_BAD_KEY_PARAMETERS_FORMAT 99
#define GOST_R_BAD_PKEY_PARAMETERS_FORMAT 100
#define GOST_R_CANNOT_PACK_EPHEMERAL_KEY 101
#define GOST_R_CTRL_CALL_FAILED 132
#define GOST_R_ERROR_COMPUTING_SHARED_KEY 102
#define GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO 103
#define GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO 104
#define GOST_R_INCOMPATIBLE_ALGORITHMS 105
#define GOST_R_INCOMPATIBLE_PEER_KEY 131
#define GOST_R_INVALID_CIPHER_PARAMS 106
#define GOST_R_INVALID_CIPHER_PARAM_OID 107
#define GOST_R_INVALID_DIGEST_TYPE 108
......
......@@ -203,6 +203,16 @@ int pkey_GOST01cp_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_le
ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid);
if (key_is_ephemeral && sec_key) EVP_PKEY_free(sec_key);
if (!key_is_ephemeral)
{
/* Set control "public key from client certificate used" */
if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0)
{
GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT,
GOST_R_CTRL_CALL_FAILED);
goto err;
}
}
if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL))>0) ret =1;
GOST_KEY_TRANSPORT_free(gkt);
return ret;
......@@ -225,7 +235,7 @@ int pkey_GOST01cp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_l
unsigned char sharedKey[32];
gost_ctx ctx;
const struct gost_cipher_info *param=NULL;
EVP_PKEY *eph_key=NULL;
EVP_PKEY *eph_key=NULL, *peerkey=NULL;
if (!key)
{
......@@ -239,18 +249,35 @@ int pkey_GOST01cp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_l
GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
return -1;
}
/* If key transport structure contains public key, use it */
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) {
if (eph_key)
{
if (EVP_PKEY_derive_set_peer(pctx, eph_key) <= 0)
{
GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,
GOST_R_NO_PEER_KEY);
GOST_R_INCOMPATIBLE_PEER_KEY);
goto err;
}
}
else
{
/* Set control "public key from client certificate used" */
if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0)
{
GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,
GOST_R_CTRL_CALL_FAILED);
goto err;
}
}
peerkey = EVP_PKEY_CTX_get0_peerkey(pctx);
if (!peerkey)
{
GOSTerr(GOST_F_PKEY_GOST01CP_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);
......@@ -260,7 +287,7 @@ int pkey_GOST01cp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_l
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);
VKO_compute_key(sharedKey,32,EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key)),
VKO_compute_key(sharedKey,32,EC_KEY_get0_public_key(EVP_PKEY_get0(peerkey)),
EVP_PKEY_get0(priv),wrappedKey);
if (!keyUnwrapCryptoPro(&ctx,sharedKey,wrappedKey,key))
{
......@@ -269,9 +296,9 @@ int pkey_GOST01cp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_l
goto err;
}
EVP_PKEY_free(eph_key);
GOST_KEY_TRANSPORT_free(gkt);
ret=1;
err:
if (eph_key) EVP_PKEY_free(eph_key);
if (gkt) GOST_KEY_TRANSPORT_free(gkt);
return ret;
}
......@@ -92,7 +92,6 @@ int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
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);
......@@ -178,10 +177,20 @@ int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid);
*outlen = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL);
if (!size)
if (*outlen <= 0)
{
GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO);
size=-1;
goto err;
}
if (!key_is_ephemeral)
{
/* Set control "public key from client certificate used" */
if (EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0)
{
GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,
GOST_R_CTRL_CALL_FAILED);
goto err;
}
}
GOST_KEY_TRANSPORT_free(gkt);
return 1;
......@@ -207,7 +216,7 @@ int pkey_GOST94cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len
unsigned char sharedKey[32];
gost_ctx cctx;
const struct gost_cipher_info *param=NULL;
EVP_PKEY *eph_key=NULL;
EVP_PKEY *eph_key=NULL, *peerkey=NULL;
EVP_PKEY *priv= EVP_PKEY_CTX_get0_pkey(ctx);
if (!key)
......@@ -224,19 +233,32 @@ int pkey_GOST94cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len
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) {
if (eph_key)
{
if (EVP_PKEY_derive_set_peer(ctx, eph_key) <= 0)
{
GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,
GOST_R_NO_PEER_KEY);
GOST_R_INCOMPATIBLE_PEER_KEY);
goto err;
}
}
else
{
/* Set control "public key from client certificate used" */
if (EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0)
{
GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,
GOST_R_CTRL_CALL_FAILED);
goto err;
}
}
peerkey = EVP_PKEY_CTX_get0_peerkey(ctx);
if (!peerkey)
{
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);
......@@ -246,7 +268,7 @@ int pkey_GOST94cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len
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(gost_get0_priv_key(priv),eph_key,sharedKey);
make_cp_exchange_key(gost_get0_priv_key(priv),peerkey,sharedKey);
if (!keyUnwrapCryptoPro(&cctx,sharedKey,wrappedKey,key))
{
GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,
......
......@@ -27,7 +27,7 @@ IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_INFO)
ASN1_NDEF_SEQUENCE(GOST_KEY_AGREEMENT_INFO) = {
ASN1_SIMPLE(GOST_KEY_AGREEMENT_INFO, cipher, ASN1_OBJECT),
ASN1_IMP(GOST_KEY_AGREEMENT_INFO, ephem_key, X509_PUBKEY, 0),
ASN1_IMP_OPT(GOST_KEY_AGREEMENT_INFO, ephem_key, X509_PUBKEY, 0),
ASN1_SIMPLE(GOST_KEY_AGREEMENT_INFO, eph_iv, ASN1_OCTET_STRING)
} ASN1_NDEF_SEQUENCE_END(GOST_KEY_AGREEMENT_INFO)
......
......@@ -47,6 +47,7 @@
int sign_param_nid; /* Should be set whenever parameters are filled */
EVP_MD *md;
unsigned char *shared_ukm;
int peer_key_used;
};
struct gost_mac_pmeth_data {
......
......@@ -98,7 +98,14 @@ static int pkey_gost_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
pctx->shared_ukm=OPENSSL_malloc((int)p1);
memcpy(pctx->shared_ukm,p2,(int) p1);
return 1;
case EVP_PKEY_CTRL_PEER_KEY:
if (p1 == 0 || p1 == 1) /* call from EVP_PKEY_derive_set_peer */
return 1;
if (p1 == 2) /* TLS: peer key used? */
return pctx->peer_key_used;
if (p1 == 3) /* TLS: peer key used! */
return (pctx->peer_key_used = 1);
return -2;
}
return -2;
}
......
......@@ -404,6 +404,11 @@ int ssl3_connect(SSL *s)
s->state=SSL3_ST_CW_CHANGE_A;
s->s3->change_cipher_spec=0;
}
if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
{
s->state=SSL3_ST_CW_CHANGE_A;
s->s3->change_cipher_spec=0;
}
s->init_num=0;
break;
......@@ -2416,7 +2421,7 @@ int ssl3_send_client_key_exchange(SSL *s)
size_t msglen;
unsigned int md_len;
int keytype;
unsigned char premaster_secret[32],shared_ukm[32];
unsigned char premaster_secret[32],shared_ukm[32], tmp[256];
EVP_MD_CTX *ukm_hash;
EVP_PKEY *pub_key;
......@@ -2442,16 +2447,13 @@ int ssl3_send_client_key_exchange(SSL *s)
/* Generate session key */
RAND_bytes(premaster_secret,32);
/* If we have client certificate, use its secret as peer key */
if (s->cert->key->privatekey) {
if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <0) {
if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <=0) {
/* If there was an error - just ignore it. Ephemeral key
* would be used
*/
ERR_clear_error();
} else {
/* Set flag "client cert key is used for key
* exchange"*/
}
}
}
/* Compute shared IV and store it in algorithm-specific
* context data */
......@@ -2470,15 +2472,30 @@ int ssl3_send_client_key_exchange(SSL *s)
/* Make GOST keytransport blob message */
/*Encapsulate it into sequence */
*(p++)=V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
*(p++)=0x81;
msglen=256;
if (EVP_PKEY_encrypt(pkey_ctx,(unsigned char *)p+1,&msglen,premaster_secret,32)<0) {
msglen=255;
if (EVP_PKEY_encrypt(pkey_ctx,tmp,&msglen,premaster_secret,32)<0) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
SSL_R_LIBRARY_BUG);
goto err;
}
*(p++)= msglen & 0xff;
n=msglen+3;
}
if (msglen >= 0x80)
{
*(p++)=0x81;
*(p++)= msglen & 0xff;
n=msglen+3;
}
else
{
*(p++)= msglen & 0xff;
n=msglen+2;
}
memcpy(p, tmp, msglen);
/* Check if pubkey from client certificate was used */
if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
{
/* Set flag "skip certificate verify" */
s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
}
EVP_PKEY_CTX_free(pkey_ctx);
s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
......
......@@ -514,6 +514,9 @@ int ssl3_accept(SSL *s)
* the client sends its ECDH pub key in
* a certificate, the CertificateVerify
* message is not sent.
* Also for GOST ciphersuites when
* the client uses its key from the certificate
* for key exchange.
*/
s->state=SSL3_ST_SR_FINISHED_A;
s->init_num = 0;
......@@ -2496,33 +2499,70 @@ int ssl3_get_client_key_exchange(SSL *s)
else
#endif
if (alg_k & SSL_kGOST)
{
{
int ret = 0;
EVP_PKEY_CTX *pkey_ctx;
unsigned char premaster_secret[32];
size_t outlen;
EVP_PKEY *client_pub_pkey = NULL;
unsigned char premaster_secret[32], *start;
size_t outlen, inlen;
/* Get our certificate privatec key*/
/* Get our certificate private key*/
pkey_ctx = EVP_PKEY_CTX_new(s->cert->key->privatekey,NULL);
EVP_PKEY_decrypt_init(pkey_ctx);
/* If client certificate is present and is of the same type, maybe
* use it for key exchange. Don't mind errors from
* EVP_PKEY_derive_set_peer, because it is completely valid to use
* a client certificate for authorization only. */
client_pub_pkey = X509_get_pubkey(s->session->peer);
if (client_pub_pkey)
{
if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
ERR_clear_error();
}
/* Decrypt session key */
if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)) || p[1]!=0x81 )
if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)))
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
goto err;
}
if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,p+3,p[2]) <0)
goto gerr;
}
if (p[1] == 0x81)
{
start = p+3;
inlen = p[2];
}
else if (p[1] < 0x80)
{
start = p+2;
inlen = p[1];
}
else
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
goto gerr;
}
if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
goto err;
goto gerr;
}
/* Generate master secret */
EVP_PKEY_CTX_free(pkey_ctx);
s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key,premaster_secret,32);
}
/* Check if pubkey from client certificate was used */
if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
ret = 2;
else
ret = 1;
gerr:
EVP_PKEY_free(client_pub_pkey);
EVP_PKEY_CTX_free(pkey_ctx);
if (ret)
return ret;
else
goto err;
}
else
{
al=SSL_AD_HANDSHAKE_FAILURE;
......
......@@ -375,6 +375,7 @@ typedef struct ssl3_buffer_st
#define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002
#define SSL3_FLAGS_POP_BUFFER 0x0004
#define TLS1_FLAGS_TLS_PADDING_BUG 0x0008
#define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010
typedef struct ssl3_state_st
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册