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