1/*
2 **************************************************************************
3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
16
17/*
18 * @file nss_nlcrypto.c
19 *	NSS Netlink Crypto Handler
20 */
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/types.h>
25#include <linux/version.h>
26
27#include <nss_crypto_if.h>
28#include <linux/netlink.h>
29#include <linux/version.h>
30#include <net/genetlink.h>
31
32#include <nss_api_if.h>
33#include <nss_cmn.h>
34#include <nss_nl_if.h>
35#include "nss_nlcmn_if.h"
36#include "nss_crypto_if.h"
37#include "nss_nlcrypto_if.h"
38#include "nss_nl.h"
39
40/*
41 * @brief prototypes
42 */
43static int nss_nlcrypto_op_session_create(struct sk_buff *skb_msg, struct genl_info *info);
44static int nss_nlcrypto_op_session_update(struct sk_buff *skb_msg, struct genl_info *info);
45static int nss_nlcrypto_op_session_destroy(struct sk_buff *skb_msg, struct genl_info *info);
46static int nss_nlcrypto_op_session_info(struct sk_buff *skb_msg, struct genl_info *info);
47
48/*
49 * NSS NETLINK crypto context
50 */
51struct nss_nlcrypto_ctx {
52	nss_crypto_handle_t crypto_hdl;
53};
54
55/*
56 * @brief  Crypto family definition
57 */
58static struct genl_family nss_nlcrypto_family = {
59	.id = GENL_ID_GENERATE,				/* Auto generate ID */
60	.name = NSS_NLCRYPTO_FAMILY,			/* family name string */
61	.hdrsize = sizeof(struct nss_nlcrypto_rule),	/* NSS NETLINK Crypto rule */
62	.version = NSS_NL_VER,				/* Set it to NSS_NLIPv4 version */
63	.maxattr = NSS_NLCRYPTO_CMD_MAX,		/* maximum commands supported */
64	.netnsok = true,
65	.pre_doit = NULL,
66	.post_doit = NULL,
67};
68
69/*
70 *  @brief operation table called by the generic netlink layer based on the command
71 */
72static struct genl_ops nss_nlcrypto_ops[] = {
73	{.cmd = NSS_NLCRYPTO_CMD_CREATE_SESSION, .doit = nss_nlcrypto_op_session_create,},	/* rule create */
74	{.cmd = NSS_NLCRYPTO_CMD_UPDATE_SESSION, .doit = nss_nlcrypto_op_session_update,},	/* rule destroy */
75	{.cmd = NSS_NLCRYPTO_CMD_DESTROY_SESSION, .doit = nss_nlcrypto_op_session_destroy,},	/* rule destroy */
76	{.cmd = NSS_NLCRYPTO_CMD_INFO_SESSION, .doit = nss_nlcrypto_op_session_info,},	/* rule destroy */
77};
78
79
80#define NSS_NLCRYPTO_OPS_SZ ARRAY_SIZE(nss_nlcrypto_ops)
81
82
83/*
84 * global context
85 */
86static struct nss_nlcrypto_ctx gbl_ctx;
87
88/*
89 * @brief nss_nlcrypto_validate_cipher()
90 * 	validate the cipher parameters
91 */
92static inline bool nss_nlcrypto_validate_cipher(struct nss_crypto_key *cipher)
93{
94	enum nss_crypto_cipher algo = cipher->algo;
95	uint16_t key_len = cipher->key_len;
96	uint16_t max_key_len = 0;
97
98	switch (algo) {
99		case NSS_CRYPTO_CIPHER_AES:
100			max_key_len = NSS_CRYPTO_MAX_KEYLEN_AES;
101			break;
102
103		case NSS_CRYPTO_CIPHER_DES:
104			max_key_len =  NSS_CRYPTO_MAX_KEYLEN_DES;
105			break;
106
107		case NSS_CRYPTO_CIPHER_NULL:
108			max_key_len = 0;
109			break;
110
111		default:
112			return false;
113	}
114
115	/*
116	 * Key length shouldn't be more than max key length
117	 */
118	return !(key_len > max_key_len);
119}
120
121/*
122 * @brief nss_nlcrypto_validate_auth()
123 * 	validate the auth parameters
124 */
125static inline bool nss_nlcrypto_validate_auth(struct nss_crypto_key *auth)
126{
127	enum nss_crypto_auth algo = auth->algo;
128	uint16_t key_len = auth->key_len;
129	uint16_t max_key_len = 0;
130
131	switch (algo) {
132		case NSS_CRYPTO_AUTH_SHA1_HMAC:
133			max_key_len = NSS_CRYPTO_MAX_KEYLEN_SHA1;
134			break;
135
136		case NSS_CRYPTO_AUTH_SHA256_HMAC:
137			max_key_len =  NSS_CRYPTO_MAX_KEYLEN_SHA256;
138			break;
139
140		case NSS_CRYPTO_AUTH_NULL:
141			max_key_len = 0;
142			break;
143
144		default:
145			return false;
146
147	}
148
149	/*
150	 * Key length shouldn't be more than max key length
151	 */
152	return !(key_len > max_key_len);
153
154}
155
156/*
157 * @brief nss_nlcrypto_validate_param()
158 * 	validate the  parameters
159 */
160static inline bool nss_nlcrypto_validate_param(struct nss_crypto_params *param)
161{
162	/* check the skip lengths */
163	if (param->auth_skip > param->cipher_skip) {
164		return false;
165	}
166
167	switch (param->req_type) {
168	/* pure encryption */
169	case NSS_CRYPTO_REQ_TYPE_ENCRYPT:
170		return true;
171	/* pure decryption */
172	case NSS_CRYPTO_REQ_TYPE_DECRYPT:
173		return true;
174	/* encryption and authentication */
175	case (NSS_CRYPTO_REQ_TYPE_ENCRYPT | NSS_CRYPTO_REQ_TYPE_AUTH):
176		return true;
177	/* decryption and authentication */
178	case (NSS_CRYPTO_REQ_TYPE_DECRYPT | NSS_CRYPTO_REQ_TYPE_AUTH):
179		return true;
180	/* otherwise */
181	default:
182		return false;
183
184	}
185
186	return false;
187}
188
189/*
190 * @brief nss_nlcrypto_compose_info()
191 * 	Compose the info message
192 */
193static inline void nss_crypto_copy_info(struct nss_nlcrypto_info_session *reply, uint32_t session_idx)
194{
195	reply->session_idx = session_idx;
196	reply->cipher.algo = nss_crypto_get_cipher(session_idx);
197	reply->auth.algo = nss_crypto_get_auth(session_idx);
198}
199
200/*
201 * @brief nss_nlcrypto_op_session_create()
202 * 	session add handler
203 */
204static int nss_nlcrypto_op_session_create(struct sk_buff *skb, struct genl_info *info)
205{
206	struct nss_nlcrypto_create_session *create_msg;
207	struct nss_nlcrypto_info_session *reply;
208	struct nss_crypto_key *cipher = NULL;
209	struct nss_crypto_key *auth = NULL;
210	struct nss_nlcrypto_rule *nl_rule;
211	nss_crypto_status_t status;
212	struct nss_nlcmn *nl_cm;
213	int32_t session_idx = -1;
214	struct sk_buff *resp;
215	uint32_t pid;
216
217	/*
218	 * extract the message payload
219	 */
220	nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_CREATE_SESSION);
221	if (!nl_cm) {
222		nss_nl_error("unable to extract rule create data\n");
223		return -EINVAL;
224	}
225
226	/*
227	 * Message validation required before accepting the configuration
228	 */
229	nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
230
231	pid = nl_cm->pid;
232	create_msg = &nl_rule->msg.create;
233
234	cipher = &create_msg->cipher;
235	auth   = &create_msg->auth;
236
237	/* validate if cipher specific parameters are correct */
238	if (nss_nlcrypto_validate_cipher(cipher) == false) {
239		nss_nl_error("cipher validation failed: algo(%d), key_len(%d)\n",
240				 cipher->algo, cipher->key_len);
241		return -EINVAL;
242	}
243
244	/* validate if auth specific parameters are correct */
245	if (nss_nlcrypto_validate_auth(auth) == false) {
246		nss_nl_error("auth validation failed:  algo(%d), key_len(%d)\n",
247				auth->algo,
248				auth->key_len);
249		return -EINVAL;
250	}
251
252	/*
253	 * Link the key pointer in crypto driver structure to the array
254	 */
255	cipher->key = create_msg->cipher_key;
256	auth->key   = create_msg->auth_key;
257
258	status = nss_crypto_session_alloc(gbl_ctx.crypto_hdl, cipher, auth, &session_idx);
259	if (status != NSS_CRYPTO_STATUS_OK) {
260		nss_nl_error("%d:session alloc failed\n", pid);
261		return -EINVAL;
262	}
263
264	/*
265	 * copy the NL message for response
266	 */
267	resp = nss_nl_copy_msg(skb);
268	if (!resp) {
269		nss_nl_error("%d:unable to save response data from NL buffer\n", pid);
270		return -ENOMEM;
271	}
272
273	/*
274	 * overload the nl_rule with the new response address
275	 */
276	nl_rule = nss_nl_get_data(resp);
277	nss_nlcrypto_rule_init(nl_rule, NSS_NLCRYPTO_CMD_INFO_SESSION);
278
279	/*
280	 * Fill up the info message
281	 */
282	reply = &nl_rule->msg.info;
283	memset(reply, 0, sizeof(struct nss_nlcrypto_info_session));
284
285	/*
286	 * copy the info message
287	 */
288	nss_crypto_copy_info(reply, session_idx);
289
290	/*
291	 * unicast the response to user
292	 */
293	nss_nl_ucast_resp(resp);
294
295	return 0;
296}
297
298/*
299 * @brief nss_nlcrypto_op_session_update()
300 * 	session update handler
301 */
302static int nss_nlcrypto_op_session_update(struct sk_buff *skb_msg, struct genl_info *info)
303{
304	struct nss_nlcrypto_rule *nl_rule;
305	struct nss_crypto_params *param;
306	struct nss_nlcmn *nl_cm;
307	uint32_t session_idx;
308	uint32_t pid;
309
310
311	/*
312	 * extract the message payload
313	 */
314	nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_UPDATE_SESSION);
315	if (!nl_cm) {
316		nss_nl_error("unable to extract rule create data\n");
317		return -EINVAL;
318	}
319
320	/*
321	 * Message validation required before accepting the configuration
322	 */
323	nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
324	pid = nl_cm->pid;
325
326	session_idx = nl_rule->msg.update.session_idx;
327
328	param = &nl_rule->msg.update.param;
329	if (nss_nlcrypto_validate_param(param) == false) {
330		nss_nl_error("param validation failed:  req_type(%d), auth_skip(%d), cipher_skip(%d)\n",
331				param->req_type,param->auth_skip, param->cipher_skip);
332		return -EINVAL;
333	}
334
335	return nss_crypto_session_update(gbl_ctx.crypto_hdl, session_idx, param);
336}
337
338/*
339 * @brief nss_nlcrypto_op_session_destroy()
340 * 	delete an existing session
341 *
342 */
343static int nss_nlcrypto_op_session_destroy(struct sk_buff *skb_msg, struct genl_info *info)
344{
345	struct nss_nlcrypto_destroy_session *destroy;
346	struct nss_nlcrypto_rule *nl_rule;
347	nss_crypto_status_t status;
348	struct nss_nlcmn *nl_cm;
349	uint32_t pid;
350
351	/*
352	 * extract the message payload
353	 */
354	nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_DESTROY_SESSION);
355	if (!nl_cm) {
356		nss_nl_error("unable to extract rule create data\n");
357		return -EINVAL;
358	}
359
360	/*
361	 * Message validation required before accepting the configuration
362	 */
363	nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
364	pid = nl_cm->pid;
365
366	destroy = &nl_rule->msg.destroy;
367
368	if (nss_crypto_get_cipher(destroy->session_idx) == NSS_CRYPTO_CIPHER_NONE) {
369		nss_nl_error("invalid session index, cipher unknown:%d\n", destroy->session_idx);
370		return -EINVAL;
371	}
372
373	if (nss_crypto_get_auth(destroy->session_idx) == NSS_CRYPTO_AUTH_NONE) {
374		nss_nl_error("invalid session index, auth unknown:%d\n", destroy->session_idx);
375		return -EINVAL;
376	}
377
378	status = nss_crypto_session_free(gbl_ctx.crypto_hdl, destroy->session_idx);
379	if (status != NSS_CRYPTO_STATUS_OK) {
380		nss_nl_error("unable to delete the session:%d\n", destroy->session_idx);
381		return -EINVAL;
382	}
383
384	return 0;
385}
386
387/*
388 * @brief nss_nlcrypto_op_session_info()
389 * 	get session information
390 */
391static int nss_nlcrypto_op_session_info(struct sk_buff *skb, struct genl_info *info)
392{
393	struct nss_nlcrypto_info_session *reply;
394	struct nss_nlcrypto_rule *nl_rule;
395	struct nss_nlcmn *nl_cm;
396	uint32_t session_idx;
397	struct sk_buff *resp;
398	uint32_t pid;
399
400	/*
401	 * extract the message payload
402	 */
403	nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_INFO_SESSION);
404	if (!nl_cm) {
405		nss_nl_error("unable to extract rule info data\n");
406		return -EINVAL;
407	}
408
409	/*
410	 * Message validation required before accepting the configuration
411	 */
412	nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
413	pid = nl_cm->pid;
414
415	/*
416	 * since we need to populate the same information in the session_info
417	 * we will reuse the op for response
418	 */
419	session_idx  = nl_rule->msg.info.session_idx;
420
421	/*
422	 * copy the NL message for response
423	 */
424	resp = nss_nl_copy_msg(skb);
425	if (!resp) {
426		nss_nl_error("%d:unable to save response data from NL buffer\n", pid);
427		return -ENOMEM;
428	}
429
430	/*
431	 * overload the nl_rule with the new response address
432	 */
433	nl_rule = nss_nl_get_data(resp);
434
435	/*
436	 * Fill up the info message
437	 */
438	reply = &nl_rule->msg.info;
439	memset(reply, 0, sizeof(struct nss_nlcrypto_info_session));
440
441	/*
442	 * copy the info message
443	 */
444	nss_crypto_copy_info(reply, session_idx);
445
446	/*
447	 * unicast the response to user
448	 */
449	nss_nl_ucast_resp(resp);
450	return 0;
451}
452/*
453 * @brief nss_nlcrypto_attach()
454 * 	crypto user attach
455 */
456nss_crypto_user_ctx_t nss_nlcrypto_attach(nss_crypto_handle_t crypto)
457{
458	gbl_ctx.crypto_hdl = crypto;
459
460	return (nss_crypto_user_ctx_t)&nss_nlcrypto_family;
461}
462
463/*
464 * @brief nss_nlcrypto_detach()
465 * 	crypto user detach; triggered by unregister
466 */
467void nss_nlcrypto_detach(nss_crypto_user_ctx_t ctx)
468{
469	gbl_ctx.crypto_hdl = NULL;
470}
471
472/*
473 * @brief nss_nlcrypto_init()
474 * 	handler init
475 */
476bool nss_nlcrypto_init(void)
477{
478	int status;
479
480	nss_nl_info_always("initiallizing the NSS netlink crypto handler\n");
481
482	/*
483	 * register with the family
484	 */
485	status = genl_register_family_with_ops(&nss_nlcrypto_family, nss_nlcrypto_ops, NSS_NLCRYPTO_OPS_SZ);
486	if (!status) {
487		return false;
488	}
489
490	nss_crypto_register_user(nss_nlcrypto_attach, nss_nlcrypto_detach, NSS_NLCRYPTO_FAMILY);
491
492	return true;
493}
494
495/*
496 * @brief nss_nlcrypto_exit()
497 * 	handler exit
498 */
499bool nss_nlcrypto_exit(void)
500{
501	int status;
502
503	nss_nl_info_always("Uninitializing the NSS netlink crypto handler\n");
504
505	/*
506	 * unregister with the family
507	 */
508	status = genl_unregister_family(&nss_nlcrypto_family);
509	if (status != 0) {
510		return false;
511	}
512
513	nss_crypto_unregister_user(gbl_ctx.crypto_hdl);
514
515	return true;
516}
517