Let ssl_get_cipher_by_char yield not-valid ciphers
[openssl.git] / ssl / statem / statem_clnt.c
index 6bd7481c56f8d6cbfc93a380da7780868cb8121d..bc35a3ea25bb96da176b70c81b4aad3b6c549586 100644 (file)
@@ -60,6 +60,7 @@
 #include <openssl/bn.h>
 #include <openssl/engine.h>
 
+static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt);
 static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);
 
 static ossl_inline int cert_req_allowed(SSL *s);
@@ -137,6 +138,17 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
     default:
         break;
 
+    case TLS_ST_CW_CLNT_HELLO:
+        /*
+         * This must a ClientHello following a HelloRetryRequest, so the only
+         * thing we can get now is a ServerHello.
+         */
+        if (mt == SSL3_MT_SERVER_HELLO) {
+            st->hand_state = TLS_ST_CR_SRVR_HELLO;
+            return 1;
+        }
+        break;
+
     case TLS_ST_CR_SRVR_HELLO:
         if (mt == SSL3_MT_ENCRYPTED_EXTENSIONS) {
             st->hand_state = TLS_ST_CR_ENCRYPTED_EXTENSIONS;
@@ -188,6 +200,10 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
             st->hand_state = TLS_ST_CR_SESSION_TICKET;
             return 1;
         }
+        if (mt == SSL3_MT_KEY_UPDATE) {
+            st->hand_state = TLS_ST_CR_KEY_UPDATE;
+            return 1;
+        }
         break;
     }
 
@@ -210,8 +226,8 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
     int ske_expected;
 
     /*
-     * Note that after a ClientHello we don't know what version we are going
-     * to negotiate yet, so we don't take this branch until later
+     * Note that after writing the first ClientHello we don't know what version
+     * we are going to negotiate yet, so we don't take this branch until later.
      */
     if (SSL_IS_TLS13(s)) {
         if (!ossl_statem_client13_read_transition(s, mt))
@@ -234,6 +250,11 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
                 st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
                 return 1;
             }
+        } else {
+            if (mt == SSL3_MT_HELLO_RETRY_REQUEST) {
+                st->hand_state = TLS_ST_CR_HELLO_RETRY_REQUEST;
+                return 1;
+            }
         }
         break;
 
@@ -385,20 +406,23 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
     OSSL_STATEM *st = &s->statem;
 
     /*
-     * TODO(TLS1.3): This is still based on the TLSv1.2 state machine. Over time
-     * we will update this to look more like real TLSv1.3
-     */
-
-    /*
-     * Note: There are no cases for TLS_ST_BEFORE or TLS_ST_CW_CLNT_HELLO,
-     * because we haven't negotiated TLSv1.3 yet at that point. They are
-     * handled by ossl_statem_client_write_transition().
+     * Note: There are no cases for TLS_ST_BEFORE because we haven't negotiated
+     * TLSv1.3 yet at that point. They are handled by
+     * ossl_statem_client_write_transition().
      */
     switch (st->hand_state) {
     default:
         /* Shouldn't happen */
         return WRITE_TRAN_ERROR;
 
+    case TLS_ST_CW_CLNT_HELLO:
+        /* We only hit this in the case of HelloRetryRequest */
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_CR_HELLO_RETRY_REQUEST:
+        st->hand_state = TLS_ST_CW_CLNT_HELLO;
+        return WRITE_TRAN_CONTINUE;
+
     case TLS_ST_CR_FINISHED:
         st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
                                                     : TLS_ST_CW_FINISHED;
@@ -414,6 +438,14 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
         st->hand_state = TLS_ST_CW_FINISHED;
         return WRITE_TRAN_CONTINUE;
 
+    case TLS_ST_CR_KEY_UPDATE:
+        if (s->key_update != SSL_KEY_UPDATE_NONE) {
+            st->hand_state = TLS_ST_CW_KEY_UPDATE;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_CW_KEY_UPDATE:
     case TLS_ST_CR_SESSION_TICKET:
     case TLS_ST_CW_FINISHED:
         st->hand_state = TLS_ST_OK;
@@ -421,7 +453,12 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
         return WRITE_TRAN_CONTINUE;
 
     case TLS_ST_OK:
-        /* Just go straight to trying to read from the server */
+        if (s->key_update != SSL_KEY_UPDATE_NONE) {
+            st->hand_state = TLS_ST_CW_KEY_UPDATE;
+            return WRITE_TRAN_CONTINUE;
+        }
+
+        /* Try to read from the server instead */
         return WRITE_TRAN_FINISHED;
     }
 }
