oops!
[openssl.git] / ssl / s3_clnt.c
index 8f96120d2e963b5719b8b650dde16834fed9933b..a62ffd5eb3dd2c677330de3fb9fb60b8a2f9492d 100644 (file)
@@ -190,7 +190,7 @@ int ssl3_connect(SSL *s)
        long num1;
        void (*cb)(const SSL *ssl,int type,int val)=NULL;
        int ret= -1;
-       int new_state,state,skip=0;;
+       int new_state,state,skip=0;
 
        RAND_add(&Time,sizeof(Time),0);
        ERR_clear_error();
@@ -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;
@@ -719,7 +724,7 @@ err:
 int ssl3_get_server_hello(SSL *s)
        {
        STACK_OF(SSL_CIPHER) *sk;
-       SSL_CIPHER *c;
+       const SSL_CIPHER *c;
        unsigned char *p,*d;
        int i,al,ok;
        unsigned int j;
@@ -737,7 +742,7 @@ int ssl3_get_server_hello(SSL *s)
 
        if (!ok) return((int)n);
 
-       if ( SSL_version(s) == DTLS1_VERSION)
+       if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
                {
                if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
                        {
@@ -788,6 +793,23 @@ int ssl3_get_server_hello(SSL *s)
                goto f_err;
                }
 
+#ifndef OPENSSL_NO_TLSEXT
+       /* check if we want to resume the session based on external pre-shared secret */
+       if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+               {
+               SSL_CIPHER *pref_cipher=NULL;
+               s->session->master_key_length=sizeof(s->session->master_key);
+               if (s->tls_session_secret_cb(s, s->session->master_key,
+                                            &s->session->master_key_length,
+                                            NULL, &pref_cipher,
+                                            s->tls_session_secret_cb_arg))
+                       {
+                       s->session->cipher = pref_cipher ?
+                               pref_cipher : ssl_get_cipher_by_char(s, p+j);
+                       }
+               }
+#endif /* OPENSSL_NO_TLSEXT */
+
        if (j != 0 && j == s->session->session_id_length
            && memcmp(p,s->session->session_id,j) == 0)
            {
@@ -854,7 +876,8 @@ int ssl3_get_server_hello(SSL *s)
                        }
                }
        s->s3->tmp.new_cipher=c;
-       ssl3_digest_cached_records(s);
+       if (!ssl3_digest_cached_records(s))
+               goto f_err;
 
        /* lets get the compression algorithm */
        /* COMPRESSION */
@@ -1000,7 +1023,7 @@ int ssl3_get_server_certificate(SSL *s)
                }
 
        i=ssl_verify_cert_chain(s,sk);
-       if ((s->verify_mode != SSL_VERIFY_NONE) && (!i)
+       if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)
 #ifndef OPENSSL_NO_KRB5
            && !((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
                 (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
@@ -1536,7 +1559,7 @@ int ssl3_get_key_exchange(SSL *s)
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,param,param_len);
-                       if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey))
+                       if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
                                {
                                /* bad signature */
                                al=SSL_AD_DECRYPT_ERROR;
@@ -1554,7 +1577,7 @@ int ssl3_get_key_exchange(SSL *s)
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
                        EVP_VerifyUpdate(&md_ctx,param,param_len);
-                       if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey))
+                       if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
                                {
                                /* bad signature */
                                al=SSL_AD_DECRYPT_ERROR;
@@ -2016,7 +2039,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                        krb5_data       *enc_ticket;
                        krb5_data       authenticator, *authp = NULL;
                        EVP_CIPHER_CTX  ciph_ctx;
-                       EVP_CIPHER      *enc = NULL;
+                       const EVP_CIPHER *enc = NULL;
                        unsigned char   iv[EVP_MAX_IV_LENGTH];
                        unsigned char   tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
                        unsigned char   epms[SSL_MAX_MASTER_KEY_LENGTH 
@@ -2119,7 +2142,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                                sizeof tmp_buf);
                        EVP_EncryptFinal_ex(&ciph_ctx,&(epms[outl]),&padl);
                        outl += padl;
-                       if (outl > sizeof epms)
+                       if (outl > (int)sizeof epms)
                                {
                                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
                                goto err;
@@ -2398,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;
 
@@ -2424,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 */
@@ -2452,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,
@@ -2672,7 +2707,7 @@ int ssl3_send_client_verify(SSL *s)
                s->method->ssl3_enc->cert_verify_mac(s,
                        NID_id_GostR3411_94,
                        data);
-               if (!EVP_PKEY_sign(pctx,signbuf,&sigsize,data,32)) {
+               if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
                        SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
                        ERR_R_INTERNAL_ERROR);
                        goto err;
@@ -2927,11 +2962,8 @@ 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)
+       /* If we have no ticket it cannot be a resumed session. */
+       if (!s->session->tlsext_tick)
                return 1;
        /* this function is called when we really expect a Certificate
         * message, so permit appropriate message length */
@@ -2959,7 +2991,7 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
                {
                i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
                                                SSL_get_client_CA_list(s),
-                                               px509, ppkey, NULL, NULL);
+                                               px509, ppkey, NULL, NULL, NULL);
                if (i != 0)
                        return i;
                }