Set TLS v1.2 disabled mask properly.
[openssl.git] / ssl / s3_clnt.c
index dbf790c3136806ea08ce6b5274cd8c52dcfe187a..24c180c4d7294a961463fe5a49a3fbdf6d9b9b28 100644 (file)
@@ -307,13 +307,6 @@ int ssl3_connect(SSL *s)
                                }
                        else
                                {
-#ifndef OPENSSL_NO_TLSEXT
-                               /* The server hello indicated that
-                                * an audit proof would follow. */
-                               if (s->s3->tlsext_authz_server_promised)
-                                       s->state=SSL3_ST_CR_SUPPLEMENTAL_DATA_A;
-                               else
-#endif
                                        s->state=SSL3_ST_CR_CERT_A;
                                }
                        s->init_num=0;
@@ -332,6 +325,12 @@ int ssl3_connect(SSL *s)
 #ifndef OPENSSL_NO_TLSEXT
                        ret=ssl3_check_finished(s);
                        if (ret <= 0) goto end;
+                       if (ret == 3)
+                               {
+                               s->state=SSL3_ST_CR_SUPPLEMENTAL_DATA_A;
+                               s->init_num=0;
+                               break;
+                               }
                        if (ret == 2)
                                {
                                s->hit = 1;
@@ -410,10 +409,14 @@ int ssl3_connect(SSL *s)
                                        }
                                }
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+                       s->state=SSL3_ST_CW_SUPPLEMENTAL_DATA_A;
+#else
                        if (s->s3->tmp.cert_req)
                                s->state=SSL3_ST_CW_CERT_A;
                        else
                                s->state=SSL3_ST_CW_KEY_EXCH_A;
+#endif
                        s->init_num=0;
 
                        break;
@@ -520,6 +523,19 @@ int ssl3_connect(SSL *s)
                        break;
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+               case SSL3_ST_CW_SUPPLEMENTAL_DATA_A:
+               case SSL3_ST_CW_SUPPLEMENTAL_DATA_B:
+                       ret = tls1_send_client_supplemental_data(s, &skip);
+                       if (ret <= 0) goto end;
+                       if (s->s3->tmp.cert_req)
+                               s->state=SSL3_ST_CW_CERT_A;
+                       else
+                               s->state=SSL3_ST_CW_KEY_EXCH_A;
+                       s->init_num=0;
+                       break;
+#endif
+
                case SSL3_ST_CW_FINISHED_A:
                case SSL3_ST_CW_FINISHED_B:
                        ret=ssl3_send_finished(s,
@@ -694,6 +710,41 @@ int ssl3_client_hello(SSL *s)
                        if (!ssl_get_new_session(s,0))
                                goto err;
                        }
+               if (s->method->version == DTLS_ANY_VERSION)
+                       {
+                       /* Determine which DTLS version to use */
+                       int options = s->options;
+                       /* 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;
+                       }
                /* else use the pre-loaded session */
 
                p=s->s3->client_random;
@@ -721,6 +772,7 @@ int ssl3_client_hello(SSL *s)
                        Time=(unsigned long)time(NULL); /* Time */
                        l2n(Time,p);
                        RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4);
+                                       
                        }
 
                /* Do the message type and length last */
@@ -873,6 +925,11 @@ int ssl3_get_server_hello(SSL *s)
 #ifndef OPENSSL_NO_COMP
        SSL_COMP *comp;
 #endif
+       /* Hello verify request and/or server hello version may not
+        * match so set first packet if we're negotiating version.
+        */
+       if (s->method->version == DTLS_ANY_VERSION)
+               s->first_packet = 1;
 
        n=s->method->ssl_get_message(s,
                SSL3_ST_CR_SRVR_HELLO_A,
@@ -883,8 +940,9 @@ int ssl3_get_server_hello(SSL *s)
 
        if (!ok) return((int)n);
 
-       if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+       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)
@@ -909,6 +967,33 @@ int ssl3_get_server_hello(SSL *s)
                }
 
        d=p=(unsigned char *)s->init_msg;
+       if (s->method->version == DTLS_ANY_VERSION)
+               {
+               /* Work out correct protocol version to use */
+               int hversion = (p[0] << 8)|p[1];
+               int 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_SSL3_GET_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_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_SSL_VERSION);
+                       s->version = hversion;
+                       al = SSL_AD_PROTOCOL_VERSION;
+                       goto f_err;
+                       }
+               s->version = s->client_version = s->method->version;
+               }
 
        if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
                {
@@ -988,6 +1073,11 @@ int ssl3_get_server_hello(SSL *s)
                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
                goto f_err;
                }
+       /* Set version disabled mask now we know version */
+       if (!SSL_USE_TLS1_2_CIPHERS(s))
+               ct->mask_ssl = SSL_TLSV1_2;
+       else
+               ct->mask_ssl = 0;
        /* If it is a disabled cipher we didn't send it in client hello,
         * so return an error.
         */
