forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.5 KiB
148 lines
3.5 KiB
// SPDX-License-Identifier: GPL-2.0+ |
|
/* |
|
* IMA support for appraising module-style appended signatures. |
|
* |
|
* Copyright (C) 2019 IBM Corporation |
|
* |
|
* Author: |
|
* Thiago Jung Bauermann <[email protected]> |
|
*/ |
|
|
|
#include <linux/types.h> |
|
#include <linux/module_signature.h> |
|
#include <keys/asymmetric-type.h> |
|
#include <crypto/pkcs7.h> |
|
|
|
#include "ima.h" |
|
|
|
struct modsig { |
|
struct pkcs7_message *pkcs7_msg; |
|
|
|
enum hash_algo hash_algo; |
|
|
|
/* This digest will go in the 'd-modsig' field of the IMA template. */ |
|
const u8 *digest; |
|
u32 digest_size; |
|
|
|
/* |
|
* This is what will go to the measurement list if the template requires |
|
* storing the signature. |
|
*/ |
|
int raw_pkcs7_len; |
|
u8 raw_pkcs7[]; |
|
}; |
|
|
|
/* |
|
* ima_read_modsig - Read modsig from buf. |
|
* |
|
* Return: 0 on success, error code otherwise. |
|
*/ |
|
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, |
|
struct modsig **modsig) |
|
{ |
|
const size_t marker_len = strlen(MODULE_SIG_STRING); |
|
const struct module_signature *sig; |
|
struct modsig *hdr; |
|
size_t sig_len; |
|
const void *p; |
|
int rc; |
|
|
|
if (buf_len <= marker_len + sizeof(*sig)) |
|
return -ENOENT; |
|
|
|
p = buf + buf_len - marker_len; |
|
if (memcmp(p, MODULE_SIG_STRING, marker_len)) |
|
return -ENOENT; |
|
|
|
buf_len -= marker_len; |
|
sig = (const struct module_signature *)(p - sizeof(*sig)); |
|
|
|
rc = mod_check_sig(sig, buf_len, func_tokens[func]); |
|
if (rc) |
|
return rc; |
|
|
|
sig_len = be32_to_cpu(sig->sig_len); |
|
buf_len -= sig_len + sizeof(*sig); |
|
|
|
/* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */ |
|
hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL); |
|
if (!hdr) |
|
return -ENOMEM; |
|
|
|
hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len); |
|
if (IS_ERR(hdr->pkcs7_msg)) { |
|
rc = PTR_ERR(hdr->pkcs7_msg); |
|
kfree(hdr); |
|
return rc; |
|
} |
|
|
|
memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len); |
|
hdr->raw_pkcs7_len = sig_len; |
|
|
|
/* We don't know the hash algorithm yet. */ |
|
hdr->hash_algo = HASH_ALGO__LAST; |
|
|
|
*modsig = hdr; |
|
|
|
return 0; |
|
} |
|
|
|
/** |
|
* ima_collect_modsig - Calculate the file hash without the appended signature. |
|
* |
|
* Since the modsig is part of the file contents, the hash used in its signature |
|
* isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code |
|
* calculates a separate one for signature verification. |
|
*/ |
|
void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size) |
|
{ |
|
int rc; |
|
|
|
/* |
|
* Provide the file contents (minus the appended sig) so that the PKCS7 |
|
* code can calculate the file hash. |
|
*/ |
|
size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) + |
|
sizeof(struct module_signature); |
|
rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size); |
|
if (rc) |
|
return; |
|
|
|
/* Ask the PKCS7 code to calculate the file hash. */ |
|
rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest, |
|
&modsig->digest_size, &modsig->hash_algo); |
|
} |
|
|
|
int ima_modsig_verify(struct key *keyring, const struct modsig *modsig) |
|
{ |
|
return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring, |
|
VERIFYING_MODULE_SIGNATURE, NULL, NULL); |
|
} |
|
|
|
int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo, |
|
const u8 **digest, u32 *digest_size) |
|
{ |
|
*algo = modsig->hash_algo; |
|
*digest = modsig->digest; |
|
*digest_size = modsig->digest_size; |
|
|
|
return 0; |
|
} |
|
|
|
int ima_get_raw_modsig(const struct modsig *modsig, const void **data, |
|
u32 *data_len) |
|
{ |
|
*data = &modsig->raw_pkcs7; |
|
*data_len = modsig->raw_pkcs7_len; |
|
|
|
return 0; |
|
} |
|
|
|
void ima_free_modsig(struct modsig *modsig) |
|
{ |
|
if (!modsig) |
|
return; |
|
|
|
pkcs7_free_message(modsig->pkcs7_msg); |
|
kfree(modsig); |
|
}
|
|
|