xref: /openbmc/linux/net/rxrpc/security.c (revision e3b9f1e8)
1 /* RxRPC security handling
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/module.h>
13 #include <linux/net.h>
14 #include <linux/skbuff.h>
15 #include <linux/udp.h>
16 #include <linux/crypto.h>
17 #include <net/sock.h>
18 #include <net/af_rxrpc.h>
19 #include <keys/rxrpc-type.h>
20 #include "ar-internal.h"
21 
22 static LIST_HEAD(rxrpc_security_methods);
23 static DECLARE_RWSEM(rxrpc_security_sem);
24 
25 static const struct rxrpc_security *rxrpc_security_types[] = {
26 	[RXRPC_SECURITY_NONE]	= &rxrpc_no_security,
27 #ifdef CONFIG_RXKAD
28 	[RXRPC_SECURITY_RXKAD]	= &rxkad,
29 #endif
30 };
31 
32 int __init rxrpc_init_security(void)
33 {
34 	int i, ret;
35 
36 	for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++) {
37 		if (rxrpc_security_types[i]) {
38 			ret = rxrpc_security_types[i]->init();
39 			if (ret < 0)
40 				goto failed;
41 		}
42 	}
43 
44 	return 0;
45 
46 failed:
47 	for (i--; i >= 0; i--)
48 		if (rxrpc_security_types[i])
49 			rxrpc_security_types[i]->exit();
50 	return ret;
51 }
52 
53 void rxrpc_exit_security(void)
54 {
55 	int i;
56 
57 	for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++)
58 		if (rxrpc_security_types[i])
59 			rxrpc_security_types[i]->exit();
60 }
61 
62 /*
63  * look up an rxrpc security module
64  */
65 static const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
66 {
67 	if (security_index >= ARRAY_SIZE(rxrpc_security_types))
68 		return NULL;
69 	return rxrpc_security_types[security_index];
70 }
71 
72 /*
73  * initialise the security on a client connection
74  */
75 int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
76 {
77 	const struct rxrpc_security *sec;
78 	struct rxrpc_key_token *token;
79 	struct key *key = conn->params.key;
80 	int ret;
81 
82 	_enter("{%d},{%x}", conn->debug_id, key_serial(key));
83 
84 	if (!key)
85 		return 0;
86 
87 	ret = key_validate(key);
88 	if (ret < 0)
89 		return ret;
90 
91 	token = key->payload.data[0];
92 	if (!token)
93 		return -EKEYREJECTED;
94 
95 	sec = rxrpc_security_lookup(token->security_index);
96 	if (!sec)
97 		return -EKEYREJECTED;
98 	conn->security = sec;
99 
100 	ret = conn->security->init_connection_security(conn);
101 	if (ret < 0) {
102 		conn->security = &rxrpc_no_security;
103 		return ret;
104 	}
105 
106 	_leave(" = 0");
107 	return 0;
108 }
109 
110 /*
111  * initialise the security on a server connection
112  */
113 int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
114 {
115 	const struct rxrpc_security *sec;
116 	struct rxrpc_local *local = conn->params.local;
117 	struct rxrpc_sock *rx;
118 	struct key *key;
119 	key_ref_t kref;
120 	char kdesc[5 + 1 + 3 + 1];
121 
122 	_enter("");
123 
124 	sprintf(kdesc, "%u:%u", conn->service_id, conn->security_ix);
125 
126 	sec = rxrpc_security_lookup(conn->security_ix);
127 	if (!sec) {
128 		_leave(" = -ENOKEY [lookup]");
129 		return -ENOKEY;
130 	}
131 
132 	/* find the service */
133 	read_lock(&local->services_lock);
134 	rx = rcu_dereference_protected(local->service,
135 				       lockdep_is_held(&local->services_lock));
136 	if (rx && (rx->srx.srx_service == conn->service_id ||
137 		   rx->second_service == conn->service_id))
138 		goto found_service;
139 
140 	/* the service appears to have died */
141 	read_unlock(&local->services_lock);
142 	_leave(" = -ENOENT");
143 	return -ENOENT;
144 
145 found_service:
146 	if (!rx->securities) {
147 		read_unlock(&local->services_lock);
148 		_leave(" = -ENOKEY");
149 		return -ENOKEY;
150 	}
151 
152 	/* look through the service's keyring */
153 	kref = keyring_search(make_key_ref(rx->securities, 1UL),
154 			      &key_type_rxrpc_s, kdesc);
155 	if (IS_ERR(kref)) {
156 		read_unlock(&local->services_lock);
157 		_leave(" = %ld [search]", PTR_ERR(kref));
158 		return PTR_ERR(kref);
159 	}
160 
161 	key = key_ref_to_ptr(kref);
162 	read_unlock(&local->services_lock);
163 
164 	conn->server_key = key;
165 	conn->security = sec;
166 
167 	_leave(" = 0");
168 	return 0;
169 }
170