Exemplo n.º 1
0
/**
 * tlsv1_client_deinit - Deinitialize TLSv1 client connection
 * @conn: TLSv1 client connection data from tlsv1_client_init()
 */
void tlsv1_client_deinit(struct tlsv1_client *conn)
{
	crypto_public_key_free(conn->server_rsa_key);
	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
	tlsv1_record_change_write_cipher(&conn->rl);
	tlsv1_record_change_read_cipher(&conn->rl);
	tls_verify_hash_free(&conn->verify);
	os_free(conn->client_hello_ext);
	tlsv1_client_free_dh(conn);
	tlsv1_cred_free(conn->cred);
	os_free(conn);
}
static void tlsv1_server_clear_data(struct tlsv1_server *conn)
{
	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
	tlsv1_record_change_write_cipher(&conn->rl);
	tlsv1_record_change_read_cipher(&conn->rl);
	tls_verify_hash_free(&conn->verify);

	crypto_public_key_free(conn->client_rsa_key);
	conn->client_rsa_key = NULL;

	os_free(conn->session_ticket);
	conn->session_ticket = NULL;
	conn->session_ticket_len = 0;
	conn->use_session_ticket = 0;

	os_free(conn->dh_secret);
	conn->dh_secret = NULL;
	conn->dh_secret_len = 0;
}
Exemplo n.º 3
0
/**
 * tlsv1_client_shutdown - Shutdown TLS connection
 * @conn: TLSv1 client connection data from tlsv1_client_init()
 * Returns: 0 on success, -1 on failure
 */
int tlsv1_client_shutdown(struct tlsv1_client *conn)
{
	conn->state = CLIENT_HELLO;

	if (tls_verify_hash_init(&conn->verify) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
			   "hash");
		return -1;
	}

	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
	tlsv1_record_change_write_cipher(&conn->rl);
	tlsv1_record_change_read_cipher(&conn->rl);

	conn->certificate_requested = 0;
	crypto_public_key_free(conn->server_rsa_key);
	conn->server_rsa_key = NULL;
	conn->session_resumed = 0;

	return 0;
}
Exemplo n.º 4
0
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
        const u8 *in_data, size_t *in_len) {
    const u8 *pos, *end, *c;
    size_t left, len, i, j;
    u16 cipher_suite;
    u16 num_suites;
    int compr_null_found;
    u16 ext_type, ext_len;

    if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
        wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
                "received content type 0x%x", ct);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_UNEXPECTED_MESSAGE);
        return -1;
    }

    pos = in_data;
    left = *in_len;

    if (left < 4)
        goto decode_error;

    /* HandshakeType msg_type */
    if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
        wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
                "message %d (expected ClientHello)", *pos);
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_UNEXPECTED_MESSAGE);
        return -1;
    }
    wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
    pos++;
    /* uint24 length */
    len = WPA_GET_BE24(pos);
    pos += 3;
    left -= 4;

    if (len > left)
        goto decode_error;

    /* body - ClientHello */

    wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
    end = pos + len;

    /* ProtocolVersion client_version */
    if (end - pos < 2)
        goto decode_error;
    conn->client_version = WPA_GET_BE16(pos);
    wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
            conn->client_version >> 8, conn->client_version & 0xff);
    if (conn->client_version < TLS_VERSION) {
        wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
                "ClientHello");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_PROTOCOL_VERSION);
        return -1;
    }
    pos += 2;

    /* Random random */
    if (end - pos < TLS_RANDOM_LEN)
        goto decode_error;

    os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
    pos += TLS_RANDOM_LEN;
    wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
            conn->client_random, TLS_RANDOM_LEN);

    /* SessionID session_id */
    if (end - pos < 1)
        goto decode_error;
    if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
        goto decode_error;
    wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
    pos += 1 + *pos;
    /* TODO: add support for session resumption */

    /* CipherSuite cipher_suites<2..2^16-1> */
    if (end - pos < 2)
        goto decode_error;
    num_suites = WPA_GET_BE16(pos);
    pos += 2;
    if (end - pos < num_suites)
        goto decode_error;
    wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
            pos, num_suites);
    if (num_suites & 1)
        goto decode_error;
    num_suites /= 2;

    cipher_suite = 0;
    for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
        c = pos;
        for (j = 0; j < num_suites; j++) {
            u16 tmp = WPA_GET_BE16(c);
            c += 2;
            if (!cipher_suite && tmp == conn->cipher_suites[i]) {
                cipher_suite = tmp;
                break;
            }
        }
    }
    pos += num_suites * 2;
    if (!cipher_suite) {
        wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
                "available");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_ILLEGAL_PARAMETER);
        return -1;
    }

    if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
        wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
                "record layer");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_INTERNAL_ERROR);
        return -1;
    }

    conn->cipher_suite = cipher_suite;

    /* CompressionMethod compression_methods<1..2^8-1> */
    if (end - pos < 1)
        goto decode_error;
    num_suites = *pos++;
    if (end - pos < num_suites)
        goto decode_error;
    wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
            pos, num_suites);
    compr_null_found = 0;
    for (i = 0; i < num_suites; i++) {
        if (*pos++ == TLS_COMPRESSION_NULL)
            compr_null_found = 1;
    }
    if (!compr_null_found) {
        wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
                "compression");
        tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
                TLS_ALERT_ILLEGAL_PARAMETER);
        return -1;
    }

    if (end - pos == 1) {
        wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
                "end of ClientHello: 0x%02x", *pos);
        goto decode_error;
    }

    if (end - pos >= 2) {
        /* Extension client_hello_extension_list<0..2^16-1> */
        ext_len = WPA_GET_BE16(pos);
        pos += 2;

        wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
                "extensions", ext_len);
        if (end - pos != ext_len) {
            wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
                    "extension list length %u (expected %u)",
                    ext_len, (unsigned int) (end - pos));
            goto decode_error;
        }

        /*
         * struct {
         *   ExtensionType extension_type (0..65535)
         *   opaque extension_data<0..2^16-1>
         * } Extension;
         */

        while (pos < end) {
            if (end - pos < 2) {
                wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
                        "extension_type field");
                goto decode_error;
            }

            ext_type = WPA_GET_BE16(pos);
            pos += 2;

            if (end - pos < 2) {
                wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
                        "extension_data length field");
                goto decode_error;
            }

            ext_len = WPA_GET_BE16(pos);
            pos += 2;

            if (end - pos < ext_len) {
                wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
                        "extension_data field");
                goto decode_error;
            }

            wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
                    "type %u", ext_type);
            wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
                    "Extension data", pos, ext_len);

            if (ext_type == TLS_EXT_SESSION_TICKET) {
                os_free(conn->session_ticket);
                conn->session_ticket = os_malloc(ext_len);
                if (conn->session_ticket) {
                    os_memcpy(conn->session_ticket, pos,
                            ext_len);
                    conn->session_ticket_len = ext_len;
                }
            }

            pos += ext_len;
        }
    }

    *in_len = end - in_data;

    wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
            "ServerHello");
    conn->state = SERVER_HELLO;

    return 0;

