Submitted by: Artem Chuprina <ran@cryptocom.ru>
authorDr. Stephen Henson <steve@openssl.org>
Tue, 16 Jun 2009 16:38:47 +0000 (16:38 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 16 Jun 2009 16:38:47 +0000 (16:38 +0000)
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.

12 files changed:
crypto/evp/pmeth_fn.c
doc/crypto/EVP_PKEY_CTX_ctrl.pod
engines/ccgost/e_gost_err.c
engines/ccgost/e_gost_err.h
engines/ccgost/gost2001_keyx.c
engines/ccgost/gost94_keyx.c
engines/ccgost/gost_asn1.c
engines/ccgost/gost_lcl.h
engines/ccgost/gost_pmeth.c
ssl/s3_clnt.c
ssl/s3_srvr.c
ssl/ssl3.h

index edd1efa..c4676f2 100644 (file)
@@ -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);
index 6deccfb..37e2b72 100644 (file)
@@ -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>.
index 4690270..9a79a37 100644 (file)
@@ -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"},
index 652d1bb..6dc5000 100644 (file)
@@ -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
index 3b5a78a..00759bc 100644 (file)
@@ -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;
        }
index 5d04a17..624be58 100644 (file)
@@ -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,
index 76c18c1..318ecfc 100644 (file)
@@ -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)
 
index 81fecd3..437a48c 100644 (file)
@@ -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 {
index 2861d38..caaea99 100644 (file)
@@ -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;
        }
index e0bfd0c..861ce30 100644 (file)
@@ -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,
index 44065d7..66c063a 100644 (file)
@@ -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;
index c2db3bd..a4a6ce2 100644 (file)
@@ -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
        {