No fprintf in the txt_db component
[openssl.git] / ssl / s3_clnt.c
index 1bc5bcd9b1ff2c5040bedf3016e7685a1fd91340..935a621e6db22aa305b31b73cac4687e3ab791c4 100644 (file)
 # include <openssl/engine.h>
 #endif
 
+static int ssl_set_version(SSL *s);
 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 int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
+                                    unsigned char *p,
+                                    int (*put_cb) (const SSL_CIPHER *,
+                                                 unsigned char *));
 
-#ifndef OPENSSL_NO_SSL3_METHOD
-static const SSL_METHOD *ssl3_get_client_method(int ver)
-{
-    if (ver == SSL3_VERSION)
-        return (SSLv3_client_method());
-    else
-        return (NULL);
-}
 
-IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
-                         ssl_undefined_function,
-                         ssl3_connect, ssl3_get_client_method)
-#endif
 int ssl3_connect(SSL *s)
 {
     BUF_MEM *buf = NULL;
@@ -242,7 +233,8 @@ int ssl3_connect(SSL *s)
                 goto end;
             }
 
-            if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+            if (s->version != TLS_ANY_VERSION &&
+                    !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
                 SSLerr(SSL_F_SSL3_CONNECT, SSL_R_VERSION_TOO_LOW);
                 return -1;
             }
@@ -315,12 +307,10 @@ int ssl3_connect(SSL *s)
 
             if (s->hit) {
                 s->state = SSL3_ST_CR_FINISHED_A;
-#ifndef OPENSSL_NO_TLSEXT
                 if (s->tlsext_ticket_expected) {
                     /* receive renewed session ticket */
                     s->state = SSL3_ST_CR_SESSION_TICKET_A;
                 }
-#endif
             } else {
                 s->state = SSL3_ST_CR_CERT_A;
             }
@@ -328,7 +318,6 @@ int ssl3_connect(SSL *s)
             break;
         case SSL3_ST_CR_CERT_A:
         case SSL3_ST_CR_CERT_B:
-#ifndef OPENSSL_NO_TLSEXT
             /* Noop (ret = 0) for everything but EAP-FAST. */
             ret = ssl3_check_finished(s);
             if (ret < 0)
@@ -339,17 +328,17 @@ int ssl3_connect(SSL *s)
                 s->init_num = 0;
                 break;
             }
-#endif
+
             /* Check if it is anon DH/ECDH, SRP auth */
             /* or PSK */
             if (!
                 (s->s3->tmp.
                  new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
-&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+                    && !(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
@@ -358,12 +347,7 @@ int ssl3_connect(SSL *s)
                 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;
 
@@ -476,7 +460,7 @@ int ssl3_connect(SSL *s)
             if (ret <= 0)
                 goto end;
 
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+#if defined(OPENSSL_NO_NEXTPROTONEG)
             s->state = SSL3_ST_CW_FINISHED_A;
 #else
             if (s->s3->next_proto_neg_seen)
@@ -511,7 +495,7 @@ int ssl3_connect(SSL *s)
 
             break;
 
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
         case SSL3_ST_CW_NEXT_PROTO_A:
         case SSL3_ST_CW_NEXT_PROTO_B:
             ret = ssl3_send_next_proto(s);
@@ -544,21 +528,17 @@ int ssl3_connect(SSL *s)
                     s->s3->delay_buf_pop_ret = 0;
                 }
             } 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);
@@ -576,7 +556,6 @@ int ssl3_connect(SSL *s)
             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:
@@ -669,6 +648,105 @@ int ssl3_connect(SSL *s)
     return (ret);
 }
 
