ima_modsig.c (3542B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * IMA support for appraising module-style appended signatures. 4 * 5 * Copyright (C) 2019 IBM Corporation 6 * 7 * Author: 8 * Thiago Jung Bauermann <bauerman@linux.ibm.com> 9 */ 10 11#include <linux/types.h> 12#include <linux/module_signature.h> 13#include <keys/asymmetric-type.h> 14#include <crypto/pkcs7.h> 15 16#include "ima.h" 17 18struct modsig { 19 struct pkcs7_message *pkcs7_msg; 20 21 enum hash_algo hash_algo; 22 23 /* This digest will go in the 'd-modsig' field of the IMA template. */ 24 const u8 *digest; 25 u32 digest_size; 26 27 /* 28 * This is what will go to the measurement list if the template requires 29 * storing the signature. 30 */ 31 int raw_pkcs7_len; 32 u8 raw_pkcs7[]; 33}; 34 35/* 36 * ima_read_modsig - Read modsig from buf. 37 * 38 * Return: 0 on success, error code otherwise. 39 */ 40int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, 41 struct modsig **modsig) 42{ 43 const size_t marker_len = strlen(MODULE_SIG_STRING); 44 const struct module_signature *sig; 45 struct modsig *hdr; 46 size_t sig_len; 47 const void *p; 48 int rc; 49 50 if (buf_len <= marker_len + sizeof(*sig)) 51 return -ENOENT; 52 53 p = buf + buf_len - marker_len; 54 if (memcmp(p, MODULE_SIG_STRING, marker_len)) 55 return -ENOENT; 56 57 buf_len -= marker_len; 58 sig = (const struct module_signature *)(p - sizeof(*sig)); 59 60 rc = mod_check_sig(sig, buf_len, func_tokens[func]); 61 if (rc) 62 return rc; 63 64 sig_len = be32_to_cpu(sig->sig_len); 65 buf_len -= sig_len + sizeof(*sig); 66 67 /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */ 68 hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL); 69 if (!hdr) 70 return -ENOMEM; 71 72 hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len); 73 if (IS_ERR(hdr->pkcs7_msg)) { 74 rc = PTR_ERR(hdr->pkcs7_msg); 75 kfree(hdr); 76 return rc; 77 } 78 79 memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len); 80 hdr->raw_pkcs7_len = sig_len; 81 82 /* We don't know the hash algorithm yet. */ 83 hdr->hash_algo = HASH_ALGO__LAST; 84 85 *modsig = hdr; 86 87 return 0; 88} 89 90/** 91 * ima_collect_modsig - Calculate the file hash without the appended signature. 92 * 93 * Since the modsig is part of the file contents, the hash used in its signature 94 * isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code 95 * calculates a separate one for signature verification. 96 */ 97void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size) 98{ 99 int rc; 100 101 /* 102 * Provide the file contents (minus the appended sig) so that the PKCS7 103 * code can calculate the file hash. 104 */ 105 size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) + 106 sizeof(struct module_signature); 107 rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size); 108 if (rc) 109 return; 110 111 /* Ask the PKCS7 code to calculate the file hash. */ 112 rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest, 113 &modsig->digest_size, &modsig->hash_algo); 114} 115 116int ima_modsig_verify(struct key *keyring, const struct modsig *modsig) 117{ 118 return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring, 119 VERIFYING_MODULE_SIGNATURE, NULL, NULL); 120} 121 122int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo, 123 const u8 **digest, u32 *digest_size) 124{ 125 *algo = modsig->hash_algo; 126 *digest = modsig->digest; 127 *digest_size = modsig->digest_size; 128 129 return 0; 130} 131 132int ima_get_raw_modsig(const struct modsig *modsig, const void **data, 133 u32 *data_len) 134{ 135 *data = &modsig->raw_pkcs7; 136 *data_len = modsig->raw_pkcs7_len; 137 138 return 0; 139} 140 141void ima_free_modsig(struct modsig *modsig) 142{ 143 if (!modsig) 144 return; 145 146 pkcs7_free_message(modsig->pkcs7_msg); 147 kfree(modsig); 148}