From HEAD:
[openssl.git] / ssl / s3_clnt.c
index 4a34b445ee94f2a167856c42d1e56de5d803e99e..23875f00e0e082b55548c03d151eba3e47ffb6f2 100644 (file)
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2007 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
 
 static const SSL_METHOD *ssl3_get_client_method(int ver);
 static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl3_check_finished(SSL *s);
+#endif
 
 static const SSL_METHOD *ssl3_get_client_method(int ver)
        {
@@ -180,7 +183,7 @@ IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
 int ssl3_connect(SSL *s)
        {
        BUF_MEM *buf=NULL;
-       unsigned long Time=(unsigned long)time(NULL),l;
+       unsigned long Time=(unsigned long)time(NULL);
        long num1;
        void (*cb)(const SSL *ssl,int type,int val)=NULL;
        int ret= -1;
@@ -286,17 +289,45 @@ int ssl3_connect(SSL *s)
 
                case SSL3_ST_CR_CERT_A:
                case SSL3_ST_CR_CERT_B:
+#ifndef OPENSSL_NO_TLSEXT
+                       ret=ssl3_check_finished(s);
+                       if (ret <= 0) goto end;
+                       if (ret == 2)
+                               {
+                               s->hit = 1;
+                               if (s->tlsext_ticket_expected)
+                                       s->state=SSL3_ST_CR_SESSION_TICKET_A;
+                               else
+                                       s->state=SSL3_ST_CR_FINISHED_A;
+                               s->init_num=0;
+                               break;
+                               }
+#endif
                        /* Check if it is anon DH/ECDH */
                        /* or PSK */
-                       if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL)
-                               && !(s->s3->tmp.new_cipher->algorithms & SSL_kPSK))
+                       if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
+                           !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK))
                                {
                                ret=ssl3_get_server_certificate(s);
                                if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+                               if (s->tlsext_status_expected)
+                                       s->state=SSL3_ST_CR_CERT_STATUS_A;
+                               else
+                                       s->state=SSL3_ST_CR_KEY_EXCH_A;
+                               }
+                       else
+                               {
+                               skip = 1;
+                               s->state=SSL3_ST_CR_KEY_EXCH_A;
+                               }
+#else
                                }
                        else
                                skip=1;
+
                        s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
                        s->init_num=0;
                        break;
 
@@ -350,7 +381,6 @@ int ssl3_connect(SSL *s)
                case SSL3_ST_CW_KEY_EXCH_B:
                        ret=ssl3_send_client_key_exchange(s);
                        if (ret <= 0) goto end;
-                       l=s->s3->tmp.new_cipher->algorithms;
                        /* EAY EAY EAY need to check for DH fix cert
                         * sent back */
                        /* For TLS, cert_req is set to 2, so a cert chain
@@ -440,11 +470,36 @@ int ssl3_connect(SSL *s)
                                }
                        else
                                {
+#ifndef OPENSSL_NO_TLSEXT
+                               /* Allow NewSessionTicket if ticket expected */
+                               if (s->tlsext_ticket_expected)
+                                       s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+                               else
+#endif
+                               
                                s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
                                }
                        s->init_num=0;
                        break;
 
+#ifndef OPENSSL_NO_TLSEXT
+               case SSL3_ST_CR_SESSION_TICKET_A:
+               case SSL3_ST_CR_SESSION_TICKET_B:
+                       ret=ssl3_get_new_session_ticket(s);
+                       if (ret <= 0) goto end;
+                       s->state=SSL3_ST_CR_FINISHED_A;
+                       s->init_num=0;
+               break;
+
+               case SSL3_ST_CR_CERT_STATUS_A:
+               case SSL3_ST_CR_CERT_STATUS_B:
+                       ret=ssl3_get_cert_status(s);
+                       if (ret <= 0) goto end;
+                       s->state=SSL3_ST_CR_KEY_EXCH_A;
+                       s->init_num=0;
+               break;
+#endif
+
                case SSL3_ST_CR_FINISHED_A:
                case SSL3_ST_CR_FINISHED_B:
 
@@ -626,7 +681,9 @@ int ssl3_client_hello(SSL *s)
                        }
 #endif
                *(p++)=0; /* Add the NULL method */
+
 #ifndef OPENSSL_NO_TLSEXT
