Update from stable branch.
[openssl.git] / ssl / s3_srvr.c
index cc01cb109fd535b9aac70afb56a9915f7cd7f882..dee1f73cde4354beb9480d7532ef380cf13dc765 100644 (file)
@@ -314,9 +314,18 @@ int ssl3_accept(SSL *s)
                case SSL3_ST_SW_SRVR_HELLO_B:
                        ret=ssl3_send_server_hello(s);
                        if (ret <= 0) goto end;
-
+#ifndef OPENSSL_NO_TLSEXT
                        if (s->hit)
-                               s->state=SSL3_ST_SW_CHANGE_A;
+                               {
+                               if (s->tlsext_ticket_expected)
+                                       s->state=SSL3_ST_SW_SESSION_TICKET_A;
+                               else
+                                       s->state=SSL3_ST_SW_CHANGE_A;
+                               }
+#else
+                       if (s->hit)
+                                       s->state=SSL3_ST_SW_CHANGE_A;
+#endif
                        else
                                s->state=SSL3_ST_SW_CERT_A;
                        s->init_num=0;
@@ -344,6 +353,7 @@ int ssl3_accept(SSL *s)
                                s->state=SSL3_ST_SW_KEY_EXCH_A;
                                }
 #else
+                               }
                        else
                                skip=1;
 
@@ -510,6 +520,8 @@ int ssl3_accept(SSL *s)
                                }
                        else
                                {
+                               int offset=0;
+                               int dgst_num;
                                s->state=SSL3_ST_SR_CERT_VRFY_A;
                                s->init_num=0;
 
@@ -518,13 +530,14 @@ int ssl3_accept(SSL *s)
                                 * FIXME - digest processing for CertificateVerify
                                 * should be generalized. But it is next step
                                 */
-                                                               
-                               s->method->ssl3_enc->cert_verify_mac(s,
-                                       NID_md5,
-                                   &(s->s3->tmp.cert_verify_md[0]));
-                               s->method->ssl3_enc->cert_verify_mac(s,
-                                       NID_sha1,
-                                   &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+                               if (s->s3->handshake_buffer)
+                                       ssl3_digest_cached_records(s);
+                               for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++)    
+                                       if (s->s3->handshake_dgst[dgst_num]) 
+                                               {
+                                               s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset]));
+                                               offset+=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
+                                               }               
                                }
                        break;
 
@@ -544,11 +557,14 @@ int ssl3_accept(SSL *s)
                        ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
                                SSL3_ST_SR_FINISHED_B);
                        if (ret <= 0) goto end;
-                       if (s->hit)
-                               s->state=SSL_ST_OK;
 #ifndef OPENSSL_NO_TLSEXT
-                       else if (s->tlsext_ticket_expected)
+                       if (s->tlsext_ticket_expected)
                                s->state=SSL3_ST_SW_SESSION_TICKET_A;
+                       else if (s->hit)
+                               s->state=SSL_ST_OK;
+#else
+                       if (s->hit)
+                               s->state=SSL_ST_OK;
 #endif
                        else
                                s->state=SSL3_ST_SW_CHANGE_A;
@@ -774,7 +790,8 @@ int ssl3_get_client_hello(SSL *s)
        s->client_version=(((int)p[0])<<8)|(int)p[1];
        p+=2;
 
-       if (s->client_version < s->version)
+       if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
+           (s->version != DTLS1_VERSION && s->client_version < s->version))
                {
                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
                if ((s->client_version>>8) == SSL3_VERSION_MAJOR)
@@ -825,7 +842,7 @@ int ssl3_get_client_hello(SSL *s)
 
        p+=j;
 
-       if (SSL_version(s) == DTLS1_VERSION)
+       if (s->version == DTLS1_VERSION)
                {
                /* cookie stuff */
                cookie_len = *(p++);
@@ -1140,8 +1157,16 @@ int ssl3_send_server_hello(SSL *s)
                 * session-id if we want it to be single use.
                 * Currently I will not implement the '0' length session-id
                 * 12-Jan-98 - I'll now support the '0' length stuff.
+                *
+                * We also have an additional case where stateless session
+                * resumption is successful: we always send back the old
+                * session id. In this case s->hit is non zero: this can
+                * only happen if stateless session resumption is succesful
+                * if session caching is disabled so existing functionality
+                * is unaffected.
                 */
-               if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER))
+               if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
+                       && !s->hit)
                        s->session->session_id_length=0;
 
                sl=s->session->session_id_length;
