18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IMA support for appraising module-style appended signatures. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 IBM Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: 88c2ecf20Sopenharmony_ci * Thiago Jung Bauermann <bauerman@linux.ibm.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/module_signature.h> 138c2ecf20Sopenharmony_ci#include <keys/asymmetric-type.h> 148c2ecf20Sopenharmony_ci#include <crypto/pkcs7.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "ima.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct modsig { 198c2ecf20Sopenharmony_ci struct pkcs7_message *pkcs7_msg; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci enum hash_algo hash_algo; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci /* This digest will go in the 'd-modsig' field of the IMA template. */ 248c2ecf20Sopenharmony_ci const u8 *digest; 258c2ecf20Sopenharmony_ci u32 digest_size; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* 288c2ecf20Sopenharmony_ci * This is what will go to the measurement list if the template requires 298c2ecf20Sopenharmony_ci * storing the signature. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci int raw_pkcs7_len; 328c2ecf20Sopenharmony_ci u8 raw_pkcs7[]; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * ima_read_modsig - Read modsig from buf. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Return: 0 on success, error code otherwise. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ciint ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, 418c2ecf20Sopenharmony_ci struct modsig **modsig) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci const size_t marker_len = strlen(MODULE_SIG_STRING); 448c2ecf20Sopenharmony_ci const struct module_signature *sig; 458c2ecf20Sopenharmony_ci struct modsig *hdr; 468c2ecf20Sopenharmony_ci size_t sig_len; 478c2ecf20Sopenharmony_ci const void *p; 488c2ecf20Sopenharmony_ci int rc; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (buf_len <= marker_len + sizeof(*sig)) 518c2ecf20Sopenharmony_ci return -ENOENT; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci p = buf + buf_len - marker_len; 548c2ecf20Sopenharmony_ci if (memcmp(p, MODULE_SIG_STRING, marker_len)) 558c2ecf20Sopenharmony_ci return -ENOENT; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci buf_len -= marker_len; 588c2ecf20Sopenharmony_ci sig = (const struct module_signature *)(p - sizeof(*sig)); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci rc = mod_check_sig(sig, buf_len, func_tokens[func]); 618c2ecf20Sopenharmony_ci if (rc) 628c2ecf20Sopenharmony_ci return rc; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci sig_len = be32_to_cpu(sig->sig_len); 658c2ecf20Sopenharmony_ci buf_len -= sig_len + sizeof(*sig); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */ 688c2ecf20Sopenharmony_ci hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL); 698c2ecf20Sopenharmony_ci if (!hdr) 708c2ecf20Sopenharmony_ci return -ENOMEM; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len); 738c2ecf20Sopenharmony_ci if (IS_ERR(hdr->pkcs7_msg)) { 748c2ecf20Sopenharmony_ci rc = PTR_ERR(hdr->pkcs7_msg); 758c2ecf20Sopenharmony_ci kfree(hdr); 768c2ecf20Sopenharmony_ci return rc; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len); 808c2ecf20Sopenharmony_ci hdr->raw_pkcs7_len = sig_len; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* We don't know the hash algorithm yet. */ 838c2ecf20Sopenharmony_ci hdr->hash_algo = HASH_ALGO__LAST; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci *modsig = hdr; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/** 918c2ecf20Sopenharmony_ci * ima_collect_modsig - Calculate the file hash without the appended signature. 928c2ecf20Sopenharmony_ci * @modsig: parsed module signature 938c2ecf20Sopenharmony_ci * @buf: data to verify the signature on 948c2ecf20Sopenharmony_ci * @size: data size 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Since the modsig is part of the file contents, the hash used in its signature 978c2ecf20Sopenharmony_ci * isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code 988c2ecf20Sopenharmony_ci * calculates a separate one for signature verification. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_civoid ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int rc; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Provide the file contents (minus the appended sig) so that the PKCS7 1068c2ecf20Sopenharmony_ci * code can calculate the file hash. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) + 1098c2ecf20Sopenharmony_ci sizeof(struct module_signature); 1108c2ecf20Sopenharmony_ci rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size); 1118c2ecf20Sopenharmony_ci if (rc) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Ask the PKCS7 code to calculate the file hash. */ 1158c2ecf20Sopenharmony_ci rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest, 1168c2ecf20Sopenharmony_ci &modsig->digest_size, &modsig->hash_algo); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ciint ima_modsig_verify(struct key *keyring, const struct modsig *modsig) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring, 1228c2ecf20Sopenharmony_ci VERIFYING_MODULE_SIGNATURE, NULL, NULL); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciint ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo, 1268c2ecf20Sopenharmony_ci const u8 **digest, u32 *digest_size) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci *algo = modsig->hash_algo; 1298c2ecf20Sopenharmony_ci *digest = modsig->digest; 1308c2ecf20Sopenharmony_ci *digest_size = modsig->digest_size; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ciint ima_get_raw_modsig(const struct modsig *modsig, const void **data, 1368c2ecf20Sopenharmony_ci u32 *data_len) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci *data = &modsig->raw_pkcs7; 1398c2ecf20Sopenharmony_ci *data_len = modsig->raw_pkcs7_len; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_civoid ima_free_modsig(struct modsig *modsig) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci if (!modsig) 1478c2ecf20Sopenharmony_ci return; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci pkcs7_free_message(modsig->pkcs7_msg); 1508c2ecf20Sopenharmony_ci kfree(modsig); 1518c2ecf20Sopenharmony_ci} 152