LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

Linux Key子系统

Linux Key Retention Service(密钥保留服务)是内核的核心安全组件,用于在内核空间安全地管理密钥、证书和认证凭据。它为内核模块和文件系统提供统一的密钥管理框架。

1 Key子系统基本概念

1.1 主要目标

1. 安全存储:在内核空间安全保存敏感数据(如加密密钥、SSL证书)
2. 访问控制:基于权限模型(UID/GID)控制密钥访问
3. 生命周期管理:支持密钥的创建、更新、撤销、自动过期
4. 命名空间隔离:为容器提供独立的密钥域(keyring_ns)
5. 层次化组织:通过嵌套的密钥环(keyring)构建树形结构。

1.2 秘钥基本概念

概念简介
1. ASN.1(Abstract Syntax Notation One)
- 作用:跨平台描述数据结构的抽象语法标准(如证书、密钥格式)。
- 特点:定义语法规则(如 INTEGER, SEQUENCE),不指定编码方式。
- 类比:类似编程语言的类型声明(如C的 struct)。

2. BER(Basic Encoding Rules)
- 作用:ASN.1 的基础编码规则,将数据结构转为二进制。
- 特点:编码灵活(同一数据可有多种合法编码),适用于网络传输等非严格场景。
- 问题:非唯一性可能导致安全风险。