@@ -694,6 +731,13 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
             return WORK_ERROR;
         }
         break;
+
+    case TLS_ST_CW_KEY_UPDATE:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        if (!tls13_update_key(s, 1))
+            return WORK_ERROR;
+        break;
     }
 
     return WORK_FINISHED_CONTINUE;
@@ -755,6 +799,11 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
         *confunc = tls_construct_finished;
         *mt = SSL3_MT_FINISHED;
         break;
+
+    case TLS_ST_CW_KEY_UPDATE:
+        *confunc = tls_construct_key_update;
+        *mt = SSL3_MT_KEY_UPDATE;
+        break;
     }
 
     return 1;
@@ -779,6 +828,9 @@ size_t ossl_statem_client_max_message_size(SSL *s)
     case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
         return HELLO_VERIFY_REQUEST_MAX_LENGTH;
 
+    case TLS_ST_CR_HELLO_RETRY_REQUEST:
+        return HELLO_RETRY_REQUEST_MAX_LENGTH;
+
     case TLS_ST_CR_CERT:
         return s->max_cert_list;
 
@@ -815,6 +867,9 @@ size_t ossl_statem_client_max_message_size(SSL *s)
 
     case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
         return ENCRYPTED_EXTENSIONS_MAX_LENGTH;
+
+    case TLS_ST_CR_KEY_UPDATE:
+        return KEY_UPDATE_MAX_LENGTH;
     }
 }
 
@@ -836,6 +891,9 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
     case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
         return dtls_process_hello_verify(s, pkt);
 
+    case TLS_ST_CR_HELLO_RETRY_REQUEST:
+        return tls_process_hello_retry_request(s, pkt);
+
     case TLS_ST_CR_CERT:
         return tls_process_server_certificate(s, pkt);
 
@@ -868,6 +926,9 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
 
     case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
         return tls_process_encrypted_extensions(s, pkt);
+
+    case TLS_ST_CR_KEY_UPDATE:
+        return tls_process_key_update(s, pkt);
     }
 }
 
@@ -1193,7 +1254,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
 
     context = SSL_IS_TLS13(s) ? EXT_TLS1_3_SERVER_HELLO
                               : EXT_TLS1_2_SERVER_HELLO;
-    if (!tls_collect_extensions(s, &extpkt, context, &extensions, &al))
+    if (!tls_collect_extensions(s, &extpkt, context, &extensions, &al, NULL))
         goto f_err;
 
     s->hit = 0;
@@ -1233,7 +1294,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
                      && master_key_length > 0) {
                 s->session->master_key_length = master_key_length;
                 s->session->cipher = pref_cipher ?
-                    pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
+                    pref_cipher : ssl_get_cipher_by_char(s, cipherchars, 0);
             } else {
                 SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
                 al = SSL_AD_INTERNAL_ERROR;
@@ -1292,7 +1353,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    c = ssl_get_cipher_by_char(s, cipherchars);
+    c = ssl_get_cipher_by_char(s, cipherchars, 0);
     if (c == NULL) {
         /* unknown cipher */
         al = SSL_AD_ILLEGAL_PARAMETER;
@@ -1432,6 +1493,52 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
+static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
+{
+    unsigned int sversion;
+    int errorcode;
+    RAW_EXTENSION *extensions = NULL;
+    int al;
+    PACKET extpkt;
+
+    if (!PACKET_get_net_2(pkt, &sversion)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    s->hello_retry_request = 1;
+
+    /* This will fail if it doesn't choose TLSv1.3+ */
+    errorcode = ssl_choose_client_version(s, sversion);
+    if (errorcode != 0) {
+        al = SSL_AD_PROTOCOL_VERSION;
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, errorcode);
+        goto f_err;
+    }
+
+    if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_BAD_LENGTH);
+        goto f_err;
+    }
+
+    if (!tls_collect_extensions(s, &extpkt, EXT_TLS1_3_HELLO_RETRY_REQUEST,
+                                &extensions, &al, NULL)
+            || !tls_parse_all_extensions(s, EXT_TLS1_3_HELLO_RETRY_REQUEST,
+                                         extensions, NULL, 0, &al))
+        goto f_err;
+
+    OPENSSL_free(extensions);
+
+    return MSG_PROCESS_FINISHED_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    ossl_statem_set_error(s);
+    OPENSSL_free(extensions);
+    return MSG_PROCESS_ERROR;
+}
+
 MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
 {
     int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
@@ -1489,7 +1596,7 @@ MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
                 goto f_err;
             }
             if (!tls_collect_extensions(s, &extensions, EXT_TLS1_3_CERTIFICATE,
-                                        &rawexts, &al)
+                                        &rawexts, &al, NULL)
                     || !tls_parse_all_extensions(s, EXT_TLS1_3_CERTIFICATE,
                                                  rawexts, x, chainidx, &al)) {
                 OPENSSL_free(rawexts);
@@ -1562,17 +1669,23 @@ MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
                SSL_R_UNKNOWN_CERTIFICATE_TYPE);
         goto f_err;
     }