+               /* TLS extensions*/
                if (ssl_prepare_clienthello_tlsext(s) <= 0)
                        {
                        SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
@@ -672,7 +729,7 @@ int ssl3_get_server_hello(SSL *s)
                SSL3_ST_CR_SRVR_HELLO_A,
                SSL3_ST_CR_SRVR_HELLO_B,
                -1,
-               300, /* ?? */
+               20000, /* ?? */
                &ok);
 
        if (!ok) return((int)n);
@@ -794,6 +851,7 @@ int ssl3_get_server_hello(SSL *s)
                        }
                }
        s->s3->tmp.new_cipher=c;
+       ssl3_digest_cached_records(s);
 
        /* lets get the compression algorithm */
        /* COMPRESSION */
@@ -822,6 +880,7 @@ int ssl3_get_server_hello(SSL *s)
                s->s3->tmp.new_compression=comp;
                }
 #endif
+
 #ifndef OPENSSL_NO_TLSEXT
        /* TLS extensions*/
        if (s->version > SSL3_VERSION)
@@ -834,7 +893,7 @@ int ssl3_get_server_hello(SSL *s)
                        }
                if (ssl_check_serverhello_tlsext(s) <= 0)
                        {
-                       SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SERVERHELLO_TLSEXT);
+                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
                                goto err;
                        }
                }