3. DER(Distinguished Encoding Rules)
- 作用:BER 的严格子集,确保唯一二进制编码。
- 场景:证书(X.509)、签名(PKCS#7)等安全领域,避免编码歧义。

4. PKCS#7/CMS(Cryptographic Message Syntax)
- 作用:基于 ASN.1/DER 的加密消息封装标准。
- 功能:支持数字签名、加密、证书链封装(如 .p7b 文件)。
- 应用:文档签名、邮件加密、内核模块签名。

5. PKCS#1 v1.5
- 作用:RSA 密钥格式与签名填充标准(基于 ASN.1/DER)。
- 问题:填充漏洞(如 Bleichenbacher 攻击),逐渐被 RSA-PSS 替代。
- 遗留应用:旧版 TLS/SSL 协议。

6. X.509
- 作用:公钥证书的国际标准(基于 ASN.1 和 DER)。
- 结构:包含版本号、序列号、使用者/颁发者、公钥、签名等字段。
- 应用:TLS/SSL、代码签名、身份认证。

7. CRL(Certificate Revocation List)
- 作用:基于 ASN.1/DER 的列表,记录被吊销的证书序列号。
- 缺点:更新延迟(需定期下载全量列表),逐渐被 OCSP 替代。

8. OCSP(Online Certificate Status Protocol)
- 作用:实时查询证书吊销状态的协议(替代 CRL)。
- 数据格式:请求/响应使用 ASN.1 编码(DER 或 BER)。
- 优势:低延迟,按需查询。

9. PEM(Privacy-Enhanced Mail)
- 作用:将 DER 二进制数据转换为 Base64 的文本封装格式。
- 标识:以 -----BEGIN/END CERTIFICATE----- 包裹。
- 文件扩展名:.pem, .crt, .key。

2 Key子系统初始化

2.1 Key初始化

key_init用户初始化Key子系统基础struct key slab对象,以及添加默认key_type:

start_kernel
  ->key_init
    ->kmem_cache_create--创建密钥对象缓存key_jar用于保存struct key。
    ->list_add_tail--将keyring(密钥环容器)、dead(无效type)、user(用户数据密钥)、logon(登录凭证)等key类型加入到key_types_list中。
    ->rb_link_node--初始user会话密钥环。
    ->rb_insert_color

常见的key_type有:

密钥类型 (key_type)描述典型用途
keyring 密钥容器 组织其他密钥的容器
user 用户密钥 存储任意用户数据
logon 登录凭据/密码 用户登录
asymmetric 非对称密钥 存储证书和公钥/私钥
trusted TPM保护密钥 可信平台模块保护的密钥
encrypted 加密密钥 加密文件系统密钥
big_key 大容量密钥 存储大尺寸数据(>4KB)
cifs.idmap CIFS身份映射 SMB/CIFS文件系统
fscrypt 文件系统加密 ext4/f2fs加密
dns_resolver DNS解析器 内核级DNS解析

2.2 初始化系统可信keyring 

system_trusted_keyring_init()是内核密钥管理子系统的一部分,专门用于存储系统级可信的公钥或证书,以支持对关键安全操作的验证(如内核模块签名验证、安全启动、完整性校验等)。初始化两种keyring:builtin_trusted_keys和secondary_trusted_keys。

system_trusted_keyring_init
    keyring_alloc--分配并初始化keyring对象(.builtin_trusted_keys和.secondary_trusted_keys),为内核或用户空间程序动态创建一个具有指定属性的keyring,用于几种管理秘钥或其他安全凭据。
    key_alloc
      key_user_lookup
      security_key_alloc
      refcount_inc
      atomic_inc
      key_alloc_serial
  • builtin_trusted_keys:存储内核编译时内置的可信公钥或证书,是系统信任链的。用于验证内核模块签名、驱动签名等核心安全操作。
  • secondary_trusted_keys:存储从外部动态加载的次级可信密钥(如 Secure Boot 的 MOK(Machine Owner Key)或由管理员手动添加的密钥),用于扩展信任链。

2.3 加载系统可信证书到keyring

在system_certificates.S中定义了system_certificate_list内容:

  • 来自certs/signing_key.x509。
  • 来自certs/x509_certificate_list,通过CONFIG_SYSTEM_TRUSTED_KEYS配置文件路径。
    .align 8
    .globl system_certificate_list
system_certificate_list:
__cert_list_start:
#ifdef CONFIG_MODULE_SIG
    .incbin "certs/signing_key.x509"
#endif
    .incbin "certs/x509_certificate_list"
__cert_list_end:

    .align 8
    .globl system_certificate_list_size
system_certificate_list_size:
#ifdef CONFIG_64BIT
    .quad __cert_list_end - __cert_list_start
#else
    .long __cert_list_end - __cert_list_start
#endif
  • system_certificate_list:指向编译时内置的 X.509 证书数据的指针。
  • system_certificate_list_size:表示 `system_certificate_list` 数据的总大小(字节数),用于确定证书数据的边界。

load_system_certificate_init()在内核初始化阶段,加载编译到内核中的 X.509 证书列表到系统信任的密钥环(如 `builtin_trusted_keys`)。

load_system_certificate_list
  x509_load_certificate_list
    make_key_ref
    key_create_or_update
      __key_create_or_update
        key_type_lookup
        key_ref_to_ptr
        key_check
        key_set_index_key
        __key_link_lock
        __key_link_begin
        key_permission
        find_key_to_update
        key_alloc
        __key_instantiate_and_link
        ima_post_key_create_or_update
        make_key_ref

2.4 生成builtin_trusted_keys

Cryptographic API
  Certificates for signature checking
    Provide system-wide ring of trusted keys
      Additional X.509 keys for default system keyring--配置x509格式签名证书路径,编译时即可编译到.builtin_trusted_keys段中。
      Reserve area for inserting a certificate without recompiling
        Number of bytes to reserve for the extra certificate
      Provide a keyring to which extra trustable keys may be added
    Provide system-wide ring of blacklisted keys

 1. 生成用于签名的X.509密钥对:

# 生成私钥
openssl genrsa -out my_signing_key.pem 4096

# 生成自签名证书(公钥)
openssl req -new -x509 -key my_signing_key.pem -out my_signing_key.x509 -subj "/CN=My Custom Key/"

2. 复制DER文件到内核源码目录。

3. 修改内核配置CONFIG_SYSTEM_TRUSTED_KEYS指向my_signing_key.x509。

4. 编译内核,启动查看秘钥:

sudo keyctl list %:.builtin_trusted_keys

查看/proc/keys,同样可以看到.builtin_trusted_keys。

2.5 /proc/keys和/proc/key-users初始化

key_proc_init创建key相关proc节点:

key_proc_init
  ->proc_create_seq--创建/proc/keys和/proc/key-users两个proc节点。

/proc/keys显示当前内核中所有已注册密钥的详细信息。

每行代表一个密钥,字段用冒号分隔:

<key_ID> <flags> <usage_count> <timeout> <permissions> <UID> <GID> <type> <description> <payload_info>

字段说明:

字段说明示例
key_ID 密钥的唯一标识符(十六进制) 01f3a5e1
flags 密钥状态标志(见下表) 位置: 1 2 3 4 5 6 7
标志: I R D Q U N i
usage_count 当前引用计数 3
permissions 权限位(十六进制) 3f3f0000
UID 所有者用户ID 0 (root)
GID 所有者组ID 0 (root)
type 密钥类型 keyringasymmetricuser
description 密钥描述 builtin_trusted_keys
payload_info 负载摘要信息 12 (user密钥数据长度)

flags显示时:- = 未设置,字母 = 已设置。

  • I - Instantiated (已实例化)

  • R - Revoked (已撤销)

  • D - Dead (待销毁)

  • Q - 计入用户配额

  • U - Under construction (构建中)

  • N - Negative key (负密钥)

  • i - Invalidated (已失效)

/proc/key-users显示每个用户的密钥配额使用情况。

每行代表一个用户,字段用空格分隔:

<UID>: <usage> <nkeys>/<nikeys> <qnkeys>/<maxkeys> <qnbytes>/<maxbytes>

字段说明

字段说明示例
UID 用户ID 0 (root)
usage 内核内部使用计数 10
nkeys/nikeys 总密钥数/已实例化密钥数 15/14
qnkeys/maxkeys 已使用密钥配额/最大配额 15/200
qnbytes/maxbytes 已使用存储配额/最大配额(字节) 2048/20000

3 数据结构

struct key 表示内核中的一个密钥实体(包含密钥数据、权限、引用计数等),Keyring 本质上是一种特殊类型的密钥,用 struct key 表示,其类型为 key_type_keyring。  

struct key {
        refcount_t              usage;          /* 引用计数 -- 跟踪密钥被引用的次数,归零时触发销毁 */
        key_serial_t            serial;         /* 密钥序列号 -- 用户空间操作密钥的唯一标识符 */
        union {
                struct list_head graveyard_link; /* 废弃链表节点 -- 用于撤销队列管理 */
                struct rb_node  serial_node;    /* 红黑树节点 -- 按序列号组织全局密钥树 */
        };
#ifdef CONFIG_KEY_NOTIFICATIONS
        struct watch_list       *watchers;      /* 监视器列表 -- 支持密钥变更通知机制 */
#endif
        struct rw_semaphore     sem;            /* 读写信号量 -- 保护密钥状态的并发修改 */
        struct key_user         *user;          /* 密钥所有者 -- 关联配额和资源统计 */
        void                    *security;      /* 安全域指针 -- 存储LSM模块的安全数据(如SELinux) */
        union {
                time64_t        expiry;         /* 过期时间 -- 密钥自动失效的时间戳(0=永不过期) */
                time64_t        revoked_at;     /* 撤销时间 -- 密钥被标记为撤销的时间戳 */
        };
        time64_t                last_used_at;   /* 最后使用时间 -- 实现LRU淘汰机制的关键字段 */
        kuid_t                  uid;            /* 用户ID -- 密钥所有者的用户标识 */
        kgid_t                  gid;            /* 组ID -- 密钥所有者的组标识 */
        key_perm_t              perm;           /* 权限位 -- 定义所有者/组/其他用户的访问权限(VIEW/READ/WRITE等) */
        unsigned short          quotalen;       /* 配额长度 -- 此密钥占用的配额单位数 */
        unsigned short          datalen;        /* 有效载荷长度 -- payload数据的实际长度(可能与RCU数据不同) */
        short                   state;          /* 密钥状态 -- 正值表示有效状态,负值表示错误码 */

        unsigned long           flags;          /* 状态标志位 -- 关键状态标识(见下方宏定义) */
        // 标志位宏定义(部分关键标志)
        #define KEY_FLAG_DEAD           0       /* 类型已删除 -- 关联的key_type已被注销 */
        #define KEY_FLAG_REVOKED        1       /* 已撤销 -- 密钥被管理员显式撤销 */
        #define KEY_FLAG_INVALIDATED    5       /* 已失效 -- 密钥内容被标记为无效 */
        #define KEY_FLAG_BUILTIN        6       /* 内置密钥 -- 内核启动时预置的不可变密钥 */
        #define KEY_FLAG_UID_KEYRING    9       /* 用户密钥环 -- 表示此密钥是用户/会话密钥环 */

        /* 密钥标识联合体 */
        union {
                struct keyring_index_key index_key; /* 索引结构 -- 加速密钥查找 */
                struct {
                        unsigned long   hash;      /* 哈希值 -- 基于描述符计算的快速查找键 */
                        unsigned long   len_desc;  /* 描述符长度 -- description字符串长度 */
                        struct key_type *type;     /* 密钥类型 -- 指向操作函数集(如user/keyring) */
                        struct key_tag  *domain_tag; /* 操作域标签 -- 支持密钥分域隔离(如NFS) */
                        char            *description; /* 描述符 -- 人类可读的密钥标识字符串 */
                };
        };

        /* 有效载荷联合体 */
        union {
                union key_payload payload;      /* 通用载荷 -- 存储实际密钥数据(如加密密钥) */
                struct {                        /* 密钥环专用结构 */
                        struct list_head name_link; /* 名称链表 -- 按描述符维护子密钥链表 */
                        struct assoc_array keys; /* 关联数组 -- 存储子密钥的高效数据结构 */
                };
        };

        struct key_restriction *restrict_link; /* 链接限制 -- 控制密钥环添加子密钥的规则 */
};

struct key_type 定义密钥类型的操作和行为(如加解密、销毁等逻辑)。key_type 是 Linux Keyring 子系统的核心抽象,定义了特定类型密钥的操作接口和行为规范。它在内核中的完整定义如下:

struct key_type {
    const char *name;                -- // 密钥类型名称(如"keyring", "user")
    size_t def_datalen;              -- // 默认负载长度(用于配额预计算)
    unsigned int flags;              -- // 类型标志(如网络域/立即回收等)
    int (*vet_description)(const char *description); -- // 校验密钥描述字符串
    int (*preparse)(struct key_preparsed_payload *prep); -- // 预解析用户态密钥数据
    void (*free_preparse)(struct key_preparsed_payload *prep); -- // 释放预解析数据
    int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); -- // 初始化密钥实体
    int (*update)(struct key *key, struct key_preparsed_payload *prep); -- // 更新密钥数据
    int (*match_preparse)(struct key_match_data *match_data); -- // 预解析密钥匹配数据
    void (*match_free)(struct key_match_data *match_data); -- // 释放匹配预解析数据
    void (*revoke)(struct key *key); -- // 撤销密钥(清除敏感数据)
    void (*destroy)(struct key *key); -- // 销毁密钥私有数据
    void (*describe)(const struct key *key, struct seq_file *p); -- // 密钥描述输出
    long (*read)(const struct key *key, char *buffer, size_t buflen); -- // 读取密钥数据
    request_key_actor_t request_key; -- // 自定义密钥请求处理函数
    struct key_restriction *(*lookup_restriction)(const char *params); -- // 查找密钥操作限制
    int (*asym_query)(const struct kernel_pkey_params *params, struct kernel_pkey_query *info); -- // 非对称密钥查询
    int (*asym_eds_op)(struct kernel_pkey_params *params, const void *in, void *out); -- // 非对称加密/解密/签名
    int (*asym_verify_signature)(struct kernel_pkey_params *params, const void *in, const void *in2); -- // 非对称签名验证
    struct list_head link;           -- // 类型链表节点(连接所有注册类型)
    struct lock_class_key lock_class;-- // 密钥信号量锁类型
} __randomize_layout;