+/*
+ * Work out what version we should be using for the initial ClientHello if
+ * the version is currently set to (D)TLS_ANY_VERSION.
+ * Returns 1 on success
+ * Returns 0 on error
+ */
+static int ssl_set_version(SSL *s)
+{
+    unsigned long mask, options = s->options;
+
+    if (s->method->version == TLS_ANY_VERSION) {
+        /*
+         * SSL_OP_NO_X disables all protocols above X *if* there are
+         * some protocols below X enabled. This is required in order
+         * to maintain "version capability" vector contiguous. So
+         * that if application wants to disable TLS1.0 in favour of
+         * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
+         * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
+         */
+        mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
+#if !defined(OPENSSL_NO_SSL3)
+            | SSL_OP_NO_SSLv3
+#endif
+            ;
+#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+        if (options & SSL_OP_NO_TLSv1_2) {
+            if ((options & mask) != mask) {
+                s->version = TLS1_1_VERSION;
+            } else {
+                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
+                return 0;
+            }
+        } else {
+            s->version = TLS1_2_VERSION;
+        }
+#else
+        if ((options & mask) == mask) {
+            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
+            return 0;
+        }
+        s->version = TLS1_1_VERSION;
+#endif
+
+        mask &= ~SSL_OP_NO_TLSv1_1;
+        if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
+            s->version = TLS1_VERSION;
+        mask &= ~SSL_OP_NO_TLSv1;
+#if !defined(OPENSSL_NO_SSL3)
+        if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
+            s->version = SSL3_VERSION;
+#endif
+
+        if (s->version != TLS1_2_VERSION && tls1_suiteb(s)) {
+            SSLerr(SSL_F_SSL_SET_VERSION,
+                   SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+            return 0;
+        }
+
+        if (s->version == SSL3_VERSION && FIPS_mode()) {
+            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+            return 0;
+        }
+
+    } else if (s->method->version == DTLS_ANY_VERSION) {
+        /* Determine which DTLS version to use */
+        /* If DTLS 1.2 disabled correct the version number */
+        if (options & SSL_OP_NO_DTLSv1_2) {
+            if (tls1_suiteb(s)) {
+                SSLerr(SSL_F_SSL_SET_VERSION,
+                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+                return 0;
+            }
+            /*
+             * Disabling all versions is silly: return an error.
+             */
+            if (options & SSL_OP_NO_DTLSv1) {
+                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_WRONG_SSL_VERSION);
+                return 0;
+            }
+            /*
+             * Update method so we don't use any DTLS 1.2 features.
+             */
+            s->method = DTLSv1_client_method();
+            s->version = DTLS1_VERSION;
+        } else {
+            /*
+             * We only support one version: update method
+             */
+            if (options & SSL_OP_NO_DTLSv1)
+                s->method = DTLSv1_2_client_method();
+            s->version = DTLS1_2_VERSION;
+        }
+    }
+
+    s->client_version = s->version;
+
+    return 1;
+}
+
 int ssl3_client_hello(SSL *s)
 {
     unsigned char *buf;
@@ -680,86 +758,21 @@ int ssl3_client_hello(SSL *s)
     int j;
     SSL_COMP *comp;
 #endif
-    unsigned long mask, options = s->options;
 
     buf = (unsigned char *)s->init_buf->data;
     if (s->state == SSL3_ST_CW_CLNT_HELLO_A) {
         SSL_SESSION *sess = s->session;
 
-        if (s->method->version == TLS_ANY_VERSION ) {
-            /*
-             * SSL_OP_NO_X disables all protocols above X *if* there are
-             * some protocols below X enabled. This is required in order
-             * to maintain "version capability" vector contiguous. So
-             * that if application wants to disable TLS1.0 in favour of
-             * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
-             * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
-             */
-            mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
-#if !defined(OPENSSL_NO_SSL3)
-                | SSL_OP_NO_SSLv3
-#endif
-                ;
-#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
-            s->version = TLS1_2_VERSION;
-
-            if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask)
-                s->version = TLS1_1_VERSION;
-#else
-            s->version = TLS1_1_VERSION;
-#endif
-            mask &= ~SSL_OP_NO_TLSv1_1;
-            if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
-                s->version = TLS1_VERSION;
-            mask &= ~SSL_OP_NO_TLSv1;
-#if !defined(OPENSSL_NO_SSL3)
-            if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
-                s->version = SSL3_VERSION;
-            mask &= ~SSL_OP_NO_SSLv3;
-#endif
-            s->client_version = s->version;
-        } else if (s->method->version == DTLS_ANY_VERSION) {
-            /* Determine which DTLS version to use */
-            /* If DTLS 1.2 disabled correct the version number */
-            if (options & SSL_OP_NO_DTLSv1_2) {
-                if (tls1_suiteb(s)) {
-                    SSLerr(SSL_F_SSL3_CLIENT_HELLO,
-                           SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-                    goto err;
-                }
-                /*
-                 * Disabling all versions is silly: return an error.
-                 */
-                if (options & SSL_OP_NO_DTLSv1) {
-                    SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_WRONG_SSL_VERSION);
-                    goto err;
-                }
-                /*
-                 * Update method so we don't use any DTLS 1.2 features.
-                 */
-                s->method = DTLSv1_client_method();
-                s->version = DTLS1_VERSION;
-            } else {
-                /*
-                 * We only support one version: update method
-                 */
-                if (options & SSL_OP_NO_DTLSv1)
-                    s->method = DTLSv1_2_client_method();
-                s->version = DTLS1_2_VERSION;
-            }
-            s->client_version = s->version;
-        }
+        /* Work out what SSL/TLS/DTLS version to use */
+        if (ssl_set_version(s) == 0)
+            goto err;
 
         if ((sess == NULL) || (sess->ssl_version != s->version) ||
-#ifdef OPENSSL_NO_TLSEXT
-            !sess->session_id_length ||
-#else
             /*
              * In the case of EAP-FAST, we can have a pre-shared
              * "ticket" without a session ID.
              */
             (!sess->session_id_length && !sess->tlsext_tick) ||
-#endif
             (sess->not_resumable)) {
             if (!ssl_get_new_session(s, 0))
                 goto err;
@@ -890,7 +903,6 @@ 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);
@@ -903,7 +915,6 @@ int ssl3_client_hello(SSL *s)
             SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
             goto err;
         }