@@ -940,10 +999,10 @@ int ssl3_get_server_certificate(SSL *s)
        i=ssl_verify_cert_chain(s,sk);
        if ((s->verify_mode != SSL_VERIFY_NONE) && (!i)
 #ifndef OPENSSL_NO_KRB5
-               && (s->s3->tmp.new_cipher->algorithms & (SSL_MKEY_MASK|SSL_AUTH_MASK))
-               != (SSL_aKRB5|SSL_kKRB5)
+           && !((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
+                (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
 #endif /* OPENSSL_NO_KRB5 */
-               )
+               )
                {
                al=ssl_verify_alarm_type(s->verify_result);
                SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
@@ -967,15 +1026,15 @@ int ssl3_get_server_certificate(SSL *s)
        pkey=X509_get_pubkey(x);
 
        /* VRS: allow null cert if auth == KRB5 */
-       need_cert =     ((s->s3->tmp.new_cipher->algorithms
-                        & (SSL_MKEY_MASK|SSL_AUTH_MASK))
-                        == (SSL_aKRB5|SSL_kKRB5))? 0: 1;
+       need_cert = ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
+                   (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
+                   ? 0 : 1;
 
 #ifdef KSSL_DEBUG
        printf("pkey,x = %p, %p\n", pkey,x);
        printf("ssl_cert_type(x,pkey) = %d\n", ssl_cert_type(x,pkey));
-       printf("cipher, alg, nc = %s, %lx, %d\n", s->s3->tmp.new_cipher->name,
-               s->s3->tmp.new_cipher->algorithms, need_cert);
+       printf("cipher, alg, nc = %s, %lx, %lx, %d\n", s->s3->tmp.new_cipher->name,
+               s->s3->tmp.new_cipher->algorithm_mkey, s->s3->tmp.new_cipher->algorithm_auth, need_cert);
 #endif    /* KSSL_DEBUG */
 
        if (need_cert && ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey)))
@@ -1047,7 +1106,7 @@ int ssl3_get_key_exchange(SSL *s)
        EVP_MD_CTX md_ctx;
        unsigned char *param,*p;
        int al,i,j,param_len,ok;
-       long n,alg;
+       long n,alg_k,alg_a;
        EVP_PKEY *pkey=NULL;
 #ifndef OPENSSL_NO_RSA
        RSA *rsa=NULL;
@@ -1080,7 +1139,7 @@ int ssl3_get_key_exchange(SSL *s)
                   omitted if no identity hint is sent. Set
                   session->sess_cert anyway to avoid problems
                   later.*/
-                if (s->s3->tmp.new_cipher->algorithms & SSL_kPSK)
+               if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)
                        {
                        s->session->sess_cert=ssl_sess_cert_new();
                        if (s->ctx->psk_identity_hint)
@@ -1123,12 +1182,13 @@ int ssl3_get_key_exchange(SSL *s)
                }
 
        param_len=0;
-       alg=s->s3->tmp.new_cipher->algorithms;
+       alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+       alg_a=s->s3->tmp.new_cipher->algorithm_auth;
        EVP_MD_CTX_init(&md_ctx);
 
 #ifndef OPENSSL_NO_PSK
-       if (alg & SSL_kPSK)
-               {
+       if (alg_k & SSL_kPSK)
+               {
                char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1];
 
                al=SSL_AD_HANDSHAKE_FAILURE;
@@ -1164,7 +1224,7 @@ int ssl3_get_key_exchange(SSL *s)
                        {
                        SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
                        goto f_err;
-                       }           
+                       }          
 
                p+=i;
                n-=param_len;
@@ -1172,7 +1232,7 @@ int ssl3_get_key_exchange(SSL *s)
        else
 #endif /* !OPENSSL_NO_PSK */
 #ifndef OPENSSL_NO_RSA
-       if (alg & SSL_kRSA)
+       if (alg_k & SSL_kRSA)
                {
                if ((rsa=RSA_new()) == NULL)
                        {
@@ -1211,7 +1271,7 @@ int ssl3_get_key_exchange(SSL *s)
                n-=param_len;
 
                /* this should be because we are using an export cipher */
-               if (alg & SSL_aRSA)
+               if (alg_a & SSL_aRSA)
                        pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
                else
                        {
@@ -1226,7 +1286,7 @@ int ssl3_get_key_exchange(SSL *s)
                ;
 #endif
 #ifndef OPENSSL_NO_DH
-       else if (alg & SSL_kEDH)
+       else if (alg_k & SSL_kEDH)
                {
                if ((dh=DH_new()) == NULL)
                        {
@@ -1280,14 +1340,14 @@ int ssl3_get_key_exchange(SSL *s)
                n-=param_len;
 
 #ifndef OPENSSL_NO_RSA
-               if (alg & SSL_aRSA)
+               if (alg_a & SSL_aRSA)
                        pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
 #else
                if (0)
                        ;
 #endif
 #ifndef OPENSSL_NO_DSA
-               else if (alg & SSL_aDSS)
+               else if (alg_a & SSL_aDSS)
                        pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
 #endif
                /* else anonymous DH, so no certificate or pkey. */
@@ -1295,7 +1355,7 @@ int ssl3_get_key_exchange(SSL *s)
                s->session->sess_cert->peer_dh_tmp=dh;
                dh=NULL;
                }
-       else if ((alg & SSL_kDHr) || (alg & SSL_kDHd))
+       else if ((alg_k & SSL_kDHr) || (alg_k & SSL_kDHd))
                {
                al=SSL_AD_ILLEGAL_PARAMETER;
                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER);
@@ -1304,7 +1364,7 @@ int ssl3_get_key_exchange(SSL *s)
 #endif /* !OPENSSL_NO_DH */
 
 #ifndef OPENSSL_NO_ECDH
-       else if (alg & SSL_kEECDH)
+       else if (alg_k & SSL_kEECDH)
                {
                EC_GROUP *ngroup;
                const EC_GROUP *group;
@@ -1388,11 +1448,11 @@ int ssl3_get_key_exchange(SSL *s)
                 */
                if (0) ;
 #ifndef OPENSSL_NO_RSA
-               else if (alg & SSL_aRSA)
+               else if (alg_a & SSL_aRSA)
                        pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
 #endif
 #ifndef OPENSSL_NO_ECDSA
-               else if (alg & SSL_aECDSA)
+               else if (alg_a & SSL_aECDSA)
                        pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
 #endif
                /* else anonymous ECDH, so no certificate or pkey. */
@@ -1403,7 +1463,7 @@ int ssl3_get_key_exchange(SSL *s)
                EC_POINT_free(srvr_ecpoint);
                srvr_ecpoint = NULL;
                }
-       else if (alg)
+       else if (alg_k)
                {
                al=SSL_AD_UNEXPECTED_MESSAGE;
                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
@@ -1508,7 +1568,7 @@ int ssl3_get_key_exchange(SSL *s)
                }
        else
                {
-               if (!(alg & SSL_aNULL) && !(alg & SSL_kPSK))
+               if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK))
                        /* aNULL or kPSK do not need public keys */
                        {
                        SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
@@ -1584,8 +1644,7 @@ int ssl3_get_certificate_request(SSL *s)
        /* TLS does not like anon-DH with client cert */
        if (s->version > SSL3_VERSION)
                {
-               l=s->s3->tmp.new_cipher->algorithms;
-               if (l & SSL_aNULL)
+               if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
                        {
                        ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
                        SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER);
@@ -1694,6 +1753,142 @@ static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
        {
        return(X509_NAME_cmp(*a,*b));
        }
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_get_new_session_ticket(SSL *s)
+       {
+       int ok,al,ret=0, ticklen;
+       long n;
+       const unsigned char *p;
+       unsigned char *d;
+
+       n=s->method->ssl_get_message(s,
+               SSL3_ST_CR_SESSION_TICKET_A,
+               SSL3_ST_CR_SESSION_TICKET_B,
+               -1,
+               16384,
+               &ok);
+
+       if (!ok)
+               return((int)n);
+
+       if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
+               {
+               s->s3->tmp.reuse_message=1;
+               return(1);
+               }
+       if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET)
+               {
+               al=SSL_AD_UNEXPECTED_MESSAGE;
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_BAD_MESSAGE_TYPE);
+               goto f_err;
+               }
+       if (n < 6)
+               {
+               /* need at least ticket_lifetime_hint + ticket length */
+               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       p=d=(unsigned char *)s->init_msg;
+       n2l(p, s->session->tlsext_tick_lifetime_hint);
+       n2s(p, ticklen);
+       /* ticket_lifetime_hint + ticket_length + ticket */
+       if (ticklen + 6 != n)
+               {
+               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       if (s->session->tlsext_tick)
+               {
+               OPENSSL_free(s->session->tlsext_tick);
+               s->session->tlsext_ticklen = 0;
+               }
+       s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+       if (!s->session->tlsext_tick)
+               {
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
+               goto err;
+               }
+       memcpy(s->session->tlsext_tick, p, ticklen);
+       s->session->tlsext_ticklen = ticklen;
+       
+       ret=1;
+       return(ret);
+f_err:
+       ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+       return(-1);
+       }
+
+int ssl3_get_cert_status(SSL *s)
+       {
+       int ok, al;
+       unsigned long resplen,n;
+       const unsigned char *p;
+
+       n=s->method->ssl_get_message(s,
+               SSL3_ST_CR_CERT_STATUS_A,
+               SSL3_ST_CR_CERT_STATUS_B,
+               SSL3_MT_CERTIFICATE_STATUS,
+               16384,
+               &ok);
+
+       if (!ok) return((int)n);
+       if (n < 4)
+               {
+               /* need at least status type + length */
+               al = SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       p = (unsigned char *)s->init_msg;
+       if (*p++ != TLSEXT_STATUSTYPE_ocsp)
+               {
+               al = SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_UNSUPPORTED_STATUS_TYPE);
+               goto f_err;
+               }
+       n2l3(p, resplen);
+       if (resplen + 4 != n)
+               {
+               al = SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       if (s->tlsext_ocsp_resp)
+               OPENSSL_free(s->tlsext_ocsp_resp);
+       s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
+       if (!s->tlsext_ocsp_resp)
+               {
+               al = SSL_AD_INTERNAL_ERROR;
+               SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+               goto f_err;
+               }
+       s->tlsext_ocsp_resplen = resplen;
+       if (s->ctx->tlsext_status_cb)
+               {
+               int ret;
+               ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+               if (ret == 0)
+                       {
+                       al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+                       SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_INVALID_STATUS_RESPONSE);
+                       goto f_err;
+                       }
+               if (ret < 0)
+                       {
+                       al = SSL_AD_INTERNAL_ERROR;
+                       SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+                       goto f_err;
+                       }
+               }
+       return 1;
+f_err:
+       ssl3_send_alert(s,SSL3_AL_FATAL,al);
+       return(-1);
+       }
+#endif
 
 int ssl3_get_server_done(SSL *s)
        {
@@ -1724,7 +1919,7 @@ int ssl3_send_client_key_exchange(SSL *s)
        {
        unsigned char *p,*d;
        int n;
-       unsigned long l;
+       unsigned long alg_k;
 #ifndef OPENSSL_NO_RSA
        unsigned char *q;
        EVP_PKEY *pkey=NULL;
@@ -1746,12 +1941,12 @@ int ssl3_send_client_key_exchange(SSL *s)
                d=(unsigned char *)s->init_buf->data;
                p= &(d[4]);
 
-               l=s->s3->tmp.new_cipher->algorithms;
+               alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
 
                /* Fool emacs indentation */
                if (0) {}
 #ifndef OPENSSL_NO_RSA
-               else if (l & SSL_kRSA)
+               else if (alg_k & SSL_kRSA)
                        {
                        RSA *rsa;
                        unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
@@ -1810,7 +2005,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                        }
 #endif
 #ifndef OPENSSL_NO_KRB5
-               else if (l & SSL_kKRB5)
+               else if (alg_k & SSL_kKRB5)
                        {
                        krb5_error_code krb5rc;
                        KSSL_CTX        *kssl_ctx = s->kssl_ctx;
@@ -1829,7 +2024,7 @@ int ssl3_send_client_key_exchange(SSL *s)
 
 #ifdef KSSL_DEBUG
                        printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
-                               l, SSL_kKRB5);
+                               alg_k, SSL_kKRB5);
 #endif /* KSSL_DEBUG */
 
                        authp = NULL;
@@ -1935,7 +2130,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                        n+=outl + 2;
 
                        s->session->master_key_length=
-                               s->method->ssl3_enc->generate_master_secret(s,
+                               s->method->ssl3_enc->generate_master_secret(s,
                                        s->session->master_key,
                                        tmp_buf, sizeof tmp_buf);
 
@@ -1944,10 +2139,17 @@ int ssl3_send_client_key_exchange(SSL *s)
                        }
 #endif
 #ifndef OPENSSL_NO_DH
-               else if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+               else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
                        {
                        DH *dh_srvr,*dh_clnt;
 
+                       if (s->session->sess_cert == NULL) 
+                               {
+                               ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+                               SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+                               goto err;
+                               }
+
                        if (s->session->sess_cert->peer_dh_tmp != NULL)
                                dh_srvr=s->session->sess_cert->peer_dh_tmp;
                        else
@@ -2001,7 +2203,7 @@ int ssl3_send_client_key_exchange(SSL *s)
 #endif
 
 #ifndef OPENSSL_NO_ECDH 
-               else if ((l & SSL_kECDH) || (l & SSL_kEECDH))
+               else if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
                        {
                        const EC_GROUP *srvr_group = NULL;
                        EC_KEY *tkey;
@@ -2013,7 +2215,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                         * computation as part of client certificate?
                         * If so, set ecdh_clnt_cert to 1.
                         */
-                       if ((l & SSL_kECDH) && (s->cert != NULL)) 
+                       if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->cert != NULL)) 
                                {
                                /* XXX: For now, we do not support client
                                 * authentication using ECDH certificates.
@@ -2185,8 +2387,86 @@ int ssl3_send_client_key_exchange(SSL *s)
                        EVP_PKEY_free(srvr_pub_pkey);
                        }
 #endif /* !OPENSSL_NO_ECDH */
+               else if (alg_k & SSL_kGOST) 
+                       {
+                       /* GOST key exchange message creation */
+                       EVP_PKEY_CTX *pkey_ctx;
+                       X509 *peer_cert; 
+                       size_t msglen;
+                       unsigned int md_len;
+                       int keytype;
+                       unsigned char premaster_secret[32],shared_ukm[32];
+                       EVP_MD_CTX *ukm_hash;
+                       EVP_PKEY *pub_key;
+
+                       /* Get server sertificate PKEY and create ctx from it */
+                       peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST01)].x509;
+                       if (!peer_cert) 
+                               peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST94)].x509;
+                       if (!peer_cert)         {
+                                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+                                       goto err;
+                               }       
+                               
+                       pkey_ctx=EVP_PKEY_CTX_new(pub_key=X509_get_pubkey(peer_cert),NULL);
+                       /* If we have send a certificate, and certificate key
+
+                        * parameters match those of server certificate, use
+                        * certificate key for key exchange
+                        */
+
+                        /* Otherwise, generate ephemeral key pair */
+                                       
+                       EVP_PKEY_encrypt_init(pkey_ctx);
+                         /* 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 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 */
+                       ukm_hash = EVP_MD_CTX_create();
+                       EVP_DigestInit(ukm_hash,EVP_get_digestbynid(NID_id_GostR3411_94));
+                       EVP_DigestUpdate(ukm_hash,s->s3->client_random,SSL3_RANDOM_SIZE);
+                       EVP_DigestUpdate(ukm_hash,s->s3->server_random,SSL3_RANDOM_SIZE);
+                       EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
+                       EVP_MD_CTX_destroy(ukm_hash);
+                       if (EVP_PKEY_CTX_ctrl(pkey_ctx,-1,EVP_PKEY_OP_ENCRYPT,EVP_PKEY_CTRL_SET_IV,
+                               8,shared_ukm)<0) {
+                                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                                               SSL_R_LIBRARY_BUG);
+                                       goto err;
+                               }       
+                       /* 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) {
+                       SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+                                       SSL_R_LIBRARY_BUG);
+                               goto err;
+                       }       
+                       *(p++)= msglen & 0xff;
+                       n=msglen+3;
+                       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);
+                       EVP_PKEY_free(pub_key);
+
+                       }
 #ifndef OPENSSL_NO_PSK
-               else if (l & SSL_kPSK)
+               else if (alg_k & SSL_kPSK)
                        {
                        char identity[PSK_MAX_IDENTITY_LEN];
                        unsigned char *t = NULL;
@@ -2259,7 +2539,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                        psk_err = 0;
                psk_err:
                        OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
-                       OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));  
+                       OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
                        if (psk_err != 0)
                                {
                                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
@@ -2303,6 +2583,7 @@ int ssl3_send_client_verify(SSL *s)
        unsigned char *p,*d;
        unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
        EVP_PKEY *pkey;
+       EVP_PKEY_CTX *pctx=NULL;
 #ifndef OPENSSL_NO_RSA
        unsigned u=0;
 #endif
@@ -2316,15 +2597,25 @@ int ssl3_send_client_verify(SSL *s)
                d=(unsigned char *)s->init_buf->data;
                p= &(d[4]);
                pkey=s->cert->key->privatekey;
-
-               s->method->ssl3_enc->cert_verify_mac(s,&(s->s3->finish_dgst2),
-                       &(data[MD5_DIGEST_LENGTH]));
-
+/* Create context from key and test if sha1 is allowed as digest */
+               pctx = EVP_PKEY_CTX_new(pkey,NULL);
+               EVP_PKEY_sign_init(pctx);
+               if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0)
+                       {
+                       s->method->ssl3_enc->cert_verify_mac(s,
+                                               NID_sha1,
+                                               &(data[MD5_DIGEST_LENGTH]));
+                       }
+               else
+                       {
+                       ERR_clear_error();
+                       }
 #ifndef OPENSSL_NO_RSA
                if (pkey->type == EVP_PKEY_RSA)
                        {
                        s->method->ssl3_enc->cert_verify_mac(s,
-                               &(s->s3->finish_dgst1),&(data[0]));
+                               NID_md5,
+                               &(data[0]));
                        if (RSA_sign(NID_md5_sha1, data,
                                         MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
                                        &(p[2]), &u, pkey->pkey.rsa) <= 0 )
@@ -2370,10 +2661,30 @@ int ssl3_send_client_verify(SSL *s)
                        }
                else
 #endif
-                       {
+               if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001) 
+               {
+               unsigned char signbuf[64];
+               int i;
+               size_t sigsize=64;
+               s->method->ssl3_enc->cert_verify_mac(s,
+                       NID_id_GostR3411_94,
+                       data);
+               if (!EVP_PKEY_sign(pctx,signbuf,&sigsize,data,32)) {
+                       SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+                       ERR_R_INTERNAL_ERROR);
+                       goto err;
+               }
+               for (i=63,j=0; i>=0; j++, i--) {
+                       p[2+j]=signbuf[i];
+               }       
+               s2n(j,p);
+               n=j+2;
+               }
+               else
+               {
                        SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
                        goto err;
-                       }
+               }
                *(d++)=SSL3_MT_CERTIFICATE_VERIFY;
                l2n3(n,d);
 