@@ -1288,21 +1378,6 @@ int ssl3_get_server_certificate(SSL *s)
        s->session->verify_result = s->verify_result;
 
        x=NULL;
-#ifndef OPENSSL_NO_TLSEXT
-       /* Check the audit proof. */
-       if (s->ctx->tlsext_authz_server_audit_proof_cb)
-               {
-               ret = s->ctx->tlsext_authz_server_audit_proof_cb(s,
-                       s->ctx->tlsext_authz_server_audit_proof_cb_arg);
-               if (ret <= 0)
-                       {
-                       al = SSL_AD_BAD_CERTIFICATE;
-                       SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_INVALID_AUDIT_PROOF);
-                       goto f_err;
-                       }
-               }
-
-#endif
        ret=1;
        if (0)
                {
@@ -1684,7 +1759,7 @@ int ssl3_get_key_exchange(SSL *s)
                 * and the ECParameters in this case is just three bytes.
                 */
                param_len=3;
-               /* Check curve is one of our prefrences, if not server has
+               /* Check curve is one of our preferences, if not server has
                 * sent an invalid curve.
                 */
                if (!tls1_check_curve(s, p, param_len))
@@ -3404,14 +3479,14 @@ int ssl3_check_cert_and_algorithm(SSL *s)
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY);
                goto f_err;
                }
-       else if ((alg_k & SSL_kDHr) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+       else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
                !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_RSA_CERT);
                goto f_err;
                }
 #ifndef OPENSSL_NO_DSA