4 Key相关API

1. 密钥(key)管理

struct key *key_alloc(struct key_type *type, const char *desc, ...);  -- 分配新密钥对象(未初始化)
int key_instantiate_and_link(struct key *key, ...);  -- 初始化密钥并链接到密钥环
void key_put(struct key *key);  -- 减少引用计数(计数归零时触发销毁)
struct key *key_get(struct key *key);  -- 增加密钥引用计数
void key_revoke(struct key *key);  -- 立即使密钥失效(标记为不可用)
int key_update(key_ref_t key_ref, ...);  -- 更新密钥负载数据
void key_invalidate(struct key *key);  -- 标记密钥为永久无效
long key_read(const struct key *key, ...);  -- 读取密钥数据到用户空间

2. 密钥类型(key_type)

int register_key_type(struct key_type *ktype);  -- 向内核注册新密钥类型
void unregister_key_type(struct key_type *ktype);  -- 注销密钥类型
int key_type_vet_description(const struct key_type *ktype, const char *desc);  -- 校验密钥描述符有效性
// 关键回调(在key_type结构体中定义):
int (*preparse)(struct key_preparsed_payload *prep);  -- 预解析用户空间密钥数据
void (*free_preparse)(struct key_preparsed_payload *prep);  -- 释放预解析资源
int (*instantiate)(struct key *key, ...);  -- 初始化密钥负载
int (*update)(struct key *key, ...);  -- 更新密钥数据
void (*destroy)(struct key *key);  -- 销毁密钥私有数据
int (*asym_eds_op)(struct kernel_pkey_params *params, ...);  -- 非对称加密/解密/签名