@@ -2381,8 +2692,10 @@ int ssl3_send_client_verify(SSL *s)
                s->init_num=(int)n+4;
                s->init_off=0;
                }
+       EVP_PKEY_CTX_free(pctx);
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
 err:
+       EVP_PKEY_CTX_free(pctx);
        return(-1);
        }
 
@@ -2468,7 +2781,7 @@ int ssl3_send_client_certificate(SSL *s)
 int ssl3_check_cert_and_algorithm(SSL *s)
        {
        int i,idx;
-       long algs;
+       long alg_k,alg_a;
        EVP_PKEY *pkey=NULL;
        SESS_CERT *sc;
 #ifndef OPENSSL_NO_RSA
@@ -2485,10 +2798,11 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                goto err;
                }
 
-       algs=s->s3->tmp.new_cipher->algorithms;
+       alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
+       alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
        /* we don't have a certificate */
-       if (algs & (SSL_aDH|SSL_aNULL|SSL_aKRB5|SSL_kPSK))
+       if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
                return(1);
 
 #ifndef OPENSSL_NO_RSA
@@ -2508,7 +2822,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                    s->s3->tmp.new_cipher) == 0) 
                        { /* check failed */
                        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
-                       goto f_err;                     
+                       goto f_err;
                        }
                else 
                        {
@@ -2522,20 +2836,20 @@ int ssl3_check_cert_and_algorithm(SSL *s)
 
        
        /* Check that we have a certificate if we require one */
-       if ((algs & SSL_aRSA) && !has_bits(i,EVP_PK_RSA|EVP_PKT_SIGN))
+       if ((alg_a & SSL_aRSA) && !has_bits(i,EVP_PK_RSA|EVP_PKT_SIGN))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_SIGNING_CERT);
                goto f_err;
                }
 #ifndef OPENSSL_NO_DSA
