!57 common_modules 代码签名模块

Merge pull request !57 from Hongjin Li/cert_path
This commit is contained in:
openharmony_ci
2023-10-19 09:33:18 +00:00
committed by Gitee
11 changed files with 522 additions and 0 deletions
+1
View File
@@ -3,5 +3,6 @@
./xpm/
./qos_auth/
./ucollection/
./code_sign
As for the specific use of the licenses, please refer to the relevant description in the documents.
+2
View File
@@ -61,10 +61,12 @@ Note:If the text contains special characters, please escape them according to th
<policyitem type="compatibility" name="GPL" path="xpm/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="qos_auth/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="ucollection/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="code_sign/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="newip/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="xpm/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="qos_auth/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="ucollection/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="code_sign/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
</policy>
</policylist>
<filefilterlist>
+13
View File
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (c) 2023 Huawei Device Co., Ltd.
#
config SECURITY_CODE_SIGN
bool "Advanced code signing feature based on FS Verity"
depends on FS_VERITY
default n
help
This option enables additional code signing verify features
based on fs-verity, including verify if a certificate's subject
and issuer can be trusted, etc.
If unsure, say N.
+21
View File
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (c) 2023 Huawei Device Co., Ltd.
#
obj-$(CONFIG_SECURITY_CODE_SIGN) += \
code_sign_misc.o \
verify_cert_chain.o \
code_sign_ioctl.o
ccflags-$(CONFIG_SECURITY_CODE_SIGN) += \
-I$(srctree)/fs/code_sign \
-I$(srctree)/security/selinux/include \
-I$(srctree)/security/selinux
$(addprefix $(obj)/,$(obj-y)): $(obj)/flask.h
quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h
cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h
targets += flask.h av_permissions.h
$(obj)/flask.h: $(srctree)/security/selinux/include/classmap.h FORCE
$(call if_changed,flask)
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2023 Huawei Device Co., Ltd.
#
set -e
OHOS_SOURCE_ROOT=$1
KERNEL_BUILD_ROOT=$2
PRODUCT_NAME=$3
KERNEL_VERSION=$4
CODE_SIGN_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/code_sign
function main()
{
pushd .
if [ ! -d "$KERNEL_BUILD_ROOT/fs/code_sign" ]; then
mkdir $KERNEL_BUILD_ROOT/fs/code_sign
fi
cd $KERNEL_BUILD_ROOT/fs/code_sign
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/fs/code_sign $CODE_SIGN_SOURCE_ROOT)/* ./
popd
}
main
+183
View File
@@ -0,0 +1,183 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/compat.h>
#include "avc.h"
#include "objsec.h"
#include "code_sign_ioctl.h"
#include "code_sign_log.h"
struct rb_root cert_chain_tree = RB_ROOT;
struct cert_source *cert_chain_search(struct rb_root *root, struct x509_certificate *cert)
{
struct rb_node **cur_node = &(root->rb_node);
while (*cur_node) {
struct cert_source *cur_cert = container_of(*cur_node, struct cert_source, node);
int result = strcmp(cert->subject, cur_cert->subject);
if (result < 0) {
cur_node = &((*cur_node)->rb_left);
} else if (result > 0) {
cur_node = &((*cur_node)->rb_right);
} else {
result = strcmp(cert->issuer, cur_cert->issuer);
if (result < 0) {
cur_node = &((*cur_node)->rb_left);
} else if (result > 0) {
cur_node = &((*cur_node)->rb_right);
} else {
code_sign_log_info("cert found");
return cur_cert;
}
}
}
code_sign_log_error("cert not found");
return NULL;
}
struct cert_source *find_match(struct x509_certificate *cert)
{
return cert_chain_search(&cert_chain_tree, cert);
}
void cert_chain_insert(struct rb_root *root, struct cert_source *cert)
{
struct rb_node **new = &(root->rb_node), *parent = NULL;
while (*new) {
struct cert_source *this = container_of(*new, struct cert_source, node);
int result = strcmp(cert->subject, this->subject);
parent = *new;
if (result < 0) {
new = &((*new)->rb_left);
} else if (result > 0) {
new = &((*new)->rb_right);
} else {
result = strcmp(cert->issuer, this->issuer);
if (result < 0) {
new = &((*new)->rb_left);
} else if (result > 0) {
new = &((*new)->rb_right);
} else {
code_sign_log_info("cert already exist in trust sources");
return;
}
}
}
// add new node
rb_link_node(&cert->node, parent, new);
rb_insert_color(&cert->node, root);
}
int code_sign_open(struct inode *inode, struct file *filp)
{
return 0;
}
int code_sign_release(struct inode *inode, struct file *filp)
{
return 0;
}
int code_sign_avc_has_perm(u16 tclass, u32 requested)
{
struct av_decision avd;
u32 sid = current_sid();
int rc, rc2;
rc = avc_has_perm_noaudit(&selinux_state, sid, sid, tclass, requested,
AVC_STRICT, &avd);
rc2 = avc_audit(&selinux_state, sid, sid, tclass, requested, &avd, rc,
NULL, AVC_STRICT);
if (rc2)
return rc2;
return rc;
}
long code_sign_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
int ret = 0;
if (code_sign_avc_has_perm(SECCLASS_CODE_SIGN, CODE_SIGN__ADD_CERT_CHAIN)) {
code_sign_log_error("selinux check failed, no permission to add cert chain");
return -EPERM;
}
if (cmd != WRITE_CERT_CHAIN) {
code_sign_log_error("code_sign cmd error, cmd: %d", cmd);
return -EINVAL;
}
struct cert_source *source = kzalloc(sizeof(struct cert_source), GFP_KERNEL);
if (!source)
return -ENOMEM;
struct cert_chain_info info;
if (copy_from_user(&info, args, sizeof(struct cert_chain_info))) {
code_sign_log_error("cmd copy_from_user failed");
ret = -ENOMEM;
goto copy_source_failed;
}
if (info.path_len > CERT_CHAIN_PATH_LEN_MAX) {
code_sign_log_error("invalid path len: %d", info.path_len);
ret = -EINVAL;
goto copy_source_failed;
}
source->subject = kzalloc(info.signing_length, GFP_KERNEL);
if (!source->subject) {
ret = -ENOMEM;
goto copy_source_failed;
}
if (copy_from_user(source->subject, u64_to_user_ptr(info.signing_ptr), info.signing_length)) {
code_sign_log_error("copy_from_user get signing failed");
ret = -EFAULT;
goto copy_subject_failed;
}
source->issuer = kzalloc(info.issuer_length, GFP_KERNEL);
if (!source->issuer) {
ret = -ENOMEM;
goto copy_subject_failed;
}
ret = copy_from_user(source->issuer, u64_to_user_ptr(info.issuer_ptr), info.issuer_length);
if (ret) {
code_sign_log_error("copy_from_user get issuer failed");
ret = -EFAULT;
goto copy_issuer_failed;
}
source->max_path_depth = info.path_len;
code_sign_log_info("add trusted cert: subject = '%s', issuer = '%s', max_path_depth = %d",
source->subject, source->issuer, source->max_path_depth);
// insert rb_tree
cert_chain_insert(&cert_chain_tree, source);
return ret;
copy_issuer_failed:
kfree(source->issuer);
copy_subject_failed:
kfree(source->subject);
copy_source_failed:
kfree(source);
return ret;
}
+43
View File
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include <linux/rbtree.h>
#include <../../crypto/asymmetric_keys/pkcs7_parser.h>
#ifndef _CODE_SIGN_H
#define _CODE_SIGN_H
struct cert_chain_info {
__u32 signing_length;
__u32 issuer_length;
__u64 signing_ptr;
__u64 issuer_ptr;
__u32 path_len;
__u8 __reserved[36];
};
struct cert_source {
char *subject;
char *issuer;
int max_path_depth;
struct rb_node node;
};
#define WRITE_CERT_CHAIN _IOW('k', 1, struct cert_chain_info)
#define CERT_CHAIN_PATH_LEN_MAX 3
/*
* cert_chain.c
*/
struct cert_source *find_match(struct x509_certificate *cert);
int code_sign_open(struct inode *inode, struct file *filp);
int code_sign_release(struct inode *inode, struct file *filp);
long code_sign_ioctl(struct file *filp, unsigned int cmd, unsigned long args);
#endif /* _CODE_SIGN_H */
+23
View File
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _CODE_SIGN_LOG_H
#define _CODE_SIGN_LOG_H
#define CODE_SIGN_TAG "code_sign_kernel"
#define CODE_SIGN_INFO_TAG "I"
#define CODE_SIGN_ERROR_TAG "E"
#define CODE_SIGN_WARN_TAG "W"
#define code_sign_log_info(fmt, args...) pr_info("[%s/%s]%s: " fmt "\n", \
CODE_SIGN_INFO_TAG, CODE_SIGN_TAG, __func__, ##args)
#define code_sign_log_error(fmt, args...) pr_err("[%s/%s]%s: " fmt "\n", \
CODE_SIGN_ERROR_TAG, CODE_SIGN_TAG, __func__, ##args)
#define code_sign_log_warn(fmt, args...) pr_warn("[%s/%s]%s: " fmt "\n", \
CODE_SIGN_WARN_TAG, CODE_SIGN_TAG, __func__, ##args)
#endif /* _CODE_SIGN_LOG_H */
+49
View File
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/hck/lite_hck_code_sign.h>
#include "code_sign_ioctl.h"
#include "code_sign_log.h"
static const struct file_operations code_sign_ops = {
.owner = THIS_MODULE,
.open = code_sign_open,
.release = code_sign_release,
.unlocked_ioctl = code_sign_ioctl,
.compat_ioctl = code_sign_ioctl,
};
static struct miscdevice code_sign_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "code_sign",
.fops = &code_sign_ops,
};
static void code_sign_register_hck_hooks(void)
{
REGISTER_HCK_LITE_HOOK(code_sign_verify_certchain_lhck, code_sign_verify_certchain);
}
static int __init code_sign_init(void)
{
code_sign_log_info("INIT");
code_sign_register_hck_hooks();
return misc_register(&code_sign_misc);
}
static void __exit code_sign_exit(void)
{
misc_deregister(&code_sign_misc);
code_sign_log_info("EXIT");
}
module_init(code_sign_init);
module_exit(code_sign_exit);
MODULE_LICENSE("GPL");
+144
View File
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include <linux/cred.h>
#include <linux/key.h>
#include <linux/slab.h>
#include <linux/verification.h>
#include <crypto/pkcs7.h>
#include "code_sign_ioctl.h"
#include "code_sign_log.h"
#include "verify_cert_chain.h"
/*
* Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
* uses the issuer's name and the issuing certificate serial number for
* matching purposes. These must match the certificate issuer's name (not
* subject's name) and the certificate serial number [RFC 2315 6.7].
*/
static int pkcs7_find_key(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct x509_certificate *cert;
unsigned certix = 1;
kenter("%u", sinfo->index);
code_sign_log_info("sinfo->index %u", sinfo->index);
cert = pkcs7->certs;
while (cert) {
if (asymmetric_key_id_same(cert->id, sinfo->sig->auth_ids[0])) {
if (strcmp(cert->pub->pkey_algo, sinfo->sig->pkey_algo) != 0
&& (strncmp(cert->pub->pkey_algo, "ecdsa-", 6) != 0
|| strcmp(cert->sig->pkey_algo, "ecdsa") != 0)) {
code_sign_log_warn("sig %u: X.509 algo and PKCS#7 sig algo don't match", sinfo->index);
cert = cert->next;
certix++;
continue;
}
} else {
code_sign_log_warn("sig %u: X.509->id and PKCS#7 sinfo->sig->auth_ids[0] don't match",
sinfo->index, cert->id, sinfo->sig->auth_ids[0]);
cert = cert->next;
certix++;
continue;
}
// cert is found
sinfo->signer = cert;
return 0;
}
/* The relevant X.509 cert isn't found here, but it might be found in
* the trust keyring.
*/
code_sign_log_info("Sig %u: Issuing X.509 cert not found (#%*phN)",
sinfo->index,
sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data);
return 0;
}
void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len, int *ret)
{
struct pkcs7_message *pkcs7;
struct pkcs7_signed_info *sinfo;
pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
if (IS_ERR(pkcs7)) {
code_sign_log_error("parse pkcs7 message failed");
*ret = PTR_ERR(pkcs7);
return;
}
// no cert chain, verify by certificates in keyring
if (!pkcs7->certs) {
code_sign_log_warn("no certs in pkcs7, might be found in trust keyring");
*ret = 0;
return;
}
if (!pkcs7->signed_infos) {
code_sign_log_error("signed info not found in pkcs7");
*ret = -EKEYREJECTED;
return;
}
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
/* Find the key for the signature if there is one */
*ret = pkcs7_find_key(pkcs7, sinfo);
if (*ret) {
code_sign_log_error("key not find in pkcs7");
return;
}
struct x509_certificate *signer = sinfo->signer;
if (!signer) {
code_sign_log_error("signer cert not found in pkcs7");
*ret = -EINVAL;
return;
}
struct cert_source *source = find_match(signer);
if (source == NULL) {
code_sign_log_error("signer certificate's subject and issuer not trusted");
*ret = -EKEYREJECTED;
return;
}
// cal cert chain depth
int cert_chain_depth_without_root = 1;
char *issuer = signer->issuer;
struct x509_certificate* cert = pkcs7->certs;
while(cert) {
// if issuer cert is found
if (cert->subject && (strcmp(cert->subject, issuer) == 0)) {
// reach root CA, end search
if (strcmp(cert->subject, cert->issuer) == 0) {
break;
}
cert_chain_depth_without_root++;
// search agains for current issuer's issuer
issuer = cert->issuer;
cert = pkcs7->certs;
} else {
// move to next certificate
cert = cert->next;
}
}
if (cert_chain_depth_without_root == (source->max_path_depth - 1)) {
code_sign_log_info("cert subject and issuer trusted");
*ret = 0;
return;
} else {
code_sign_log_error("depth mismatch: cert chain depth without root is %d, max_path_depth is %d",
cert_chain_depth_without_root, source->max_path_depth);
}
}
code_sign_log_error("cert subject and issuer verify failed");
*ret = -EKEYREJECTED;
return;
}
+15
View File
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#ifndef _VERIFY_CERT_CHAIN_H
#define _VERIFY_CERT_CHAIN_H
/*
* verify_cert_chain.c
*/
void code_sign_verify_certchain(const void *raw_pkcs7, size_t pkcs7_len, int *ret);
#endif /* _VERIFY_CERT_CHAIN_H */