@@ -1179,7 +1204,6 @@ int ssl3_send_server_hello(SSL *s)
                        return -1;
                        }
 #endif
-
                /* do the header */
                l=(p-d);
                d=buf;
@@ -1821,7 +1845,7 @@ int ssl3_get_client_key_exchange(SSL *s)
                        rsa=pkey->pkey.rsa;
                        }
 
-               /* TLS */
+               /* TLS and [incidentally] DTLS{0xFEFF} */
                if (s->version > SSL3_VERSION)
                        {
                        n2s(p,i);
@@ -2396,6 +2420,35 @@ int ssl3_get_client_key_exchange(SSL *s)
                        }
                else
 #endif
+               if (alg_k & SSL_kGOST) 
+               {
+                       EVP_PKEY_CTX *pkey_ctx;
+                       unsigned char premaster_secret[32];
+                       size_t outlen;                  
+
+                       /* Get our certificate privatec key*/
+                       pkey_ctx = EVP_PKEY_CTX_new(s->cert->key->privatekey,NULL);     
+                       EVP_PKEY_decrypt_init(pkey_ctx);
+                       /* Decrypt session key */
+                       if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)) || p[1]!=0x81 ) 
+                               {
+                               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) 
+
+                               {
+                               SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+                               goto err;
+                               }
+                       /* 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);
+
+               }
+               else
                {
                al=SSL_AD_HANDSHAKE_FAILURE;
                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
@@ -2485,15 +2538,25 @@ int ssl3_get_cert_verify(SSL *s)
 
        /* we now have a signature that we need to verify */
        p=(unsigned char *)s->init_msg;
-       n2s(p,i);
-       n-=2;
-       if (i > n)
+       /* Check for broken implementations of GOST ciphersuites */
+       /* If key is GOST and n is exactly 64, it is bare
+        * signature without length field */
+       if (n==64 && (pkey->type==NID_id_GostR3410_94 ||
+               pkey->type == NID_id_GostR3410_2001) )
                {
-               SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH);
-               al=SSL_AD_DECODE_ERROR;
-               goto f_err;
-               }
-
+               i=64;
+               } 
+       else 
+               {       
+               n2s(p,i);
+               n-=2;
+               if (i > n)
+                       {
+                       SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_LENGTH_MISMATCH);
+                       al=SSL_AD_DECODE_ERROR;
+                       goto f_err;
+                       }
+       }
        j=EVP_PKEY_size(pkey);
        if ((i > j) || (n > j) || (n <= 0))
                {
@@ -2556,6 +2619,28 @@ int ssl3_get_cert_verify(SSL *s)
                }
        else
 #endif
+       if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001)
+               {   unsigned char signature[64];
+                       int idx;
+                       EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey,NULL);
+                       EVP_PKEY_verify_init(pctx);
+                       if (i!=64) {
+                               fprintf(stderr,"GOST signature length is %d",i);
+                       }       
+                       for (idx=0;idx<64;idx++) {
+                               signature[63-idx]=p[idx];
+                       }       
+                       j=EVP_PKEY_verify(pctx,signature,64,s->s3->tmp.cert_verify_md,32);
+                       EVP_PKEY_CTX_free(pctx);
+                       if (j<=0) 
+                               {
+                               al=SSL_AD_DECRYPT_ERROR;
+                               SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,
+                                       SSL_R_BAD_ECDSA_SIGNATURE);
+                               goto f_err;
+                               }       
+               }
+       else    
                {
                SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR);
                al=SSL_AD_UNSUPPORTED_CERTIFICATE;