decode_error:
    wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
    tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
            TLS_ALERT_DECODE_ERROR);
    return -1;
}
static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
				    const u8 *in_data, size_t *in_len)
{
	const u8 *pos, *end;
	size_t left, len, i;
	u16 cipher_suite;
	u16 tls_version;

	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
			   "received content type 0x%x", ct);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_UNEXPECTED_MESSAGE);
		return -1;
	}

	pos = in_data;
	left = *in_len;

	if (left < 4)
		goto decode_error;

	/* HandshakeType msg_type */
	if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
			   "message %d (expected ServerHello)", *pos);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_UNEXPECTED_MESSAGE);
		return -1;
	}
	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
	pos++;
	/* uint24 length */
	len = WPA_GET_BE24(pos);
	pos += 3;
	left -= 4;

	if (len > left)
		goto decode_error;

	/* body - ServerHello */

	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
	end = pos + len;

	/* ProtocolVersion server_version */
	if (end - pos < 2)
		goto decode_error;
	tls_version = WPA_GET_BE16(pos);
	if (!tls_version_ok(tls_version)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
			   "ServerHello %u.%u", pos[0], pos[1]);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_PROTOCOL_VERSION);
		return -1;
	}
	pos += 2;

	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
		   tls_version_str(tls_version));
	conn->rl.tls_version = tls_version;

	/* Random random */
	if (end - pos < TLS_RANDOM_LEN)
		goto decode_error;

	os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
	pos += TLS_RANDOM_LEN;
	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
		    conn->server_random, TLS_RANDOM_LEN);

	/* SessionID session_id */
	if (end - pos < 1)
		goto decode_error;
	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
		goto decode_error;
	if (conn->session_id_len && conn->session_id_len == *pos &&
	    os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
		pos += 1 + conn->session_id_len;
		wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
		conn->session_resumed = 1;
	} else {
		conn->session_id_len = *pos;
		pos++;
		os_memcpy(conn->session_id, pos, conn->session_id_len);
		pos += conn->session_id_len;
	}
	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
		    conn->session_id, conn->session_id_len);

	/* CipherSuite cipher_suite */
	if (end - pos < 2)
		goto decode_error;
	cipher_suite = WPA_GET_BE16(pos);
	pos += 2;
	for (i = 0; i < conn->num_cipher_suites; i++) {
		if (cipher_suite == conn->cipher_suites[i])
			break;
	}
	if (i == conn->num_cipher_suites) {
		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
			   "cipher suite 0x%04x", cipher_suite);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_ILLEGAL_PARAMETER);
		return -1;
	}

	if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
		wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
			   "cipher suite for a resumed connection (0x%04x != "
			   "0x%04x)", cipher_suite, conn->prev_cipher_suite);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_ILLEGAL_PARAMETER);
		return -1;
	}

	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
			   "record layer");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}

	conn->prev_cipher_suite = cipher_suite;

	/* CompressionMethod compression_method */
	if (end - pos < 1)
		goto decode_error;
	if (*pos != TLS_COMPRESSION_NULL) {
		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
			   "compression 0x%02x", *pos);
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_ILLEGAL_PARAMETER);
		return -1;
	}
	pos++;

	if (end != pos) {
		/* TODO: ServerHello extensions */
		wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
			    "end of ServerHello", pos, end - pos);
		goto decode_error;
	}

	if (conn->session_ticket_included && conn->session_ticket_cb) {
		/* TODO: include SessionTicket extension if one was included in
		 * ServerHello */
		int res = conn->session_ticket_cb(
			conn->session_ticket_cb_ctx, NULL, 0,
			conn->client_random, conn->server_random,
			conn->master_secret);
		if (res < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
				   "indicated failure");
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
				  TLS_ALERT_HANDSHAKE_FAILURE);
			return -1;
		}
		conn->use_session_ticket = !!res;
	}

	if ((conn->session_resumed || conn->use_session_ticket) &&
	    tls_derive_keys(conn, NULL, 0)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}

	*in_len = end - in_data;

	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
		SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;

	return 0;

decode_error:
	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
	return -1;
}