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);
}
Exemplo n.º 2
0
static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
{
#ifdef EAP_FAST
	/* ClientDiffieHellmanPublic */
	u8 *csecret, *csecret_start, *dh_yc, *shared;
	size_t csecret_len, dh_yc_len, shared_len;

	csecret_len = conn->dh_p_len;
	csecret = os_malloc(csecret_len);
	if (csecret == NULL) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
			   "memory for Yc (Diffie-Hellman)");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		return -1;
	}
	if (os_get_random(csecret, csecret_len)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
			   "data for Diffie-Hellman");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		os_free(csecret);
		return -1;
	}

	if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
		csecret[0] = 0; /* make sure Yc < p */

	csecret_start = csecret;
	while (csecret_len > 1 && *csecret_start == 0) {
		csecret_start++;
		csecret_len--;
	}
	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
			csecret_start, csecret_len);

	/* Yc = g^csecret mod p */
	dh_yc_len = conn->dh_p_len;
	dh_yc = os_malloc(dh_yc_len);
	if (dh_yc == NULL) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
			   "memory for Diffie-Hellman");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		os_free(csecret);
		return -1;
	}
	if (crypto_mod_exp(conn->dh_g, conn->dh_g_len,
			   csecret_start, csecret_len,
			   conn->dh_p, conn->dh_p_len,
			   dh_yc, &dh_yc_len)) {
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		os_free(csecret);
		os_free(dh_yc);
		return -1;
	}

	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
		    dh_yc, dh_yc_len);

	WPA_PUT_BE16(*pos, dh_yc_len);
	*pos += 2;
	if (*pos + dh_yc_len > end) {
		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
			   "message buffer for Yc");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		os_free(csecret);
		os_free(dh_yc);
		return -1;
	}
	os_memcpy(*pos, dh_yc, dh_yc_len);
	*pos += dh_yc_len;
	os_free(dh_yc);

	shared_len = conn->dh_p_len;
	shared = os_malloc(shared_len);
	if (shared == NULL) {
		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
			   "DH");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		os_free(csecret);
		return -1;
	}

	/* shared = Ys^csecret mod p */
	if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
			   csecret_start, csecret_len,
			   conn->dh_p, conn->dh_p_len,
			   shared, &shared_len)) {
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		os_free(csecret);
		os_free(shared);
		return -1;
	}
	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
			shared, shared_len);

	os_memset(csecret_start, 0, csecret_len);
	os_free(csecret);
	if (tls_derive_keys(conn, shared, shared_len)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
			  TLS_ALERT_INTERNAL_ERROR);
		os_free(shared);
		return -1;
	}
	os_memset(shared, 0, shared_len);
	os_free(shared);
	tlsv1_client_free_dh(conn);
	return 0;
#else /* EAP_FAST */
	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR);
	return -1;
