18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/hmdfs/comm/crypto.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "crypto.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <crypto/aead.h>
118c2ecf20Sopenharmony_ci#include <crypto/hash.h>
128c2ecf20Sopenharmony_ci#include <linux/tcp.h>
138c2ecf20Sopenharmony_ci#include <net/inet_connection_sock.h>
148c2ecf20Sopenharmony_ci#include <net/tcp_states.h>
158c2ecf20Sopenharmony_ci#include <net/tls.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "hmdfs.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void tls_crypto_set_key(struct connection *conn_impl, int tx)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	int rc = 0;
228c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = conn_impl->connect_handle;
238c2ecf20Sopenharmony_ci	struct tls_context *ctx = NULL;
248c2ecf20Sopenharmony_ci	struct cipher_context *cctx = NULL;
258c2ecf20Sopenharmony_ci	struct tls_sw_context_tx *sw_ctx_tx = NULL;
268c2ecf20Sopenharmony_ci	struct tls_sw_context_rx *sw_ctx_rx = NULL;
278c2ecf20Sopenharmony_ci	struct crypto_aead **aead = NULL;
288c2ecf20Sopenharmony_ci	struct tls12_crypto_info_aes_gcm_128 *crypto_info = NULL;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	lock_sock(tcp->sock->sk);
318c2ecf20Sopenharmony_ci	ctx = tls_get_ctx(tcp->sock->sk);
328c2ecf20Sopenharmony_ci	if (tx) {
338c2ecf20Sopenharmony_ci		crypto_info = &conn_impl->send_crypto_info;
348c2ecf20Sopenharmony_ci		cctx = &ctx->tx;
358c2ecf20Sopenharmony_ci		sw_ctx_tx = tls_sw_ctx_tx(ctx);
368c2ecf20Sopenharmony_ci		aead = &sw_ctx_tx->aead_send;
378c2ecf20Sopenharmony_ci	} else {
388c2ecf20Sopenharmony_ci		crypto_info = &conn_impl->recv_crypto_info;
398c2ecf20Sopenharmony_ci		cctx = &ctx->rx;
408c2ecf20Sopenharmony_ci		sw_ctx_rx = tls_sw_ctx_rx(ctx);
418c2ecf20Sopenharmony_ci		aead = &sw_ctx_rx->aead_recv;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	memcpy(cctx->iv, crypto_info->salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
458c2ecf20Sopenharmony_ci	memcpy(cctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, crypto_info->iv,
468c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_IV_SIZE);
478c2ecf20Sopenharmony_ci	memcpy(cctx->rec_seq, crypto_info->rec_seq,
488c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
498c2ecf20Sopenharmony_ci	rc = crypto_aead_setkey(*aead, crypto_info->key,
508c2ecf20Sopenharmony_ci				TLS_CIPHER_AES_GCM_128_KEY_SIZE);
518c2ecf20Sopenharmony_ci	if (rc)
528c2ecf20Sopenharmony_ci		hmdfs_err("crypto set key error");
538c2ecf20Sopenharmony_ci	release_sock(tcp->sock->sk);
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciint tls_crypto_info_init(struct connection *conn_impl)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	int ret = 0;
598c2ecf20Sopenharmony_ci	u8 key_meterial[HMDFS_KEY_SIZE];
608c2ecf20Sopenharmony_ci	struct tcp_handle *tcp =
618c2ecf20Sopenharmony_ci		(struct tcp_handle *)(conn_impl->connect_handle);
628c2ecf20Sopenharmony_ci	if (!tcp)
638c2ecf20Sopenharmony_ci		return -EINVAL;
648c2ecf20Sopenharmony_ci	// send
658c2ecf20Sopenharmony_ci	update_key(conn_impl->send_key, key_meterial, HKDF_TYPE_IV);
668c2ecf20Sopenharmony_ci	ret = tcp->sock->ops->setsockopt(tcp->sock, SOL_TCP, TCP_ULP,
678c2ecf20Sopenharmony_ci							KERNEL_SOCKPTR("tls"), sizeof("tls"));
688c2ecf20Sopenharmony_ci	if (ret)
698c2ecf20Sopenharmony_ci		hmdfs_err("set tls error %d", ret);
708c2ecf20Sopenharmony_ci	tcp->connect->send_crypto_info.info.version = TLS_1_2_VERSION;
718c2ecf20Sopenharmony_ci	tcp->connect->send_crypto_info.info.cipher_type =
728c2ecf20Sopenharmony_ci		TLS_CIPHER_AES_GCM_128;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.key, tcp->connect->send_key,
758c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_KEY_SIZE);
768c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.iv,
778c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_IV_OFFSET, TLS_CIPHER_AES_GCM_128_IV_SIZE);
788c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.salt,
798c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SALT_OFFSET,
808c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_SALT_SIZE);
818c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.rec_seq,
828c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SEQ_OFFSET,
838c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	ret = tcp->sock->ops->setsockopt(tcp->sock, SOL_TLS, TLS_TX,
868c2ecf20Sopenharmony_ci				KERNEL_SOCKPTR(&(tcp->connect->send_crypto_info)),
878c2ecf20Sopenharmony_ci				sizeof(tcp->connect->send_crypto_info));
888c2ecf20Sopenharmony_ci	if (ret)
898c2ecf20Sopenharmony_ci		hmdfs_err("set tls send_crypto_info error %d", ret);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	// recv
928c2ecf20Sopenharmony_ci	update_key(tcp->connect->recv_key, key_meterial, HKDF_TYPE_IV);
938c2ecf20Sopenharmony_ci	tcp->connect->recv_crypto_info.info.version = TLS_1_2_VERSION;
948c2ecf20Sopenharmony_ci	tcp->connect->recv_crypto_info.info.cipher_type =
958c2ecf20Sopenharmony_ci		TLS_CIPHER_AES_GCM_128;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.key, tcp->connect->recv_key,
988c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_KEY_SIZE);
998c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.iv,
1008c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_IV_OFFSET, TLS_CIPHER_AES_GCM_128_IV_SIZE);
1018c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.salt,
1028c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SALT_OFFSET,
1038c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_SALT_SIZE);
1048c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.rec_seq,
1058c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SEQ_OFFSET,
1068c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
1078c2ecf20Sopenharmony_ci	memset(key_meterial, 0, HMDFS_KEY_SIZE);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	ret = tcp->sock->ops->setsockopt(tcp->sock, SOL_TLS, TLS_RX,
1108c2ecf20Sopenharmony_ci				KERNEL_SOCKPTR(&(tcp->connect->recv_crypto_info)),
1118c2ecf20Sopenharmony_ci				sizeof(tcp->connect->recv_crypto_info));
1128c2ecf20Sopenharmony_ci	if (ret)
1138c2ecf20Sopenharmony_ci		hmdfs_err("set tls recv_crypto_info error %d", ret);
1148c2ecf20Sopenharmony_ci	return ret;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int tls_set_tx(struct tcp_handle *tcp)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	int ret = 0;
1208c2ecf20Sopenharmony_ci	u8 new_key[HMDFS_KEY_SIZE];
1218c2ecf20Sopenharmony_ci	u8 key_meterial[HMDFS_KEY_SIZE];
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	ret = update_key(tcp->connect->send_key, new_key, HKDF_TYPE_REKEY);
1248c2ecf20Sopenharmony_ci	if (ret < 0)
1258c2ecf20Sopenharmony_ci		return ret;
1268c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_key, new_key, HMDFS_KEY_SIZE);
1278c2ecf20Sopenharmony_ci	ret = update_key(tcp->connect->send_key, key_meterial, HKDF_TYPE_IV);
1288c2ecf20Sopenharmony_ci	if (ret < 0)
1298c2ecf20Sopenharmony_ci		return ret;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.key, tcp->connect->send_key,
1328c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_KEY_SIZE);
1338c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.iv,
1348c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_IV_OFFSET, TLS_CIPHER_AES_GCM_128_IV_SIZE);
1358c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.salt,
1368c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SALT_OFFSET,
1378c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_SALT_SIZE);
1388c2ecf20Sopenharmony_ci	memcpy(tcp->connect->send_crypto_info.rec_seq,
1398c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SEQ_OFFSET,
1408c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
1418c2ecf20Sopenharmony_ci	memset(new_key, 0, HMDFS_KEY_SIZE);
1428c2ecf20Sopenharmony_ci	memset(key_meterial, 0, HMDFS_KEY_SIZE);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	tls_crypto_set_key(tcp->connect, 1);
1458c2ecf20Sopenharmony_ci	return 0;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int tls_set_rx(struct tcp_handle *tcp)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	int ret = 0;
1518c2ecf20Sopenharmony_ci	u8 new_key[HMDFS_KEY_SIZE];
1528c2ecf20Sopenharmony_ci	u8 key_meterial[HMDFS_KEY_SIZE];
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	ret = update_key(tcp->connect->recv_key, new_key, HKDF_TYPE_REKEY);
1558c2ecf20Sopenharmony_ci	if (ret < 0)
1568c2ecf20Sopenharmony_ci		return ret;
1578c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_key, new_key, HMDFS_KEY_SIZE);
1588c2ecf20Sopenharmony_ci	ret = update_key(tcp->connect->recv_key, key_meterial, HKDF_TYPE_IV);
1598c2ecf20Sopenharmony_ci	if (ret < 0)
1608c2ecf20Sopenharmony_ci		return ret;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.key, tcp->connect->recv_key,
1638c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_KEY_SIZE);
1648c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.iv,
1658c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_IV_OFFSET, TLS_CIPHER_AES_GCM_128_IV_SIZE);
1668c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.salt,
1678c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SALT_OFFSET,
1688c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_SALT_SIZE);
1698c2ecf20Sopenharmony_ci	memcpy(tcp->connect->recv_crypto_info.rec_seq,
1708c2ecf20Sopenharmony_ci	       key_meterial + CRYPTO_SEQ_OFFSET,
1718c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
1728c2ecf20Sopenharmony_ci	memset(new_key, 0, HMDFS_KEY_SIZE);
1738c2ecf20Sopenharmony_ci	memset(key_meterial, 0, HMDFS_KEY_SIZE);
1748c2ecf20Sopenharmony_ci	tls_crypto_set_key(tcp->connect, 0);
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ciint set_crypto_info(struct connection *conn_impl, int set_type)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	int ret = 0;
1818c2ecf20Sopenharmony_ci	struct tcp_handle *tcp =
1828c2ecf20Sopenharmony_ci		(struct tcp_handle *)(conn_impl->connect_handle);
1838c2ecf20Sopenharmony_ci	if (!tcp)
1848c2ecf20Sopenharmony_ci		return -EINVAL;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (set_type == SET_CRYPTO_SEND) {
1878c2ecf20Sopenharmony_ci		ret = tls_set_tx(tcp);
1888c2ecf20Sopenharmony_ci		if (ret) {
1898c2ecf20Sopenharmony_ci			hmdfs_err("tls set tx fail");
1908c2ecf20Sopenharmony_ci			return ret;
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci	if (set_type == SET_CRYPTO_RECV) {
1948c2ecf20Sopenharmony_ci		ret = tls_set_rx(tcp);
1958c2ecf20Sopenharmony_ci		if (ret) {
1968c2ecf20Sopenharmony_ci			hmdfs_err("tls set rx fail");
1978c2ecf20Sopenharmony_ci			return ret;
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci	hmdfs_info("KTLS setting success");
2018c2ecf20Sopenharmony_ci	return ret;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int hmac_sha256(u8 *key, u8 key_len, char *info, u8 info_len, u8 *output)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct crypto_shash *tfm = NULL;
2078c2ecf20Sopenharmony_ci	struct shash_desc *shash = NULL;
2088c2ecf20Sopenharmony_ci	int ret = 0;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (!key)
2118c2ecf20Sopenharmony_ci		return -EINVAL;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
2148c2ecf20Sopenharmony_ci	if (IS_ERR(tfm)) {
2158c2ecf20Sopenharmony_ci		hmdfs_err("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm));
2168c2ecf20Sopenharmony_ci		return PTR_ERR(tfm);
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	ret = crypto_shash_setkey(tfm, key, key_len);
2208c2ecf20Sopenharmony_ci	if (ret) {
2218c2ecf20Sopenharmony_ci		hmdfs_err("crypto_ahash_setkey failed: err %d", ret);
2228c2ecf20Sopenharmony_ci		goto failed;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
2268c2ecf20Sopenharmony_ci			GFP_KERNEL);
2278c2ecf20Sopenharmony_ci	if (!shash) {
2288c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2298c2ecf20Sopenharmony_ci		goto failed;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	shash->tfm = tfm;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	ret = crypto_shash_digest(shash, info, info_len, output);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	kfree(shash);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cifailed:
2398c2ecf20Sopenharmony_ci	crypto_free_shash(tfm);
2408c2ecf20Sopenharmony_ci	return ret;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic const char *const g_key_lable[] = { "ktls key initiator",
2448c2ecf20Sopenharmony_ci					   "ktls key accepter",
2458c2ecf20Sopenharmony_ci					   "ktls key update", "ktls iv&salt" };
2468c2ecf20Sopenharmony_cistatic const int g_key_lable_len[] = { 18, 17, 15, 12 };
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ciint update_key(__u8 *old_key, __u8 *new_key, int type)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	int ret = 0;
2518c2ecf20Sopenharmony_ci	char lable[MAX_LABLE_SIZE];
2528c2ecf20Sopenharmony_ci	u8 lable_size;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	lable_size = g_key_lable_len[type] + sizeof(u16) + sizeof(char);
2558c2ecf20Sopenharmony_ci	*((u16 *)lable) = HMDFS_KEY_SIZE;
2568c2ecf20Sopenharmony_ci	memcpy(lable + sizeof(u16), g_key_lable[type], g_key_lable_len[type]);
2578c2ecf20Sopenharmony_ci	*(lable + sizeof(u16) + g_key_lable_len[type]) = 0x01;
2588c2ecf20Sopenharmony_ci	ret = hmac_sha256(old_key, HMDFS_KEY_SIZE, lable, lable_size, new_key);
2598c2ecf20Sopenharmony_ci	if (ret < 0)
2608c2ecf20Sopenharmony_ci		hmdfs_err("hmac sha256 error");
2618c2ecf20Sopenharmony_ci	return ret;
2628c2ecf20Sopenharmony_ci}
263