-       else if ((algs & SSL_aDSS) && !has_bits(i,EVP_PK_DSA|EVP_PKT_SIGN))
+       else if ((alg_a & SSL_aDSS) && !has_bits(i,EVP_PK_DSA|EVP_PKT_SIGN))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DSA_SIGNING_CERT);
                goto f_err;
                }
 #endif
 #ifndef OPENSSL_NO_RSA
-       if ((algs & SSL_kRSA) &&
+       if ((alg_k & SSL_kRSA) &&
                !(has_bits(i,EVP_PK_RSA|EVP_PKT_ENC) || (rsa != NULL)))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_ENCRYPTING_CERT);
@@ -2543,19 +2857,19 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                }
 #endif
 #ifndef OPENSSL_NO_DH
-       if ((algs & SSL_kEDH) &&
+       if ((alg_k & SSL_kEDH) &&
                !(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY);
                goto f_err;
                }
-       else if ((algs & SSL_kDHr) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
+       else if ((alg_k & SSL_kDHr) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_RSA_CERT);
                goto f_err;
                }
 #ifndef OPENSSL_NO_DSA
-       else if ((algs & SSL_kDHd) && !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
+       else if ((alg_k & SSL_kDHd) && !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_DSA_CERT);
                goto f_err;
@@ -2566,7 +2880,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
        if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i,EVP_PKT_EXP))
                {
 #ifndef OPENSSL_NO_RSA
-               if (algs & SSL_kRSA)
+               if (alg_k & SSL_kRSA)
                        {
                        if (rsa == NULL
                            || RSA_size(rsa)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
@@ -2578,7 +2892,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                else
 #endif
 #ifndef OPENSSL_NO_DH
-                       if (algs & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+                       if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
                            {
                            if (dh == NULL
                                || DH_size(dh)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher))
@@ -2600,3 +2914,37 @@ f_err:
 err:
        return(0);
        }
+
+/* Check to see if handshake is full or resumed. Usually this is just a
+ * case of checking to see if a cache hit has occurred. In the case of
+ * session tickets we have to check the next message to be sure.
+ */
+
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl3_check_finished(SSL *s)
+       {
+       int ok;
+       long n;
+       /* If we have no ticket or session ID is non-zero length (a match of
+        * a non-zero session length would never reach here) it cannot be a
+        * resumed session.
+        */
+       if (!s->session->tlsext_tick || s->session->session_id_length)
+               return 1;
+       /* this function is called when we really expect a Certificate
+        * message, so permit appropriate message length */
+       n=s->method->ssl_get_message(s,
+               SSL3_ST_CR_CERT_A,
+               SSL3_ST_CR_CERT_B,
+               -1,
+               s->max_cert_list,
+               &ok);
+       if (!ok) return((int)n);
+       s->s3->tmp.reuse_message = 1;
+       if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
+               || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
+               return 2;
+
+       return 1;
+       }
+#endif