-#endif
 
         l = p - d;
         if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
@@ -925,7 +936,6 @@ int ssl3_get_server_hello(SSL *s)
 {
     STACK_OF(SSL_CIPHER) *sk;
     const SSL_CIPHER *c;
-    CERT *ct = s->cert;
     unsigned char *p, *d;
     int i, al = SSL_AD_INTERNAL_ERROR, ok;
     unsigned int j;
@@ -937,8 +947,7 @@ int ssl3_get_server_hello(SSL *s)
      * Hello verify request and/or server hello version may not match so set
      * first packet if we're negotiating version.
      */
-    if (SSL_IS_DTLS(s))
-        s->first_packet = 1;
+    s->first_packet = 1;
 
     n = s->method->ssl_get_message(s,
                                    SSL3_ST_CR_SRVR_HELLO_A,
@@ -947,8 +956,8 @@ int ssl3_get_server_hello(SSL *s)
     if (!ok)
         return ((int)n);
 
+    s->first_packet = 0;
     if (SSL_IS_DTLS(s)) {
-        s->first_packet = 0;
         if (s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) {
             if (s->d1->send_cookie == 0) {
                 s->s3->tmp.reuse_message = 1;
@@ -981,7 +990,8 @@ int ssl3_get_server_hello(SSL *s)
             if (FIPS_mode()) {
                 SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
                        SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
-                goto err;
+                al = SSL_AD_PROTOCOL_VERSION;
+                goto f_err;
             }
             s->method = SSLv3_client_method();
         } else
@@ -996,13 +1006,15 @@ int ssl3_get_server_hello(SSL *s)
             s->method = TLSv1_2_client_method();
         } else {
             SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
-            goto err;
+            al = SSL_AD_PROTOCOL_VERSION;
+            goto f_err;
         }
         s->session->ssl_version = s->version = s->method->version;
 
         if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
             SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
-            goto err;
+            al = SSL_AD_PROTOCOL_VERSION;
+            goto f_err;
         }
     } else if (s->method->version == DTLS_ANY_VERSION) {
         /* Work out correct protocol version to use */
@@ -1024,7 +1036,7 @@ int ssl3_get_server_hello(SSL *s)
             al = SSL_AD_PROTOCOL_VERSION;
             goto f_err;
         }
-        s->version = s->method->version;
+        s->session->ssl_version = s->version = s->method->version;
     } else if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) {
         SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
         s->version = (s->version & 0xff00) | p[1];
@@ -1048,7 +1060,7 @@ int ssl3_get_server_hello(SSL *s)
         SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG);
         goto f_err;
     }
