auth.c (13801B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * This file is part of UBIFS. 4 * 5 * Copyright (C) 2018 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> 6 */ 7 8/* 9 * This file implements various helper functions for UBIFS authentication support 10 */ 11 12#include <linux/crypto.h> 13#include <linux/verification.h> 14#include <crypto/hash.h> 15#include <crypto/algapi.h> 16#include <keys/user-type.h> 17#include <keys/asymmetric-type.h> 18 19#include "ubifs.h" 20 21/** 22 * ubifs_node_calc_hash - calculate the hash of a UBIFS node 23 * @c: UBIFS file-system description object 24 * @node: the node to calculate a hash for 25 * @hash: the returned hash 26 * 27 * Returns 0 for success or a negative error code otherwise. 28 */ 29int __ubifs_node_calc_hash(const struct ubifs_info *c, const void *node, 30 u8 *hash) 31{ 32 const struct ubifs_ch *ch = node; 33 34 return crypto_shash_tfm_digest(c->hash_tfm, node, le32_to_cpu(ch->len), 35 hash); 36} 37 38/** 39 * ubifs_hash_calc_hmac - calculate a HMAC from a hash 40 * @c: UBIFS file-system description object 41 * @hash: the node to calculate a HMAC for 42 * @hmac: the returned HMAC 43 * 44 * Returns 0 for success or a negative error code otherwise. 45 */ 46static int ubifs_hash_calc_hmac(const struct ubifs_info *c, const u8 *hash, 47 u8 *hmac) 48{ 49 return crypto_shash_tfm_digest(c->hmac_tfm, hash, c->hash_len, hmac); 50} 51 52/** 53 * ubifs_prepare_auth_node - Prepare an authentication node 54 * @c: UBIFS file-system description object 55 * @node: the node to calculate a hash for 56 * @inhash: input hash of previous nodes 57 * 58 * This function prepares an authentication node for writing onto flash. 59 * It creates a HMAC from the given input hash and writes it to the node. 60 * 61 * Returns 0 for success or a negative error code otherwise. 62 */ 63int ubifs_prepare_auth_node(struct ubifs_info *c, void *node, 64 struct shash_desc *inhash) 65{ 66 struct ubifs_auth_node *auth = node; 67 u8 hash[UBIFS_HASH_ARR_SZ]; 68 int err; 69 70 { 71 SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm); 72 73 hash_desc->tfm = c->hash_tfm; 74 ubifs_shash_copy_state(c, inhash, hash_desc); 75 76 err = crypto_shash_final(hash_desc, hash); 77 if (err) 78 return err; 79 } 80 81 err = ubifs_hash_calc_hmac(c, hash, auth->hmac); 82 if (err) 83 return err; 84 85 auth->ch.node_type = UBIFS_AUTH_NODE; 86 ubifs_prepare_node(c, auth, ubifs_auth_node_sz(c), 0); 87 return 0; 88} 89 90static struct shash_desc *ubifs_get_desc(const struct ubifs_info *c, 91 struct crypto_shash *tfm) 92{ 93 struct shash_desc *desc; 94 int err; 95 96 if (!ubifs_authenticated(c)) 97 return NULL; 98 99 desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL); 100 if (!desc) 101 return ERR_PTR(-ENOMEM); 102 103 desc->tfm = tfm; 104 105 err = crypto_shash_init(desc); 106 if (err) { 107 kfree(desc); 108 return ERR_PTR(err); 109 } 110 111 return desc; 112} 113 114/** 115 * __ubifs_hash_get_desc - get a descriptor suitable for hashing a node 116 * @c: UBIFS file-system description object 117 * 118 * This function returns a descriptor suitable for hashing a node. Free after use 119 * with kfree. 120 */ 121struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c) 122{ 123 return ubifs_get_desc(c, c->hash_tfm); 124} 125 126/** 127 * ubifs_bad_hash - Report hash mismatches 128 * @c: UBIFS file-system description object 129 * @node: the node 130 * @hash: the expected hash 131 * @lnum: the LEB @node was read from 132 * @offs: offset in LEB @node was read from 133 * 134 * This function reports a hash mismatch when a node has a different hash than 135 * expected. 136 */ 137void ubifs_bad_hash(const struct ubifs_info *c, const void *node, const u8 *hash, 138 int lnum, int offs) 139{ 140 int len = min(c->hash_len, 20); 141 int cropped = len != c->hash_len; 142 const char *cont = cropped ? "..." : ""; 143 144 u8 calc[UBIFS_HASH_ARR_SZ]; 145 146 __ubifs_node_calc_hash(c, node, calc); 147 148 ubifs_err(c, "hash mismatch on node at LEB %d:%d", lnum, offs); 149 ubifs_err(c, "hash expected: %*ph%s", len, hash, cont); 150 ubifs_err(c, "hash calculated: %*ph%s", len, calc, cont); 151} 152 153/** 154 * __ubifs_node_check_hash - check the hash of a node against given hash 155 * @c: UBIFS file-system description object 156 * @node: the node 157 * @expected: the expected hash 158 * 159 * This function calculates a hash over a node and compares it to the given hash. 160 * Returns 0 if both hashes are equal or authentication is disabled, otherwise a 161 * negative error code is returned. 162 */ 163int __ubifs_node_check_hash(const struct ubifs_info *c, const void *node, 164 const u8 *expected) 165{ 166 u8 calc[UBIFS_HASH_ARR_SZ]; 167 int err; 168 169 err = __ubifs_node_calc_hash(c, node, calc); 170 if (err) 171 return err; 172 173 if (ubifs_check_hash(c, expected, calc)) 174 return -EPERM; 175 176 return 0; 177} 178 179/** 180 * ubifs_sb_verify_signature - verify the signature of a superblock 181 * @c: UBIFS file-system description object 182 * @sup: The superblock node 183 * 184 * To support offline signed images the superblock can be signed with a 185 * PKCS#7 signature. The signature is placed directly behind the superblock 186 * node in an ubifs_sig_node. 187 * 188 * Returns 0 when the signature can be successfully verified or a negative 189 * error code if not. 190 */ 191int ubifs_sb_verify_signature(struct ubifs_info *c, 192 const struct ubifs_sb_node *sup) 193{ 194 int err; 195 struct ubifs_scan_leb *sleb; 196 struct ubifs_scan_node *snod; 197 const struct ubifs_sig_node *signode; 198 199 sleb = ubifs_scan(c, UBIFS_SB_LNUM, UBIFS_SB_NODE_SZ, c->sbuf, 0); 200 if (IS_ERR(sleb)) { 201 err = PTR_ERR(sleb); 202 return err; 203 } 204 205 if (sleb->nodes_cnt == 0) { 206 ubifs_err(c, "Unable to find signature node"); 207 err = -EINVAL; 208 goto out_destroy; 209 } 210 211 snod = list_first_entry(&sleb->nodes, struct ubifs_scan_node, list); 212 213 if (snod->type != UBIFS_SIG_NODE) { 214 ubifs_err(c, "Signature node is of wrong type"); 215 err = -EINVAL; 216 goto out_destroy; 217 } 218 219 signode = snod->node; 220 221 if (le32_to_cpu(signode->len) > snod->len + sizeof(struct ubifs_sig_node)) { 222 ubifs_err(c, "invalid signature len %d", le32_to_cpu(signode->len)); 223 err = -EINVAL; 224 goto out_destroy; 225 } 226 227 if (le32_to_cpu(signode->type) != UBIFS_SIGNATURE_TYPE_PKCS7) { 228 ubifs_err(c, "Signature type %d is not supported\n", 229 le32_to_cpu(signode->type)); 230 err = -EINVAL; 231 goto out_destroy; 232 } 233 234 err = verify_pkcs7_signature(sup, sizeof(struct ubifs_sb_node), 235 signode->sig, le32_to_cpu(signode->len), 236 NULL, VERIFYING_UNSPECIFIED_SIGNATURE, 237 NULL, NULL); 238 239 if (err) 240 ubifs_err(c, "Failed to verify signature"); 241 else 242 ubifs_msg(c, "Successfully verified super block signature"); 243 244out_destroy: 245 ubifs_scan_destroy(sleb); 246 247 return err; 248} 249 250/** 251 * ubifs_init_authentication - initialize UBIFS authentication support 252 * @c: UBIFS file-system description object 253 * 254 * This function returns 0 for success or a negative error code otherwise. 255 */ 256int ubifs_init_authentication(struct ubifs_info *c) 257{ 258 struct key *keyring_key; 259 const struct user_key_payload *ukp; 260 int err; 261 char hmac_name[CRYPTO_MAX_ALG_NAME]; 262 263 if (!c->auth_hash_name) { 264 ubifs_err(c, "authentication hash name needed with authentication"); 265 return -EINVAL; 266 } 267 268 c->auth_hash_algo = match_string(hash_algo_name, HASH_ALGO__LAST, 269 c->auth_hash_name); 270 if ((int)c->auth_hash_algo < 0) { 271 ubifs_err(c, "Unknown hash algo %s specified", 272 c->auth_hash_name); 273 return -EINVAL; 274 } 275 276 snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", 277 c->auth_hash_name); 278 279 keyring_key = request_key(&key_type_logon, c->auth_key_name, NULL); 280 281 if (IS_ERR(keyring_key)) { 282 ubifs_err(c, "Failed to request key: %ld", 283 PTR_ERR(keyring_key)); 284 return PTR_ERR(keyring_key); 285 } 286 287 down_read(&keyring_key->sem); 288 289 if (keyring_key->type != &key_type_logon) { 290 ubifs_err(c, "key type must be logon"); 291 err = -ENOKEY; 292 goto out; 293 } 294 295 ukp = user_key_payload_locked(keyring_key); 296 if (!ukp) { 297 /* key was revoked before we acquired its semaphore */ 298 err = -EKEYREVOKED; 299 goto out; 300 } 301 302 c->hash_tfm = crypto_alloc_shash(c->auth_hash_name, 0, 0); 303 if (IS_ERR(c->hash_tfm)) { 304 err = PTR_ERR(c->hash_tfm); 305 ubifs_err(c, "Can not allocate %s: %d", 306 c->auth_hash_name, err); 307 goto out; 308 } 309 310 c->hash_len = crypto_shash_digestsize(c->hash_tfm); 311 if (c->hash_len > UBIFS_HASH_ARR_SZ) { 312 ubifs_err(c, "hash %s is bigger than maximum allowed hash size (%d > %d)", 313 c->auth_hash_name, c->hash_len, UBIFS_HASH_ARR_SZ); 314 err = -EINVAL; 315 goto out_free_hash; 316 } 317 318 c->hmac_tfm = crypto_alloc_shash(hmac_name, 0, 0); 319 if (IS_ERR(c->hmac_tfm)) { 320 err = PTR_ERR(c->hmac_tfm); 321 ubifs_err(c, "Can not allocate %s: %d", hmac_name, err); 322 goto out_free_hash; 323 } 324 325 c->hmac_desc_len = crypto_shash_digestsize(c->hmac_tfm); 326 if (c->hmac_desc_len > UBIFS_HMAC_ARR_SZ) { 327 ubifs_err(c, "hmac %s is bigger than maximum allowed hmac size (%d > %d)", 328 hmac_name, c->hmac_desc_len, UBIFS_HMAC_ARR_SZ); 329 err = -EINVAL; 330 goto out_free_hmac; 331 } 332 333 err = crypto_shash_setkey(c->hmac_tfm, ukp->data, ukp->datalen); 334 if (err) 335 goto out_free_hmac; 336 337 c->authenticated = true; 338 339 c->log_hash = ubifs_hash_get_desc(c); 340 if (IS_ERR(c->log_hash)) { 341 err = PTR_ERR(c->log_hash); 342 goto out_free_hmac; 343 } 344 345 err = 0; 346 347out_free_hmac: 348 if (err) 349 crypto_free_shash(c->hmac_tfm); 350out_free_hash: 351 if (err) 352 crypto_free_shash(c->hash_tfm); 353out: 354 up_read(&keyring_key->sem); 355 key_put(keyring_key); 356 357 return err; 358} 359 360/** 361 * __ubifs_exit_authentication - release resource 362 * @c: UBIFS file-system description object 363 * 364 * This function releases the authentication related resources. 365 */ 366void __ubifs_exit_authentication(struct ubifs_info *c) 367{ 368 if (!ubifs_authenticated(c)) 369 return; 370 371 crypto_free_shash(c->hmac_tfm); 372 crypto_free_shash(c->hash_tfm); 373 kfree(c->log_hash); 374} 375 376/** 377 * ubifs_node_calc_hmac - calculate the HMAC of a UBIFS node 378 * @c: UBIFS file-system description object 379 * @node: the node to insert a HMAC into. 380 * @len: the length of the node 381 * @ofs_hmac: the offset in the node where the HMAC is inserted 382 * @hmac: returned HMAC 383 * 384 * This function calculates a HMAC of a UBIFS node. The HMAC is expected to be 385 * embedded into the node, so this area is not covered by the HMAC. Also not 386 * covered is the UBIFS_NODE_MAGIC and the CRC of the node. 387 */ 388static int ubifs_node_calc_hmac(const struct ubifs_info *c, const void *node, 389 int len, int ofs_hmac, void *hmac) 390{ 391 SHASH_DESC_ON_STACK(shash, c->hmac_tfm); 392 int hmac_len = c->hmac_desc_len; 393 int err; 394 395 ubifs_assert(c, ofs_hmac > 8); 396 ubifs_assert(c, ofs_hmac + hmac_len < len); 397 398 shash->tfm = c->hmac_tfm; 399 400 err = crypto_shash_init(shash); 401 if (err) 402 return err; 403 404 /* behind common node header CRC up to HMAC begin */ 405 err = crypto_shash_update(shash, node + 8, ofs_hmac - 8); 406 if (err < 0) 407 return err; 408 409 /* behind HMAC, if any */ 410 if (len - ofs_hmac - hmac_len > 0) { 411 err = crypto_shash_update(shash, node + ofs_hmac + hmac_len, 412 len - ofs_hmac - hmac_len); 413 if (err < 0) 414 return err; 415 } 416 417 return crypto_shash_final(shash, hmac); 418} 419 420/** 421 * __ubifs_node_insert_hmac - insert a HMAC into a UBIFS node 422 * @c: UBIFS file-system description object 423 * @node: the node to insert a HMAC into. 424 * @len: the length of the node 425 * @ofs_hmac: the offset in the node where the HMAC is inserted 426 * 427 * This function inserts a HMAC at offset @ofs_hmac into the node given in 428 * @node. 429 * 430 * This function returns 0 for success or a negative error code otherwise. 431 */ 432int __ubifs_node_insert_hmac(const struct ubifs_info *c, void *node, int len, 433 int ofs_hmac) 434{ 435 return ubifs_node_calc_hmac(c, node, len, ofs_hmac, node + ofs_hmac); 436} 437 438/** 439 * __ubifs_node_verify_hmac - verify the HMAC of UBIFS node 440 * @c: UBIFS file-system description object 441 * @node: the node to insert a HMAC into. 442 * @len: the length of the node 443 * @ofs_hmac: the offset in the node where the HMAC is inserted 444 * 445 * This function verifies the HMAC at offset @ofs_hmac of the node given in 446 * @node. Returns 0 if successful or a negative error code otherwise. 447 */ 448int __ubifs_node_verify_hmac(const struct ubifs_info *c, const void *node, 449 int len, int ofs_hmac) 450{ 451 int hmac_len = c->hmac_desc_len; 452 u8 *hmac; 453 int err; 454 455 hmac = kmalloc(hmac_len, GFP_NOFS); 456 if (!hmac) 457 return -ENOMEM; 458 459 err = ubifs_node_calc_hmac(c, node, len, ofs_hmac, hmac); 460 if (err) { 461 kfree(hmac); 462 return err; 463 } 464 465 err = crypto_memneq(hmac, node + ofs_hmac, hmac_len); 466 467 kfree(hmac); 468 469 if (!err) 470 return 0; 471 472 return -EPERM; 473} 474 475int __ubifs_shash_copy_state(const struct ubifs_info *c, struct shash_desc *src, 476 struct shash_desc *target) 477{ 478 u8 *state; 479 int err; 480 481 state = kmalloc(crypto_shash_descsize(src->tfm), GFP_NOFS); 482 if (!state) 483 return -ENOMEM; 484 485 err = crypto_shash_export(src, state); 486 if (err) 487 goto out; 488 489 err = crypto_shash_import(target, state); 490 491out: 492 kfree(state); 493 494 return err; 495} 496 497/** 498 * ubifs_hmac_wkm - Create a HMAC of the well known message 499 * @c: UBIFS file-system description object 500 * @hmac: The HMAC of the well known message 501 * 502 * This function creates a HMAC of a well known message. This is used 503 * to check if the provided key is suitable to authenticate a UBIFS 504 * image. This is only a convenience to the user to provide a better 505 * error message when the wrong key is provided. 506 * 507 * This function returns 0 for success or a negative error code otherwise. 508 */ 509int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac) 510{ 511 SHASH_DESC_ON_STACK(shash, c->hmac_tfm); 512 int err; 513 const char well_known_message[] = "UBIFS"; 514 515 if (!ubifs_authenticated(c)) 516 return 0; 517 518 shash->tfm = c->hmac_tfm; 519 520 err = crypto_shash_init(shash); 521 if (err) 522 return err; 523 524 err = crypto_shash_update(shash, well_known_message, 525 sizeof(well_known_message) - 1); 526 if (err < 0) 527 return err; 528 529 err = crypto_shash_final(shash, hmac); 530 if (err) 531 return err; 532 return 0; 533} 534 535/* 536 * ubifs_hmac_zero - test if a HMAC is zero 537 * @c: UBIFS file-system description object 538 * @hmac: the HMAC to test 539 * 540 * This function tests if a HMAC is zero and returns true if it is 541 * and false otherwise. 542 */ 543bool ubifs_hmac_zero(struct ubifs_info *c, const u8 *hmac) 544{ 545 return !memchr_inv(hmac, 0, c->hmac_desc_len); 546}