3. 密钥环(keyring)操作

struct key *keyring_alloc(const char *desc, ...);  -- 创建新密钥环对象
int key_link(struct key *keyring, struct key *key);  -- 将密钥链接到密钥环
int key_unlink(struct key *keyring, struct key *key);  -- 从密钥环移除密钥
int keyring_clear(struct key *keyring);  -- 清空密钥环所有密钥
key_ref_t keyring_search(key_ref_t keyring_ref, ...);  -- 在密钥环中递归搜索密钥
key_ref_t keyring_search_rcu(key_ref_t keyring_ref, ...);  -- RCU保护的密钥搜索(无锁)
int keyring_restrict(key_ref_t keyring_ref, ...);  -- 设置密钥环操作限制

4. 密钥搜索与匹配

key_ref_t lookup_user_key(key_serial_t id, ...);  -- 根据用户空间ID查找密钥
int key_match_preparse(struct key_match_data *match_data);  -- 预解析密钥匹配数据
int key_match(const struct key *key, ...);  -- 执行密钥匹配逻辑
bool search_nested_keyrings(struct key *keyring, ...);  -- 递归搜索嵌套密钥环

5. 权限与安全控制

int key_permission(const key_ref_t key_ref, unsigned perm);  -- 检查密钥操作权限
bool key_validate(const struct key *key);  -- 验证密钥状态有效性
int key_task_permission(const key_ref_t key_ref, ...);  -- 检查进程密钥权限
int key_create(key_ref_t keyring_ref, ...);  -- 安全创建密钥(含权限检查)