-#ifndef OPENSSL_NO_TLSEXT
+
     /*
      * Check if we can resume the session based on external pre-shared secret.
      * EAP-FAST (RFC 4851) supports two types of session resumption.
@@ -1077,7 +1089,6 @@ int ssl3_get_server_hello(SSL *s)
             goto f_err;
         }
     }
-#endif                          /* OPENSSL_NO_TLSEXT */
 
     if (j != 0 && j == s->session->session_id_length
         && memcmp(p, s->session->session_id, j) == 0) {
@@ -1116,9 +1127,9 @@ int ssl3_get_server_hello(SSL *s)
     }
     /* Set version disabled mask now we know version */
     if (!SSL_USE_TLS1_2_CIPHERS(s))
-        ct->mask_ssl = SSL_TLSV1_2;
+        s->s3->tmp.mask_ssl = SSL_TLSV1_2;
     else
-        ct->mask_ssl = 0;
+        s->s3->tmp.mask_ssl = 0;
     /*
      * If it is a disabled cipher we didn't send it in client hello, so
      * return an error.
@@ -1203,13 +1214,11 @@ int ssl3_get_server_hello(SSL *s)
     }
 #endif
 
-#ifndef OPENSSL_NO_TLSEXT
     /* TLS extensions */
     if (!ssl_parse_serverhello_tlsext(s, &p, d, n)) {
         SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
         goto err;
     }
-#endif
 
     if (p != (d + n)) {
         /* wrong packet length */
@@ -1695,6 +1704,13 @@ int ssl3_get_key_exchange(SSL *s)
             SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto err;
         }
+
+        if (EVP_PKEY_bits(pkey) <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+            al = SSL_AD_UNEXPECTED_MESSAGE;
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
+            goto f_err;
+        }
+
         s->session->sess_cert->peer_rsa_tmp = rsa;
         rsa = NULL;
     }
@@ -2128,8 +2144,8 @@ int ssl3_get_certificate_request(SSL *s)
         }
         /* Clear certificate digests and validity flags */
         for (i = 0; i < SSL_PKEY_NUM; i++) {
-            s->cert->pkeys[i].digest = NULL;
-            s->cert->pkeys[i].valid_flags = 0;
+            s->s3->tmp.md[i] = NULL;
+            s->s3->tmp.valid_flags[i] = 0;
         }
         if ((llen & 1) || !tls1_save_sigalgs(s, p, llen)) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
@@ -2206,7 +2222,6 @@ 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;
@@ -2230,6 +2245,38 @@ int ssl3_get_new_session_ticket(SSL *s)
     }
 
     p = d = (unsigned char *)s->init_msg;
+
+    if (s->session->session_id_length > 0) {
+        int i = s->session_ctx->session_cache_mode;
+        SSL_SESSION *new_sess;
+        /*
+         * We reused an existing session, so we need to replace it with a new
+         * one
+         */
+        if (i & SSL_SESS_CACHE_CLIENT) {
+            /*
+             * Remove the old session from the cache
+             */
+            if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE) {
+                if (s->session_ctx->remove_session_cb != NULL)
+                    s->session_ctx->remove_session_cb(s->session_ctx,
+                                                      s->session);
+            } else {
+                /* We carry on if this fails */
+                SSL_CTX_remove_session(s->session_ctx, s->session);
+            }
+        }
+
+        if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+
+        SSL_SESSION_free(s->session);
+        s->session = new_sess;
+    }
+
     n2l(p, s->session->tlsext_tick_lifetime_hint);
     n2s(p, ticklen);
     /* ticket_lifetime_hint + ticket_length + ticket */
@@ -2329,7 +2376,6 @@ int ssl3_get_cert_status(SSL *s)
     s->state = SSL_ST_ERR;
     return (-1);
 }
-#endif
 
 int ssl3_get_server_done(SSL *s)
 {
@@ -2533,8 +2579,6 @@ int ssl3_send_client_key_exchange(SSL *s)
             }
 
             DH_free(dh_clnt);
-
-            /* perhaps clean things up a bit EAY EAY EAY EAY */
         }
 #endif
 