-       else if ((alg_k & SSL_kDHd) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+       else if ((alg_k & SSL_kDHd) && !SSL_USE_SIGALGS(s) &&
                !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
                {
                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_DSA_CERT);
@@ -3494,11 +3569,11 @@ int ssl3_check_finished(SSL *s)
        {
        int ok;
        long n;
-       /* 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 */
+
+       /* Read the message to see if it is supplemental data,
+        * regardless if there is a session ticket this function is
+        * called when we really expect a Certificate message, so
+        * permit appropriate message length */
        n=s->method->ssl_get_message(s,
                SSL3_ST_CR_CERT_A,
                SSL3_ST_CR_CERT_B,
@@ -3507,6 +3582,12 @@ int ssl3_check_finished(SSL *s)
                &ok);
        if (!ok) return((int)n);
        s->s3->tmp.reuse_message = 1;
+
+       if (s->s3->tmp.message_type == SSL3_MT_SUPPLEMENTAL_DATA)
+               return 3;
+       /* If we have no ticket it cannot be a resumed session. */
+       if (!s->session->tlsext_tick)
+               return 1;
        if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
                || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
                return 2;
@@ -3534,15 +3615,102 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
        }
 
 #ifndef OPENSSL_NO_TLSEXT
+int tls1_send_client_supplemental_data(SSL *s, int *skip)
+       {
+       if (s->ctx->cli_supp_data_records_count)
+               {
+               unsigned char *p = NULL;
+               unsigned char *size_loc = NULL;
+               cli_supp_data_record *record = NULL;
+               size_t length = 0;
+               size_t i = 0;
+
+               for (i = 0; i < s->ctx->cli_supp_data_records_count; i++)
+                       {
+                       const unsigned char *out = NULL;
+                       unsigned short outlen = 0;
+                       int cb_retval = 0;
+                       record = &s->ctx->cli_supp_data_records[i];
+
+                       /* NULL callback or -1 omits supp data entry*/
+                       if (!record->fn2)
+                               continue;
+                       cb_retval = record->fn2(s, record->supp_data_type,
+                               &out, &outlen,
+                               record->arg);
+                       if (cb_retval == -1)
+                               continue; /* skip this supp data entry */
+                       if (cb_retval == 0)
+                               {
+                               SSLerr(SSL_F_TLS1_SEND_CLIENT_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+                               return 0;
+                               }
+                       if (outlen == 0 || TLSEXT_MAXLEN_supplemental_data < outlen + 4 + length)
+                               {
+                               SSLerr(SSL_F_TLS1_SEND_CLIENT_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+                               return 0;
+                               }
+                       /* if first entry, write handshake message type */
+                       if (length == 0)
+                               {
+                               if (!BUF_MEM_grow_clean(s->init_buf, 4))
+                                       {
+                                       SSLerr(SSL_F_TLS1_SEND_CLIENT_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+                                       return 0;
+                                       }
+                               p = (unsigned char *)s->init_buf->data;
+                               *(p++) = SSL3_MT_SUPPLEMENTAL_DATA;
+                               /* update message length when all
+                                * callbacks complete */
+                               size_loc = p;
+                               /* skip over handshake length field (3
+                                * bytes) and supp_data length field
+                                * (3 bytes) */
+                               p += 3 + 3;
+                               length += 1 +3 +3;
+                               }
+                       if (!BUF_MEM_grow(s->init_buf, outlen + 4))
+                               {
+                               SSLerr(SSL_F_TLS1_SEND_CLIENT_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+                               return 0;
+                               }
+                       s2n(record->supp_data_type, p);
+                       s2n(outlen, p);
+                       memcpy(p, out, outlen);
+                       length += (outlen + 4);
+                       p += outlen;
+                       }
+               if (length > 0)
+                       {
+                       /* write handshake length */
+                       l2n3(length - 4, size_loc);
+                       /* supp_data length */
+                       l2n3(length - 7, size_loc);
+                       s->state = SSL3_ST_CW_SUPPLEMENTAL_DATA_B;
+                       s->init_num = length;
+                       s->init_off = 0;
+                       return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+                       }
+               }
+
+       /* no supp data message sent */
+       *skip = 1;
+       s->init_num = 0;
+       s->init_off = 0;
+       return 1;
+       }
+
 int tls1_get_server_supplemental_data(SSL *s)
        {
-       int al;
+       int al = 0;
        int ok;
-       unsigned long supp_data_len, authz_data_len;
        long n;
-       unsigned short supp_data_type, authz_data_type, proof_len;
-       const unsigned char *p;
-       unsigned char *new_proof;
+       const unsigned char *p, *d;
+       unsigned short supp_data_entry_type = 0;
+       unsigned long supp_data_entry_len = 0;
+       unsigned long supp_data_len = 0;
+       size_t i;
+       int cb_retval = 0;
 
        n=s->method->ssl_get_message(s,
                SSL3_ST_CR_SUPPLEMENTAL_DATA_A,
@@ -3555,7 +3723,7 @@ int tls1_get_server_supplemental_data(SSL *s)
        if (!ok) return((int)n);
 
        p = (unsigned char *)s->init_msg;
-
+       d = p;
        /* The message cannot be empty */
        if (n < 3)
                {
@@ -3563,72 +3731,26 @@ int tls1_get_server_supplemental_data(SSL *s)
                SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
                goto f_err;
                }
-       /* Length of supplemental data */
-       n2l3(p,supp_data_len);
-       n -= 3;
-       /* We must have at least one supplemental data entry
-        * with type (1 byte) and length (2 bytes). */
-       if (supp_data_len != (unsigned long) n || n < 4)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       /* Supplemental data type: must be authz_data */
-       n2s(p,supp_data_type);
-       n -= 2;
-       if (supp_data_type != TLSEXT_SUPPLEMENTALDATATYPE_authz_data)
-               {
-               al = SSL_AD_UNEXPECTED_MESSAGE;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE);
-               goto f_err;
-               }
-       /* Authz data length */
-       n2s(p, authz_data_len);
-       n -= 2;
-       if (authz_data_len != (unsigned long) n || n < 1)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       /* Authz data type: must be audit_proof */
-       authz_data_type = *(p++);
-       n -= 1;
-       if (authz_data_type != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+       n2l3(p, supp_data_len);
+       while (p < d+supp_data_len)
                {
-               al=SSL_AD_UNEXPECTED_MESSAGE;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_AUTHZ_DATA_TYPE);
-               goto f_err;
-               }
-       /* We have a proof: read its length */
-       if (n < 2)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       n2s(p, proof_len);
-       n -= 2;
-       if (proof_len != (unsigned long) n)
-               {
-               al = SSL_AD_DECODE_ERROR;
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
-               goto f_err;
-               }
-       /* Store the proof */
-       new_proof = OPENSSL_realloc(s->session->audit_proof,
-                                   proof_len);
-       if (new_proof == NULL)
-               {
-               SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,ERR_R_MALLOC_FAILURE);
-               return 0;
+               n2s(p, supp_data_entry_type);
+               n2s(p, supp_data_entry_len);
+               /* if there is a callback for this supp data type, send it */
+               for (i=0; i < s->ctx->cli_supp_data_records_count; i++)
+                       {
+                       if (s->ctx->cli_supp_data_records[i].supp_data_type == supp_data_entry_type && s->ctx->cli_supp_data_records[i].fn1)
+                               {
+                               cb_retval = s->ctx->cli_supp_data_records[i].fn1(s, supp_data_entry_type, p, supp_data_entry_len, &al, s->ctx->cli_supp_data_records[i].arg);
+                               if (cb_retval == 0)
+                                       {
+                                       SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA, ERR_R_SSL_LIB);
+                                       goto f_err;
+                                       }
+                               }
+                       }
+               p += supp_data_entry_len;
                }
-       s->session->audit_proof_length = proof_len;
-       s->session->audit_proof = new_proof;
-       memcpy(s->session->audit_proof, p, proof_len);
-
-       /* Got the proof, but can't verify it yet. */
        return 1;
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);