From f0288f05b92c3c206a515691f548b857f6aaa194 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Tue, 16 Jun 2009 16:38:47 +0000 Subject: [PATCH] Submitted by: Artem Chuprina 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. --- crypto/evp/pmeth_fn.c | 11 +++++- doc/crypto/EVP_PKEY_CTX_ctrl.pod | 2 +- engines/ccgost/e_gost_err.c | 4 +- engines/ccgost/e_gost_err.h | 2 + engines/ccgost/gost2001_keyx.c | 51 +++++++++++++++++++------ engines/ccgost/gost94_keyx.c | 52 ++++++++++++++++++-------- engines/ccgost/gost_asn1.c | 2 +- engines/ccgost/gost_lcl.h | 1 + engines/ccgost/gost_pmeth.c | 9 ++++- ssl/s3_clnt.c | 43 ++++++++++++++------- ssl/s3_srvr.c | 64 ++++++++++++++++++++++++++------ ssl/ssl3.h | 1 + 12 files changed, 184 insertions(+), 58 deletions(-) diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c index edd1efa6df..c4676f2f8d 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->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); diff --git a/doc/crypto/EVP_PKEY_CTX_ctrl.pod b/doc/crypto/EVP_PKEY_CTX_ctrl.pod index 6deccfbf95..37e2b72323 100644 --- a/doc/crypto/EVP_PKEY_CTX_ctrl.pod +++ b/doc/crypto/EVP_PKEY_CTX_ctrl.pod @@ -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. The key type used must match B if it is not zero. The parameter +B. The key type used must match B if it is not -1. The parameter B is a mask indicating which operations the control can be applied to. The control command is indicated in B and any additional arguments in B and B. diff --git a/engines/ccgost/e_gost_err.c b/engines/ccgost/e_gost_err.c index 469027051a..9a79a374e2 100644 --- a/engines/ccgost/e_gost_err.c +++ b/engines/ccgost/e_gost_err.c @@ -1,6 +1,6 @@ /* 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"}, diff --git a/engines/ccgost/e_gost_err.h b/engines/ccgost/e_gost_err.h index 652d1bb392..6dc500079d 100644 --- a/engines/ccgost/e_gost_err.h +++ b/engines/ccgost/e_gost_err.h @@ -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 diff --git a/engines/ccgost/gost2001_keyx.c b/engines/ccgost/gost2001_keyx.c index 3b5a78ac3d..00759bcab0 100644 --- a/engines/ccgost/gost2001_keyx.c +++ b/engines/ccgost/gost2001_keyx.c @@ -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; } diff --git a/engines/ccgost/gost94_keyx.c b/engines/ccgost/gost94_keyx.c index 5d04a17821..624be586a5 100644 --- a/engines/ccgost/gost94_keyx.c +++ b/engines/ccgost/gost94_keyx.c @@ -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, diff --git a/engines/ccgost/gost_asn1.c b/engines/ccgost/gost_asn1.c index 76c18c1c66..318ecfce57 100644 --- a/engines/ccgost/gost_asn1.c +++ b/engines/ccgost/gost_asn1.c @@ -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) diff --git a/engines/ccgost/gost_lcl.h b/engines/ccgost/gost_lcl.h index 81fecd38a2..437a48cc86 100644 --- a/engines/ccgost/gost_lcl.h +++ b/engines/ccgost/gost_lcl.h @@ -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 { diff --git a/engines/ccgost/gost_pmeth.c b/engines/ccgost/gost_pmeth.c index 2861d38327..caaea99d36 100644 --- a/engines/ccgost/gost_pmeth.c +++ b/engines/ccgost/gost_pmeth.c @@ -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; } diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index e0bfd0ceaf..861ce30138 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -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, diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 44065d7e89..66c063a7ba 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -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; diff --git a/ssl/ssl3.h b/ssl/ssl3.h index c2db3bd636..a4a6ce28c3 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -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 { -- GitLab