6. 引用管理

key_ref_t make_key_ref(const struct key *key, bool possessed);  -- 创建密钥引用对象
struct key *key_ref_to_ptr(const key_ref_t key_ref);  -- 安全转换引用为指针
int key_create_or_update(key_ref_t keyring_ref, ...);  -- 创建/更新密钥的封装

7. 用户空间交互

// keyring负载定义(include/linux/key.h)
struct keyring_payload {
    struct assoc_array keys;  -- 关联数组存储子密钥指针
};

// 密钥环类型定义(security/keys/keyring.c)
struct key_type key_type_keyring = {
    .name           = "keyring",  -- 密钥环类型标识
    .preparse       = keyring_preparse,  -- 密钥环专用预解析
    .free_preparse  = keyring_free_preparse,  -- 释放密钥环预解析
    .instantiate    = keyring_instantiate,  -- 密钥环实例化
    .destroy        = keyring_destroy,  -- 密钥环销毁
    .describe       = keyring_describe,  -- 密钥环描述
    .read           = keyring_read,  -- 读取密钥环内容
};

5 其他Key/Keyring

5.1 Platform Keyring

platform_trusted_keys:存储与硬件平台相关的可信密钥(如 TPM 模块中的证书或固件提供的密钥),用于验证固件更新、硬件驱动等。

platform_keyring_init
  integrity_init_keyring
    __integrity_init_keyring
      keyring_alloc
      set_platform_trusted_keys

machine_trusted_keys:特定于虚拟机或容器环境的密钥环,用于验证虚拟设备(如虚拟 TPM)或容器镜像的签名。

5.2 Asymmetric Key(非对称密钥)

asymmetric_key_init注册asymmetric密钥类型:

asymmetric_key_init
  ->register_key_type -- 注册非对称密钥类型到内核密钥子系统
    ->key_type_asymmetric -- 定义非对称密钥操作的标准结构体

 asymmetric密钥类型操作函数如下:

