Updated to hostap_2_6
[mech_eap.git] / libeap / src / tls / tlsv1_client_write.c
index d192f44..04d895e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - write handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -47,8 +47,28 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
        struct os_time now;
        size_t len, i;
+       u8 *ext_start;
+       u16 tls_version = TLS_VERSION;
 
-       wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+       /* Pick the highest locally enabled TLS version */
+#ifdef CONFIG_TLSV12
+       if ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+           tls_version == TLS_VERSION_1_2)
+               tls_version = TLS_VERSION_1_1;
+#endif /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+       if ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+           tls_version == TLS_VERSION_1_1)
+               tls_version = TLS_VERSION_1;
+#endif /* CONFIG_TLSV11 */
+       if ((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+           tls_version == TLS_VERSION_1) {
+               wpa_printf(MSG_INFO, "TLSv1: No TLS version allowed");
+               return NULL;
+       }
+
+       wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello (ver %s)",
+                  tls_version_str(tls_version));
        *out_len = 0;
 
        os_get_time(&now);
@@ -61,7 +81,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
                    conn->client_random, TLS_RANDOM_LEN);
 
-       len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
+       len = 150 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
        hello = os_malloc(len);
        if (hello == NULL)
                return NULL;
@@ -81,7 +101,7 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        pos += 3;
        /* body - ClientHello */
        /* ProtocolVersion client_version */
-       WPA_PUT_BE16(pos, TLS_VERSION);
+       WPA_PUT_BE16(pos, tls_version);
        pos += 2;
        /* Random random: uint32 gmt_unix_time, opaque random_bytes */
        os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
@@ -101,12 +121,124 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
        *pos++ = 1;
        *pos++ = TLS_COMPRESSION_NULL;
 
+       /* Extension */
+       ext_start = pos;
+       pos += 2;
+
+#ifdef CONFIG_TLSV12
+       if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+               /*
+                * Add signature_algorithms extension since we support only
+                * SHA256 (and not the default SHA1) with TLSv1.2.
+                */
+               /* ExtensionsType extension_type = signature_algorithms(13) */
+               WPA_PUT_BE16(pos, TLS_EXT_SIGNATURE_ALGORITHMS);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 8);
+               pos += 2;
+               /* supported_signature_algorithms<2..2^16-2> length */
+               WPA_PUT_BE16(pos, 6);
+               pos += 2;
+               /* supported_signature_algorithms */
+               *pos++ = TLS_HASH_ALG_SHA512;
+               *pos++ = TLS_SIGN_ALG_RSA;
+               *pos++ = TLS_HASH_ALG_SHA384;
+               *pos++ = TLS_SIGN_ALG_RSA;
+               *pos++ = TLS_HASH_ALG_SHA256;
+               *pos++ = TLS_SIGN_ALG_RSA;
+       }
+#endif /* CONFIG_TLSV12 */
+
        if (conn->client_hello_ext) {
                os_memcpy(pos, conn->client_hello_ext,
                          conn->client_hello_ext_len);
                pos += conn->client_hello_ext_len;
        }
 
+       if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Add status_request extension for OCSP stapling");
+               /* ExtensionsType extension_type = status_request(5) */
+               WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 5);
+               pos += 2;
+
+               /*
+                * RFC 6066, 8:
+                * struct {
+                *     CertificateStatusType status_type;
+                *     select (status_type) {
+                *         case ocsp: OCSPStatusRequest;
+                *     } request;
+                * } CertificateStatusRequest;
+                *
+                * enum { ocsp(1), (255) } CertificateStatusType;
+                */
+               *pos++ = 1; /* status_type = ocsp(1) */
+
+               /*
+                * struct {
+                *     ResponderID responder_id_list<0..2^16-1>;
+                *     Extensions  request_extensions;
+                * } OCSPStatusRequest;
+                *
+                * opaque ResponderID<1..2^16-1>;
+                * opaque Extensions<0..2^16-1>;
+                */
+               WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+               pos += 2;
+               WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+               pos += 2;
+
+               wpa_printf(MSG_DEBUG,
+                          "TLSv1: Add status_request_v2 extension for OCSP stapling");
+               /* ExtensionsType extension_type = status_request_v2(17) */
+               WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+               pos += 2;
+               /* opaque extension_data<0..2^16-1> length */
+               WPA_PUT_BE16(pos, 7);
+               pos += 2;
+
+               /*
+                * RFC 6961, 2.2:
+                * struct {
+                *     CertificateStatusType status_type;
+                *     uint16 request_length;
+                *     select (status_type) {
+                *         case ocsp: OCSPStatusRequest;
+                *         case ocsp_multi: OCSPStatusRequest;
+                *     } request;
+                * } CertificateStatusRequestItemV2;
+                *
+                * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+                *
+                * struct {
+                * CertificateStatusRequestItemV2
+                *     certificate_status_req_list<1..2^16-1>;
+                * } CertificateStatusRequestListV2;
+                */
+
+               /* certificate_status_req_list<1..2^16-1> */
+               WPA_PUT_BE16(pos, 5);
+               pos += 2;
+
+               /* CertificateStatusRequestItemV2 */
+               *pos++ = 2; /* status_type = ocsp_multi(2) */
+               /* OCSPStatusRequest as shown above for v1 */
+               WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+               pos += 2;
+               WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+               pos += 2;
+       }
+
+       if (pos == ext_start + 2)
+               pos -= 2; /* no extensions */
+       else
+               WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
        WPA_PUT_BE24(hs_length, pos - hs_length - 3);
        tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
@@ -134,6 +266,11 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
        struct x509_certificate *cert;
 
        pos = *msgpos;
+       if (TLS_RECORD_HEADER_LEN + 1 + 3 + 3 > end - pos) {
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_INTERNAL_ERROR);
+               return -1;
+       }
 
        wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
        rhdr = pos;
@@ -154,7 +291,7 @@ static int tls_write_client_certificate(struct tlsv1_client *conn,
        pos += 3;
        cert = conn->cred ? conn->cred->cert : NULL;
        while (cert) {
-               if (pos + 3 + cert->cert_len > end) {
+               if (3 + cert->cert_len > (size_t) (end - pos)) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
                                   "for Certificate (cert_len=%lu left=%lu)",
                                   (unsigned long) cert->cert_len,
@@ -265,9 +402,16 @@ static int tlsv1_key_x_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
        wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
                    dh_yc, dh_yc_len);
 
+       if (end - *pos < 2) {
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_INTERNAL_ERROR);
+               os_free(csecret);
+               os_free(dh_yc);
+               return -1;
+       }
        WPA_PUT_BE16(*pos, dh_yc_len);
        *pos += 2;
-       if (*pos + dh_yc_len > end) {
+       if (dh_yc_len > (size_t) (end - *pos)) {
                wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
                           "message buffer for Yc");
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -789,6 +933,8 @@ static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
 
        wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
                   "successfully");
+       if (!conn->session_resumed && conn->use_session_ticket)
+               conn->session_resumed = 1;
        conn->state = ESTABLISHED;
 
        return msg;