diff options
Diffstat (limited to 'src/tls/tlsv1_client_write.c')
-rw-r--r-- | src/tls/tlsv1_client_write.c | 158 |
1 files changed, 152 insertions, 6 deletions
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c index d192f44f4088..04d895e61926 100644 --- a/src/tls/tlsv1_client_write.c +++ b/src/tls/tlsv1_client_write.c @@ -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; |