struct key_type key_type_asymmetric = {
        .name                   = "asymmetric",
        .preparse               = asymmetric_key_preparse,
        .free_preparse          = asymmetric_key_free_preparse,
        .instantiate            = generic_key_instantiate,
        .match_preparse         = asymmetric_key_match_preparse,
        .match_free             = asymmetric_key_match_free,
        .destroy                = asymmetric_key_destroy,
        .describe               = asymmetric_key_describe,
        .lookup_restriction     = asymmetric_lookup_restriction,
        .asym_query             = query_asymmetric_key,
        .asym_eds_op            = asymmetric_key_eds_op,
        .asym_verify_signature  = asymmetric_key_verify_signature,
};

 x509_key_init注册解析x509格式秘钥的解析器:

x509_key_init
  ->register_asymmetric_key_parser -- 将x509解析器注册到非对称密钥解析器列表
    ->x509_key_parser -- X.509证书专用解析器结构
      ->x509_key_preparse -- X.509证书预处理主函数
        ->x509_cert_parse -- 执行证书解析的核心函数
          ->kzalloc -- 动态分配证书解析所需内存空间
          ->asn1_ber_decoder -- 使用BER规则解码ASN.1格式证书数据
          ->kmemdup -- 复制解码后的公钥等关键数据到安全内存区
          ->x509_get_sig_params -- 提取并验证证书签名算法参数
          ->asymmetric_key_generate_id -- 生成基于颁发者和序列号的唯一密钥标识
          ->x509_check_for_self_signed -- 检测证书是否自签名
            ->public_key_verify_signature -- 用公钥验证证书签名有效性
        ->填充struct key_preparsed_payload数据 -- 将解析结果装配到密钥预备数据结构 

struct asymmetric_key_subtype定义非对称密钥的操作集合(函数指针),用于实现特定类型密钥(如公钥、私钥、证书)的定制化行为。它是内核密钥子系统的核心扩展机制。

struct asymmetric_key_subtype {
    const char *name;  // 子类型名称(如 "public_key")
    void (*describe)(const struct key *key, struct seq_file *m); // 密钥描述
    void (*destroy)(void *payload); // 密钥销毁时清理资源
    int (*query)(const struct kernel_pkey_params *params, struct kernel_pkey_query *info); // 查询密钥能力
    int (*eds_op)(struct kernel_pkey_params *params, const void *in, void *out); // 加密/解密/签名操作
    int (*verify_signature)(const struct key *key, const struct public_key_signature *sig); // 验证签名
};

public_key_subtype 是 asymmetric_key_subtype 的一个具体实例,专用于处理 公钥(Public Key) 的操作。它是内核中公钥的默认实现。

static struct asymmetric_key_subtype public_key_subtype = {
    .name = "public_key",
    .describe = public_key_describe,      // 打印公钥信息
    .destroy = public_key_destroy,        // 清理公钥资源
    .query = public_key_query,            // 查询公钥能力
    .eds_op = public_key_eds_op,          // 公钥加密(通常仅支持加密)
    .verify_signature = public_key_verify_signature, // 验证签名
};

6 Keyctl使用说明

密钥类型包括:

- user:用户自定义的密钥(明文存储)。
- keyring:密钥容器(类似目录)。
- logon:用于加密文件系统的密钥(如 eCryptfs)。
- big_key:存储大容量数据(超过 4KB)。

  • 创建密钥
keyctl add <type> <description> <data> <keyring>

创建一个用户密钥,内容为 "mysecret",关联到当前会话密钥环(@s)

keyctl add user mykey "mysecret" @s
  • 列出密钥
keyctl list <keyring>

列出当前用户会话密钥环中的密钥

keyctl list @s

列出所有进程可访问的密钥

keyctl list @us
  • 读取密钥内容
keyctl print <key-id>

读取密钥 ID 为 12345678 的内容

keyctl print 12345678
  • 更新密钥
keyctl update <key-id> <new-data>

更新密钥 ID 为 12345678 的内容为 "newsecret"

keyctl update 12345678 "newsecret"
  • 删除密钥
keyctl unlink <key-id> <keyring>

从当前会话密钥环中删除密钥 12345678

keyctl unlink 12345678 @s

 

posted on 2025-07-21 23:59  ArnoldLu  阅读(151)  评论(0)    收藏  举报

导航