make EVP_PKEY opaque
[openssl.git] / ssl / statem / statem_clnt.c
index c0eeeed10238eaf7841e85eada60d57be9ed42e5..047bcf5d5b3d76a8039f225a5ab1e8d0a8e1d24c 100644 (file)
 
 static ossl_inline int cert_req_allowed(SSL *s);
 static int key_exchange_expected(SSL *s);
-static int ssl_set_version(SSL *s);
 static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
 static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
                                     unsigned char *p);
@@ -800,110 +799,12 @@ WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst)
     return WORK_ERROR;
 }
 
-/*
- * 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 tls_construct_client_hello(SSL *s)
 {
     unsigned char *buf;
     unsigned char *p, *d;
     int i;
+    int protverr;
     unsigned long l;
     int al = 0;
 #ifndef OPENSSL_NO_COMP
@@ -915,8 +816,11 @@ int tls_construct_client_hello(SSL *s)
     buf = (unsigned char *)s->init_buf->data;
 
     /* Work out what SSL/TLS/DTLS version to use */
-    if (ssl_set_version(s) == 0)
+    protverr = ssl_set_client_hello_version(s);
+    if (protverr != 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, protverr);
         goto err;
+    }
 
     if ((sess == NULL) || (sess->ssl_version != s->version) ||
         /*
@@ -1123,97 +1027,23 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     unsigned char *cipherchars;
     int i, al = SSL_AD_INTERNAL_ERROR;
     unsigned int compression;
+    unsigned int sversion;
+    int protverr;
 #ifndef OPENSSL_NO_COMP
     SSL_COMP *comp;
 #endif
 
-    if (s->method->version == TLS_ANY_VERSION) {
-        unsigned int sversion;
-
-        if (!PACKET_get_net_2(pkt, &sversion)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-#if TLS_MAX_VERSION != TLS1_2_VERSION
-#error Code needs updating for new TLS version
-#endif
-#ifndef OPENSSL_NO_SSL3
-        if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3)) {
-            if (FIPS_mode()) {
-                SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-                       SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            }
-            s->method = SSLv3_client_method();
-        } else
-#endif
-        if ((sversion == TLS1_VERSION) && !(s->options & SSL_OP_NO_TLSv1)) {
-            s->method = TLSv1_client_method();
-        } else if ((sversion == TLS1_1_VERSION) &&
-                   !(s->options & SSL_OP_NO_TLSv1_1)) {
-            s->method = TLSv1_1_client_method();
-        } else if ((sversion == TLS1_2_VERSION) &&
-                   !(s->options & SSL_OP_NO_TLSv1_2)) {
-            s->method = TLSv1_2_client_method();
-        } else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
-            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_TLS_PROCESS_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-    } else if (s->method->version == DTLS_ANY_VERSION) {
-        /* Work out correct protocol version to use */
-        unsigned int hversion;
-        int options;
-
-        if (!PACKET_get_net_2(pkt, &hversion)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        options = s->options;
-        if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2))
-            s->method = DTLSv1_2_client_method();
-        else if (tls1_suiteb(s)) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-                   SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-            s->version = hversion;
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1))
-            s->method = DTLSv1_client_method();
-        else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
-            s->version = hversion;
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-        s->session->ssl_version = s->version = s->method->version;
-    } else {
-        unsigned char *vers;
+    if (!PACKET_get_net_2(pkt, &sversion)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
 
-        if (!PACKET_get_bytes(pkt, &vers, 2)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if ((vers[0] != (s->version >> 8))
-                || (vers[1] != (s->version & 0xff))) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
-            s->version = (s->version & 0xff00) | vers[1];
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
+    protverr = ssl_choose_client_version(s, sversion);
+    if (protverr != 0) {
+        al = SSL_AD_PROTOCOL_VERSION;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, protverr);
+        goto f_err;
     }
 
     /* load the server hello data */
@@ -1260,7 +1090,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
      */
     if (s->version >= TLS1_VERSION && s->tls_session_secret_cb &&
         s->session->tlsext_tick) {
-        SSL_CIPHER *pref_cipher = NULL;
+        const 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,
@@ -1853,7 +1683,7 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 #ifdef SSL_DEBUG
             fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
 #endif
-        } else if (pkey->type == EVP_PKEY_RSA) {
+        } else if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) {
             md = EVP_md5_sha1();
         } else {
             md = EVP_sha1();
@@ -2361,8 +2191,7 @@ psk_err:
         }
 
         pkey = X509_get0_pubkey(s->session->peer);
-        if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA)
-            || (pkey->pkey.rsa == NULL)) {
+        if (EVP_PKEY_get0_RSA(pkey) == NULL) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                    ERR_R_INTERNAL_ERROR);
             goto err;
@@ -2378,8 +2207,6 @@ psk_err:
         if (s->version > SSL3_VERSION)
             p += 2;
         pctx = EVP_PKEY_CTX_new(pkey, NULL);
-        EVP_PKEY_free(pkey);
-        pkey = NULL;
         if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0
             || EVP_PKEY_encrypt(pctx, NULL, &enclen, pms, pmslen) <= 0) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
@@ -2445,9 +2272,7 @@ psk_err:
         } else {
             /* Get the Server Public Key from Cert */
             skey = X509_get0_pubkey(s->session->peer);
-            if ((skey == NULL)
-                || (skey->type != EVP_PKEY_EC)
-                || (skey->pkey.ec == NULL)) {
+            if ((skey == NULL) || EVP_PKEY_get0_EC_KEY(skey) == NULL) {
                 SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                        ERR_R_INTERNAL_ERROR);
                 goto err;
@@ -2781,10 +2606,12 @@ int tls_construct_client_verify(SSL *s)
         goto err;
     }
 #ifndef OPENSSL_NO_GOST
-    if (pkey->type == NID_id_GostR3410_2001
-            || pkey->type == NID_id_GostR3410_2012_256
-            || pkey->type == NID_id_GostR3410_2012_512) {
-        BUF_reverse(p + 2, NULL, u);
+    {
+        int pktype = EVP_PKEY_id(pkey);
+        if (pktype == NID_id_GostR3410_2001
+            || pktype == NID_id_GostR3410_2012_256
+            || pktype == NID_id_GostR3410_2012_512)
+            BUF_reverse(p + 2, NULL, u);
     }
 #endif
 
@@ -3037,7 +2864,7 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
                              unsigned char *p)
 {
     int i, j = 0;
-    SSL_CIPHER *c;
+    const SSL_CIPHER *c;
     unsigned char *q;
     int empty_reneg_info_scsv = !s->renegotiate;
     /* Set disabled masks for this session */