@@ -2968,13 +3012,13 @@ int ssl3_send_client_key_exchange(SSL *s)
 #endif
         /* If we haven't written everything save PMS */
     if (n <= 0) {
-        s->cert->pms = pms;
-        s->cert->pmslen = pmslen;
+        s->s3->tmp.pms = pms;
+        s->s3->tmp.pmslen = pmslen;
     } else {
         /* If we don't have a PMS restore */
         if (pms == NULL) {
-            pms = s->cert->pms;
-            pmslen = s->cert->pmslen;
+            pms = s->s3->tmp.pms;
+            pmslen = s->s3->tmp.pmslen;
         }
         if (pms == NULL) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -2987,7 +3031,7 @@ int ssl3_send_client_key_exchange(SSL *s)
                                                         session->master_key,
                                                         pms, pmslen);
         OPENSSL_clear_free(pms, pmslen);
-        s->cert->pms = NULL;
+        s->s3->tmp.pms = NULL;
         if (s->session->master_key_length < 0) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
             SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
@@ -3000,7 +3044,7 @@ int ssl3_send_client_key_exchange(SSL *s)
     SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
  err:
     OPENSSL_clear_free(pms, pmslen);
-    s->cert->pms = NULL;
+    s->s3->tmp.pms = NULL;
 #ifndef OPENSSL_NO_EC
     BN_CTX_free(bn_ctx);
     OPENSSL_free(encodedPoint);
@@ -3046,7 +3090,7 @@ int ssl3_send_client_verify(SSL *s)
         if (SSL_USE_SIGALGS(s)) {
             long hdatalen = 0;
             void *hdata;
-            const EVP_MD *md = s->cert->key->digest;
+            const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
             hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
             if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
                 SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
@@ -3162,7 +3206,7 @@ static int ssl3_check_client_certificate(SSL *s)
     if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
         return 0;
     /* If no suitable signature algorithm can't use certificate */
-    if (SSL_USE_SIGALGS(s) && !s->cert->key->digest)
+    if (SSL_USE_SIGALGS(s) && !s->s3->tmp.md[s->cert->key - s->cert->pkeys])
         return 0;
     /*
      * If strict mode check suitability of chain before using it. This also
@@ -3290,6 +3334,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
     int i, idx;
     long alg_k, alg_a;
     EVP_PKEY *pkey = NULL;
+    int pkey_bits;
     SESS_CERT *sc;
 #ifndef OPENSSL_NO_RSA
     RSA *rsa;
@@ -3297,6 +3342,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
 #ifndef OPENSSL_NO_DH
     DH *dh;
 #endif
+    int al = SSL_AD_HANDSHAKE_FAILURE;
 
     alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
     alg_a = s->s3->tmp.new_cipher->algorithm_auth;
@@ -3339,6 +3385,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
     }
 #endif
     pkey = X509_get_pubkey(sc->peer_pkeys[idx].x509);
+    pkey_bits = EVP_PKEY_bits(pkey);
     i = X509_certificate_type(sc->peer_pkeys[idx].x509, pkey);
     EVP_PKEY_free(pkey);
 
@@ -3356,17 +3403,33 @@ int ssl3_check_cert_and_algorithm(SSL *s)
     }
 #endif
 #ifndef OPENSSL_NO_RSA
-    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);
-        goto f_err;
+    if (alg_k & SSL_kRSA) {
+        if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+            !has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
+            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                   SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+            goto f_err;
+        } else if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
+            if (pkey_bits <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+                if (!has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
+                    SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                           SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+                    goto f_err;
+                }
+                if (rsa != NULL) {
+                    /* server key exchange is not allowed. */
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
+                    goto f_err;
+                }
+            }
+        }
     }
 #endif
 #ifndef OPENSSL_NO_DH
-    if ((alg_k & SSL_kDHE) &&
-        !(has_bits(i, EVP_PK_DH | EVP_PKT_EXCH) || (dh != NULL))) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_DH_KEY);
+    if ((alg_k & SSL_kDHE) && (dh == NULL)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
         goto f_err;
     } else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
                !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
@@ -3384,12 +3447,18 @@ int ssl3_check_cert_and_algorithm(SSL *s)
 # endif
 #endif
 
