18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* RxRPC security handling
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/net.h>
108c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
118c2ecf20Sopenharmony_ci#include <linux/udp.h>
128c2ecf20Sopenharmony_ci#include <linux/crypto.h>
138c2ecf20Sopenharmony_ci#include <net/sock.h>
148c2ecf20Sopenharmony_ci#include <net/af_rxrpc.h>
158c2ecf20Sopenharmony_ci#include <keys/rxrpc-type.h>
168c2ecf20Sopenharmony_ci#include "ar-internal.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic const struct rxrpc_security *rxrpc_security_types[] = {
198c2ecf20Sopenharmony_ci	[RXRPC_SECURITY_NONE]	= &rxrpc_no_security,
208c2ecf20Sopenharmony_ci#ifdef CONFIG_RXKAD
218c2ecf20Sopenharmony_ci	[RXRPC_SECURITY_RXKAD]	= &rxkad,
228c2ecf20Sopenharmony_ci#endif
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciint __init rxrpc_init_security(void)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	int i, ret;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++) {
308c2ecf20Sopenharmony_ci		if (rxrpc_security_types[i]) {
318c2ecf20Sopenharmony_ci			ret = rxrpc_security_types[i]->init();
328c2ecf20Sopenharmony_ci			if (ret < 0)
338c2ecf20Sopenharmony_ci				goto failed;
348c2ecf20Sopenharmony_ci		}
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return 0;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cifailed:
408c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
418c2ecf20Sopenharmony_ci		if (rxrpc_security_types[i])
428c2ecf20Sopenharmony_ci			rxrpc_security_types[i]->exit();
438c2ecf20Sopenharmony_ci	return ret;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_civoid rxrpc_exit_security(void)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	int i;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++)
518c2ecf20Sopenharmony_ci		if (rxrpc_security_types[i])
528c2ecf20Sopenharmony_ci			rxrpc_security_types[i]->exit();
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * look up an rxrpc security module
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_cistatic const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	if (security_index >= ARRAY_SIZE(rxrpc_security_types))
618c2ecf20Sopenharmony_ci		return NULL;
628c2ecf20Sopenharmony_ci	return rxrpc_security_types[security_index];
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/*
668c2ecf20Sopenharmony_ci * initialise the security on a client connection
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_ciint rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	const struct rxrpc_security *sec;
718c2ecf20Sopenharmony_ci	struct rxrpc_key_token *token;
728c2ecf20Sopenharmony_ci	struct key *key = conn->params.key;
738c2ecf20Sopenharmony_ci	int ret;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	_enter("{%d},{%x}", conn->debug_id, key_serial(key));
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (!key)
788c2ecf20Sopenharmony_ci		return 0;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	ret = key_validate(key);
818c2ecf20Sopenharmony_ci	if (ret < 0)
828c2ecf20Sopenharmony_ci		return ret;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	token = key->payload.data[0];
858c2ecf20Sopenharmony_ci	if (!token)
868c2ecf20Sopenharmony_ci		return -EKEYREJECTED;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	sec = rxrpc_security_lookup(token->security_index);
898c2ecf20Sopenharmony_ci	if (!sec)
908c2ecf20Sopenharmony_ci		return -EKEYREJECTED;
918c2ecf20Sopenharmony_ci	conn->security = sec;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	ret = conn->security->init_connection_security(conn);
948c2ecf20Sopenharmony_ci	if (ret < 0) {
958c2ecf20Sopenharmony_ci		conn->security = &rxrpc_no_security;
968c2ecf20Sopenharmony_ci		return ret;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	_leave(" = 0");
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/*
1048c2ecf20Sopenharmony_ci * Find the security key for a server connection.
1058c2ecf20Sopenharmony_ci */
1068c2ecf20Sopenharmony_cibool rxrpc_look_up_server_security(struct rxrpc_local *local, struct rxrpc_sock *rx,
1078c2ecf20Sopenharmony_ci				   const struct rxrpc_security **_sec,
1088c2ecf20Sopenharmony_ci				   struct key **_key,
1098c2ecf20Sopenharmony_ci				   struct sk_buff *skb)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	const struct rxrpc_security *sec;
1128c2ecf20Sopenharmony_ci	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
1138c2ecf20Sopenharmony_ci	key_ref_t kref = NULL;
1148c2ecf20Sopenharmony_ci	char kdesc[5 + 1 + 3 + 1];
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	_enter("");
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	sprintf(kdesc, "%u:%u", sp->hdr.serviceId, sp->hdr.securityIndex);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	sec = rxrpc_security_lookup(sp->hdr.securityIndex);
1218c2ecf20Sopenharmony_ci	if (!sec) {
1228c2ecf20Sopenharmony_ci		trace_rxrpc_abort(0, "SVS",
1238c2ecf20Sopenharmony_ci				  sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
1248c2ecf20Sopenharmony_ci				  RX_INVALID_OPERATION, EKEYREJECTED);
1258c2ecf20Sopenharmony_ci		skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
1268c2ecf20Sopenharmony_ci		skb->priority = RX_INVALID_OPERATION;
1278c2ecf20Sopenharmony_ci		return false;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (sp->hdr.securityIndex == RXRPC_SECURITY_NONE)
1318c2ecf20Sopenharmony_ci		goto out;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (!rx->securities) {
1348c2ecf20Sopenharmony_ci		trace_rxrpc_abort(0, "SVR",
1358c2ecf20Sopenharmony_ci				  sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
1368c2ecf20Sopenharmony_ci				  RX_INVALID_OPERATION, EKEYREJECTED);
1378c2ecf20Sopenharmony_ci		skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
1388c2ecf20Sopenharmony_ci		skb->priority = RX_INVALID_OPERATION;
1398c2ecf20Sopenharmony_ci		return false;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* look through the service's keyring */
1438c2ecf20Sopenharmony_ci	kref = keyring_search(make_key_ref(rx->securities, 1UL),
1448c2ecf20Sopenharmony_ci			      &key_type_rxrpc_s, kdesc, true);
1458c2ecf20Sopenharmony_ci	if (IS_ERR(kref)) {
1468c2ecf20Sopenharmony_ci		trace_rxrpc_abort(0, "SVK",
1478c2ecf20Sopenharmony_ci				  sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
1488c2ecf20Sopenharmony_ci				  sec->no_key_abort, EKEYREJECTED);
1498c2ecf20Sopenharmony_ci		skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
1508c2ecf20Sopenharmony_ci		skb->priority = sec->no_key_abort;
1518c2ecf20Sopenharmony_ci		return false;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ciout:
1558c2ecf20Sopenharmony_ci	*_sec = sec;
1568c2ecf20Sopenharmony_ci	*_key = key_ref_to_ptr(kref);
1578c2ecf20Sopenharmony_ci	return true;
1588c2ecf20Sopenharmony_ci}
159