#endif /* EAP_FAST */
}
static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
					const u8 *buf, size_t len,
					tls_key_exchange key_exchange)
{
	const u8 *pos, *end, *server_params, *server_params_end;
	u8 alert;
	unsigned int bits;

	tlsv1_client_free_dh(conn);

	pos = buf;
	end = buf + len;

	if (end - pos < 3)
		goto fail;
	server_params = pos;
	conn->dh_p_len = WPA_GET_BE16(pos);
	pos += 2;
	if (conn->dh_p_len == 0 || conn->dh_p_len > (size_t) (end - pos)) {
		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
			   (unsigned long) conn->dh_p_len);
		goto fail;
	}
	bits = count_bits(pos, conn->dh_p_len);
	if (bits < 768) {
		wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)",
			   bits);
		wpa_hexdump(MSG_DEBUG, "TLSv1: Rejected DH prime",
			    pos, conn->dh_p_len);
		goto fail;
	}
	conn->dh_p = os_malloc(conn->dh_p_len);
	if (conn->dh_p == NULL)
		goto fail;
	os_memcpy(conn->dh_p, pos, conn->dh_p_len);
	pos += conn->dh_p_len;
	wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
		    conn->dh_p, conn->dh_p_len);

	if (end - pos < 3)
		goto fail;
	conn->dh_g_len = WPA_GET_BE16(pos);
	pos += 2;
	if (conn->dh_g_len == 0 || conn->dh_g_len > (size_t) (end - pos))
		goto fail;
	conn->dh_g = os_malloc(conn->dh_g_len);
	if (conn->dh_g == NULL)
		goto fail;
	os_memcpy(conn->dh_g, pos, conn->dh_g_len);
	pos += conn->dh_g_len;
	wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
		    conn->dh_g, conn->dh_g_len);
	if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
		goto fail;

	if (end - pos < 3)
		goto fail;
	conn->dh_ys_len = WPA_GET_BE16(pos);
	pos += 2;
	if (conn->dh_ys_len == 0 || conn->dh_ys_len > (size_t) (end - pos))
		goto fail;
	conn->dh_ys = os_malloc(conn->dh_ys_len);
	if (conn->dh_ys == NULL)
		goto fail;
	os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
	pos += conn->dh_ys_len;
	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
		    conn->dh_ys, conn->dh_ys_len);
	server_params_end = pos;

	if (key_exchange == TLS_KEY_X_DHE_RSA) {
		u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
		int hlen;

		if (conn->rl.tls_version == TLS_VERSION_1_2) {
#ifdef CONFIG_TLSV12
			/*
			 * RFC 5246, 4.7:
			 * TLS v1.2 adds explicit indication of the used
			 * signature and hash algorithms.
			 *
			 * struct {
			 *   HashAlgorithm hash;
			 *   SignatureAlgorithm signature;
			 * } SignatureAndHashAlgorithm;
			 */
			if (end - pos < 2)
				goto fail;
			if (pos[0] != TLS_HASH_ALG_SHA256 ||
			    pos[1] != TLS_SIGN_ALG_RSA) {
				wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
					   pos[0], pos[1]);
				goto fail;
			}
			pos += 2;

			hlen = tlsv12_key_x_server_params_hash(
				conn->rl.tls_version, conn->client_random,
				conn->server_random, server_params,
				server_params_end - server_params, hash);
#else /* CONFIG_TLSV12 */
			goto fail;
#endif /* CONFIG_TLSV12 */
		} else {
			hlen = tls_key_x_server_params_hash(
				conn->rl.tls_version, conn->client_random,
				conn->server_random, server_params,
				server_params_end - server_params, hash);
		}

		if (hlen < 0)
			goto fail;
		wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerKeyExchange hash",
			    hash, hlen);

		if (tls_verify_signature(conn->rl.tls_version,
					 conn->server_rsa_key,
					 hash, hlen, pos, end - pos,
					 &alert) < 0)
			goto fail;
	}

	return 0;

fail:
	wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
	tlsv1_client_free_dh(conn);
	return -1;
}
static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
                                        const u8 *buf, size_t len)
{
        const u8 *pos, *end;

        tlsv1_client_free_dh(conn);

        pos = buf;
        end = buf + len;

        if (end - pos < 3)
                goto fail;
        conn->dh_p_len = WPA_GET_BE16(pos);
        pos += 2;
        if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
                wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
                           (unsigned long) conn->dh_p_len);
                goto fail;
        }
        conn->dh_p = os_malloc(conn->dh_p_len);
        if (conn->dh_p == NULL)
                goto fail;
        os_memcpy(conn->dh_p, pos, conn->dh_p_len);
        pos += conn->dh_p_len;
        wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
                    conn->dh_p, conn->dh_p_len);

        if (end - pos < 3)
                goto fail;
        conn->dh_g_len = WPA_GET_BE16(pos);
        pos += 2;
        if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
                goto fail;
        conn->dh_g = os_malloc(conn->dh_g_len);
        if (conn->dh_g == NULL)
                goto fail;
        os_memcpy(conn->dh_g, pos, conn->dh_g_len);
        pos += conn->dh_g_len;
        wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
                    conn->dh_g, conn->dh_g_len);
        if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
                goto fail;

        if (end - pos < 3)
                goto fail;
        conn->dh_ys_len = WPA_GET_BE16(pos);
        pos += 2;
        if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
                goto fail;
        conn->dh_ys = os_malloc(conn->dh_ys_len);
        if (conn->dh_ys == NULL)
                goto fail;
        os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
        pos += conn->dh_ys_len;
        wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
                    conn->dh_ys, conn->dh_ys_len);

        return 0;

fail:
        wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
        tlsv1_client_free_dh(conn);
        return -1;
}