-
-    exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
-    if (exp_idx >= 0 && i != exp_idx
-        && (exp_idx != SSL_PKEY_GOST_EC ||
-            (i != SSL_PKEY_GOST12_512 && i != SSL_PKEY_GOST12_256
-             && i != SSL_PKEY_GOST01))) {
-        x = NULL;
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
-               SSL_R_WRONG_CERTIFICATE_TYPE);
-        goto f_err;
+    /*
+     * Check certificate type is consistent with ciphersuite. For TLS 1.3
+     * skip check since TLS 1.3 ciphersuites can be used with any certificate
+     * type.
+     */
+    if (!SSL_IS_TLS13(s)) {
+        exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+        if (exp_idx >= 0 && i != exp_idx
+            && (exp_idx != SSL_PKEY_GOST_EC ||
+                (i != SSL_PKEY_GOST12_512 && i != SSL_PKEY_GOST12_256
+                 && i != SSL_PKEY_GOST01))) {
+            x = NULL;
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                   SSL_R_WRONG_CERTIFICATE_TYPE);
+            goto f_err;
+        }
     }
     s->session->peer_type = i;
 
@@ -1975,16 +2088,16 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
                 al = SSL_AD_DECODE_ERROR;
                 goto err;
             }
-            md = s->s3->tmp.peer_md;
 #ifdef SSL_DEBUG
             fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
 #endif
-        } else if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) {
-            md = EVP_md5_sha1();
-        } else {
-            md = EVP_sha1();
+        } else if (!tls1_set_peer_legacy_sigalg(s, pkey)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            goto err;
         }
 
+        md = ssl_md(s->s3->tmp.peer_sigalg->hash_idx);
+
         if (!PACKET_get_length_prefixed_2(pkt, &signature)
             || PACKET_remaining(pkt) != 0) {
             al = SSL_AD_DECODE_ERROR;
@@ -2127,11 +2240,9 @@ MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
             goto err;
         }
 
-        /* Clear certificate digests and validity flags */
-        for (i = 0; i < SSL_PKEY_NUM; i++) {
-            s->s3->tmp.md[i] = NULL;
+        /* Clear certificate validity flags */
+        for (i = 0; i < SSL_PKEY_NUM; i++)
             s->s3->tmp.valid_flags[i] = 0;
-        }
         if (!tls1_save_sigalgs(s, &sigalgs)) {
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
             SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
@@ -2143,8 +2254,6 @@ MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
             SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
             goto err;
         }
-    } else {
-        ssl_set_default_md(s);
     }
 
     /* get the CA RDNs */
@@ -2290,7 +2399,7 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
         if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
                 || !tls_collect_extensions(s, &extpkt,
                                            EXT_TLS1_3_NEW_SESSION_TICKET,
-                                           &exts, &al)
+                                           &exts, &al, NULL)
                 || !tls_parse_all_extensions(s, EXT_TLS1_3_NEW_SESSION_TICKET,
                                              exts, NULL, 0, &al)) {
             SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_BAD_EXTENSION);
@@ -3007,10 +3116,8 @@ int tls_client_key_exchange_post_work(SSL *s)
  */
 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->s3->tmp.md[s->cert->key - s->cert->pkeys])
+    if (!tls_choose_sigalg(s, NULL) || s->s3->tmp.sigalg == NULL)
         return 0;
     /*
      * If strict mode check suitability of chain before using it. This also
@@ -3255,7 +3362,7 @@ static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
     }
 
     if (!tls_collect_extensions(s, &extensions, EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
-                                &rawexts, &al)
+                                &rawexts, &al, NULL)
             || !tls_parse_all_extensions(s, EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
                                          rawexts, NULL, 0, &al))
         goto err;