-    if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i, EVP_PKT_EXP)) {
+    if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+        pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
 #ifndef OPENSSL_NO_RSA
         if (alg_k & SSL_kRSA) {
-            if (rsa == NULL
-                || RSA_size(rsa) * 8 >
+            if (rsa == NULL) {
+                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                       SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
+                goto f_err;
+            } else if (RSA_bits(rsa) >
                 SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+                /* We have a temporary RSA key but it's too large. */
+                al = SSL_AD_EXPORT_RESTRICTION;
                 SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
                        SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
                 goto f_err;
@@ -3397,14 +3466,21 @@ int ssl3_check_cert_and_algorithm(SSL *s)
         } else
 #endif
 #ifndef OPENSSL_NO_DH
-        if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) {
-            if (dh == NULL
-                || DH_size(dh) * 8 >
+        if (alg_k & SSL_kDHE) {
+            if (DH_bits(dh) >
                 SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+                /* We have a temporary DH key but it's too large. */
+                al = SSL_AD_EXPORT_RESTRICTION;
                 SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
                        SSL_R_MISSING_EXPORT_TMP_DH_KEY);
                 goto f_err;
             }
+        } else if (alg_k & (SSL_kDHr | SSL_kDHd)) {
+            /* The cert should have had an export DH key. */
+            al = SSL_AD_EXPORT_RESTRICTION;
+            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                   SSL_R_MISSING_EXPORT_TMP_DH_KEY);
+                goto f_err;
         } else
 #endif
         {
@@ -3415,12 +3491,11 @@ int ssl3_check_cert_and_algorithm(SSL *s)
     }
     return (1);
  f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
  err:
     return (0);
 }
 
-#ifndef OPENSSL_NO_TLSEXT
 /*
  * Normally, we can tell if the server is resuming the session from
  * the session ID. EAP-FAST (RFC 4851), however, relies on the next server
@@ -3470,7 +3545,7 @@ static int ssl3_check_finished(SSL *s)
     return 0;
 }
 
-# ifndef OPENSSL_NO_NEXTPROTONEG
+#ifndef OPENSSL_NO_NEXTPROTONEG
 int ssl3_send_next_proto(SSL *s)
 {
     unsigned int len, padding_len;
@@ -3493,7 +3568,6 @@ int ssl3_send_next_proto(SSL *s)
 
     return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
 }
-# endif
 #endif
 
 int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
@@ -3512,3 +3586,65 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
         i = s->ctx->client_cert_cb(s, px509, ppkey);
     return i;
 }
+
+int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
+                             unsigned char *p,
+                             int (*put_cb) (const SSL_CIPHER *,
+                                            unsigned char *))
+{
+    int i, j = 0;
+    SSL_CIPHER *c;
+    unsigned char *q;
+    int empty_reneg_info_scsv = !s->renegotiate;
+    /* Set disabled masks for this session */
+    ssl_set_client_disabled(s);
+
+    if (sk == NULL)
+        return (0);
+    q = p;
+    if (put_cb == NULL)
+        put_cb = s->method->put_cipher_by_char;
+
+    for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
+        c = sk_SSL_CIPHER_value(sk, i);
+        /* Skip disabled ciphers */
+        if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED))
+            continue;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+        if (c->id == SSL3_CK_SCSV) {
+            if (!empty_reneg_info_scsv)
+                continue;
+            else
+                empty_reneg_info_scsv = 0;
+        }
+#endif
+        j = put_cb(c, p);
+        p += j;
+    }
+    /*
+     * If p == q, no ciphers; caller indicates an error. Otherwise, add
+     * applicable SCSVs.
+     */
+    if (p != q) {
+        if (empty_reneg_info_scsv) {
+            static SSL_CIPHER scsv = {
+                0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            j = put_cb(&scsv, p);
+            p += j;
+#ifdef OPENSSL_RI_DEBUG
+            fprintf(stderr,
+                    "TLS_EMPTY_RENEGOTIATION_INFO_SCSV sent by client\n");
+#endif
+        }
+        if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
+            static SSL_CIPHER scsv = {
+                0, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            j = put_cb(&scsv, p);
+            p += j;
+        }
+    }
+
+    return (p - q);
+}