12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28c3e34a4SDavid Howells /* RxRPC security handling
38c3e34a4SDavid Howells *
48c3e34a4SDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
58c3e34a4SDavid Howells * Written by David Howells (dhowells@redhat.com)
68c3e34a4SDavid Howells */
78c3e34a4SDavid Howells
88c3e34a4SDavid Howells #include <linux/module.h>
98c3e34a4SDavid Howells #include <linux/net.h>
108c3e34a4SDavid Howells #include <linux/skbuff.h>
118c3e34a4SDavid Howells #include <linux/udp.h>
128c3e34a4SDavid Howells #include <linux/crypto.h>
138c3e34a4SDavid Howells #include <net/sock.h>
148c3e34a4SDavid Howells #include <net/af_rxrpc.h>
158c3e34a4SDavid Howells #include <keys/rxrpc-type.h>
168c3e34a4SDavid Howells #include "ar-internal.h"
178c3e34a4SDavid Howells
188c3e34a4SDavid Howells static const struct rxrpc_security *rxrpc_security_types[] = {
198c3e34a4SDavid Howells [RXRPC_SECURITY_NONE] = &rxrpc_no_security,
208c3e34a4SDavid Howells #ifdef CONFIG_RXKAD
218c3e34a4SDavid Howells [RXRPC_SECURITY_RXKAD] = &rxkad,
228c3e34a4SDavid Howells #endif
238c3e34a4SDavid Howells };
248c3e34a4SDavid Howells
rxrpc_init_security(void)258c3e34a4SDavid Howells int __init rxrpc_init_security(void)
268c3e34a4SDavid Howells {
278c3e34a4SDavid Howells int i, ret;
288c3e34a4SDavid Howells
298c3e34a4SDavid Howells for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++) {
308c3e34a4SDavid Howells if (rxrpc_security_types[i]) {
318c3e34a4SDavid Howells ret = rxrpc_security_types[i]->init();
328c3e34a4SDavid Howells if (ret < 0)
338c3e34a4SDavid Howells goto failed;
348c3e34a4SDavid Howells }
358c3e34a4SDavid Howells }
368c3e34a4SDavid Howells
378c3e34a4SDavid Howells return 0;
388c3e34a4SDavid Howells
398c3e34a4SDavid Howells failed:
408c3e34a4SDavid Howells for (i--; i >= 0; i--)
418c3e34a4SDavid Howells if (rxrpc_security_types[i])
428c3e34a4SDavid Howells rxrpc_security_types[i]->exit();
438c3e34a4SDavid Howells return ret;
448c3e34a4SDavid Howells }
458c3e34a4SDavid Howells
rxrpc_exit_security(void)468c3e34a4SDavid Howells void rxrpc_exit_security(void)
478c3e34a4SDavid Howells {
488c3e34a4SDavid Howells int i;
498c3e34a4SDavid Howells
508c3e34a4SDavid Howells for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++)
518c3e34a4SDavid Howells if (rxrpc_security_types[i])
528c3e34a4SDavid Howells rxrpc_security_types[i]->exit();
538c3e34a4SDavid Howells }
548c3e34a4SDavid Howells
558c3e34a4SDavid Howells /*
568c3e34a4SDavid Howells * look up an rxrpc security module
578c3e34a4SDavid Howells */
rxrpc_security_lookup(u8 security_index)5812da59fcSDavid Howells const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
598c3e34a4SDavid Howells {
608c3e34a4SDavid Howells if (security_index >= ARRAY_SIZE(rxrpc_security_types))
618c3e34a4SDavid Howells return NULL;
628c3e34a4SDavid Howells return rxrpc_security_types[security_index];
638c3e34a4SDavid Howells }
648c3e34a4SDavid Howells
658c3e34a4SDavid Howells /*
66f3441d41SDavid Howells * Initialise the security on a client call.
67f3441d41SDavid Howells */
rxrpc_init_client_call_security(struct rxrpc_call * call)68f3441d41SDavid Howells int rxrpc_init_client_call_security(struct rxrpc_call *call)
69f3441d41SDavid Howells {
70fdb99487SDavid Howells const struct rxrpc_security *sec = &rxrpc_no_security;
71f3441d41SDavid Howells struct rxrpc_key_token *token;
72f3441d41SDavid Howells struct key *key = call->key;
73f3441d41SDavid Howells int ret;
74f3441d41SDavid Howells
75f3441d41SDavid Howells if (!key)
76fdb99487SDavid Howells goto found;
77f3441d41SDavid Howells
78f3441d41SDavid Howells ret = key_validate(key);
79f3441d41SDavid Howells if (ret < 0)
80f3441d41SDavid Howells return ret;
81f3441d41SDavid Howells
82f3441d41SDavid Howells for (token = key->payload.data[0]; token; token = token->next) {
83f3441d41SDavid Howells sec = rxrpc_security_lookup(token->security_index);
84f3441d41SDavid Howells if (sec)
85f3441d41SDavid Howells goto found;
86f3441d41SDavid Howells }
87f3441d41SDavid Howells return -EKEYREJECTED;
88f3441d41SDavid Howells
89f3441d41SDavid Howells found:
90f3441d41SDavid Howells call->security = sec;
91fdb99487SDavid Howells call->security_ix = sec->security_index;
92f3441d41SDavid Howells return 0;
93f3441d41SDavid Howells }
94f3441d41SDavid Howells
95f3441d41SDavid Howells /*
968c3e34a4SDavid Howells * initialise the security on a client connection
978c3e34a4SDavid Howells */
rxrpc_init_client_conn_security(struct rxrpc_connection * conn)988c3e34a4SDavid Howells int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
998c3e34a4SDavid Howells {
1008c3e34a4SDavid Howells struct rxrpc_key_token *token;
1012cc80086SDavid Howells struct key *key = conn->key;
1029d35d880SDavid Howells int ret = 0;
1038c3e34a4SDavid Howells
1048c3e34a4SDavid Howells _enter("{%d},{%x}", conn->debug_id, key_serial(key));
1058c3e34a4SDavid Howells
10641057ebdSDavid Howells for (token = key->payload.data[0]; token; token = token->next) {
1079d35d880SDavid Howells if (token->security_index == conn->security->security_index)
10841057ebdSDavid Howells goto found;
10941057ebdSDavid Howells }
1108c3e34a4SDavid Howells return -EKEYREJECTED;
1118c3e34a4SDavid Howells
11241057ebdSDavid Howells found:
1139d35d880SDavid Howells mutex_lock(&conn->security_lock);
1149d35d880SDavid Howells if (conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
11541057ebdSDavid Howells ret = conn->security->init_connection_security(conn, token);
1169d35d880SDavid Howells if (ret == 0) {
1179d35d880SDavid Howells spin_lock(&conn->state_lock);
1189d35d880SDavid Howells if (conn->state == RXRPC_CONN_CLIENT_UNSECURED)
1199d35d880SDavid Howells conn->state = RXRPC_CONN_CLIENT;
1209d35d880SDavid Howells spin_unlock(&conn->state_lock);
1218c3e34a4SDavid Howells }
1229d35d880SDavid Howells }
1239d35d880SDavid Howells mutex_unlock(&conn->security_lock);
1249d35d880SDavid Howells return ret;
1258c3e34a4SDavid Howells }
1268c3e34a4SDavid Howells
1278c3e34a4SDavid Howells /*
128ec832bd0SDavid Howells * Set the ops a server connection.
1298c3e34a4SDavid Howells */
rxrpc_get_incoming_security(struct rxrpc_sock * rx,struct sk_buff * skb)130ec832bd0SDavid Howells const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx,
131063c60d3SDavid Howells struct sk_buff *skb)
1328c3e34a4SDavid Howells {
1338c3e34a4SDavid Howells const struct rxrpc_security *sec;
134063c60d3SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
1358c3e34a4SDavid Howells
1368c3e34a4SDavid Howells _enter("");
1378c3e34a4SDavid Howells
138063c60d3SDavid Howells sec = rxrpc_security_lookup(sp->hdr.securityIndex);
1398c3e34a4SDavid Howells if (!sec) {
14057af281eSDavid Howells rxrpc_direct_abort(skb, rxrpc_abort_unsupported_security,
14157af281eSDavid Howells RX_INVALID_OPERATION, -EKEYREJECTED);
142ec832bd0SDavid Howells return NULL;
1438c3e34a4SDavid Howells }
1448c3e34a4SDavid Howells
145ec832bd0SDavid Howells if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE &&
146ec832bd0SDavid Howells !rx->securities) {
14757af281eSDavid Howells rxrpc_direct_abort(skb, rxrpc_abort_no_service_key,
14857af281eSDavid Howells sec->no_key_abort, -EKEYREJECTED);
149ec832bd0SDavid Howells return NULL;
1508c3e34a4SDavid Howells }
1518c3e34a4SDavid Howells
152ec832bd0SDavid Howells return sec;
153ec832bd0SDavid Howells }
154ec832bd0SDavid Howells
155ec832bd0SDavid Howells /*
156ec832bd0SDavid Howells * Find the security key for a server connection.
157ec832bd0SDavid Howells */
rxrpc_look_up_server_security(struct rxrpc_connection * conn,struct sk_buff * skb,u32 kvno,u32 enctype)158ec832bd0SDavid Howells struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
159ec832bd0SDavid Howells struct sk_buff *skb,
160ec832bd0SDavid Howells u32 kvno, u32 enctype)
161ec832bd0SDavid Howells {
162ec832bd0SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
163ec832bd0SDavid Howells struct rxrpc_sock *rx;
164ec832bd0SDavid Howells struct key *key = ERR_PTR(-EKEYREJECTED);
165ec832bd0SDavid Howells key_ref_t kref = NULL;
166ec832bd0SDavid Howells char kdesc[5 + 1 + 3 + 1 + 12 + 1 + 12 + 1];
167ec832bd0SDavid Howells int ret;
168ec832bd0SDavid Howells
169ec832bd0SDavid Howells _enter("");
170ec832bd0SDavid Howells
171ec832bd0SDavid Howells if (enctype)
172ec832bd0SDavid Howells sprintf(kdesc, "%u:%u:%u:%u",
173ec832bd0SDavid Howells sp->hdr.serviceId, sp->hdr.securityIndex, kvno, enctype);
174ec832bd0SDavid Howells else if (kvno)
175ec832bd0SDavid Howells sprintf(kdesc, "%u:%u:%u",
176ec832bd0SDavid Howells sp->hdr.serviceId, sp->hdr.securityIndex, kvno);
177ec832bd0SDavid Howells else
178ec832bd0SDavid Howells sprintf(kdesc, "%u:%u",
179ec832bd0SDavid Howells sp->hdr.serviceId, sp->hdr.securityIndex);
180ec832bd0SDavid Howells
181*42f229c3SDavid Howells read_lock(&conn->local->services_lock);
182ec832bd0SDavid Howells
183*42f229c3SDavid Howells rx = conn->local->service;
184ec832bd0SDavid Howells if (!rx)
185ec832bd0SDavid Howells goto out;
186ec832bd0SDavid Howells
1878c3e34a4SDavid Howells /* look through the service's keyring */
1888c3e34a4SDavid Howells kref = keyring_search(make_key_ref(rx->securities, 1UL),
189dcf49dbcSDavid Howells &key_type_rxrpc_s, kdesc, true);
1908c3e34a4SDavid Howells if (IS_ERR(kref)) {
191ec832bd0SDavid Howells key = ERR_CAST(kref);
192ec832bd0SDavid Howells goto out;
193ec832bd0SDavid Howells }
194ec832bd0SDavid Howells
195ec832bd0SDavid Howells key = key_ref_to_ptr(kref);
196ec832bd0SDavid Howells
197ec832bd0SDavid Howells ret = key_validate(key);
198ec832bd0SDavid Howells if (ret < 0) {
199ec832bd0SDavid Howells key_put(key);
200ec832bd0SDavid Howells key = ERR_PTR(ret);
201ec832bd0SDavid Howells goto out;
2028c3e34a4SDavid Howells }
2038c3e34a4SDavid Howells
204063c60d3SDavid Howells out:
205*42f229c3SDavid Howells read_unlock(&conn->local->services_lock);
206ec832bd0SDavid Howells return key;
2078c3e34a4SDavid Howells }
208