request_key 函数详解 見出しへのリンク
1. 函数介绍 見出しへのリンク
request_key
是Linux内核密钥管理子系统(keyring)的用户空间接口函数,用于请求或查找密钥。它是Linux安全子系统的重要组成部分,允许应用程序安全地存储和检索密钥、密码、认证令牌等敏感信息。通过密钥管理系统,可以避免将敏感信息存储在不安全的位置。
2. 函数原型 見出しへのリンク
#include <sys/types.h>
#include <keyutils.h>
key_serial_t request_key(const char *type, const char *description,
const char *callout_info, key_serial_t dest_keyring);
3. 功能 見出しへのリンク
request_key
用于查找指定类型的密钥,如果密钥不存在则可以通过回调机制创建密钥。它提供了一种标准化的方式来管理应用程序的密钥和认证信息,支持多种密钥类型和安全的密钥存储。
4. 参数 見出しへのリンク
- *const char type: 密钥类型(如"user"、“logon”、“trusted"等)
- *const char description: 密钥描述(唯一标识符)
- *const char callout_info: 回调信息(用于创建密钥时的附加信息,可为NULL)
- key_serial_t dest_keyring: 目标密钥环(用于存储找到的密钥,可为0)
5. 返回值 見出しへのリンク
- 成功: 返回密钥序列号(正整数)
- 失败: 返回-1,并设置errno
6. 相似函数,或关联函数 見出しへのリンク
- add_key: 添加新密钥
- keyctl: 密钥控制操作的通用接口
- search_key: 在密钥环中搜索密钥
- revoke_key: 撤销密钥
7. 示例代码 見出しへのリンク
示例1:基础密钥操作 見出しへのリンク
#include <sys/types.h>
#include <keyutils.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
/**
* 演示基础密钥操作
*/
int demo_basic_key_operations() {
key_serial_t key1, key2;
char key_data[] = "This is my secret key data";
char retrieved_data[256];
long result;
printf("=== 基础密钥操作示例 ===\n");
// 添加一个用户密钥
key1 = add_key("user", "my_first_key", key_data, strlen(key_data), KEY_SPEC_SESSION_KEYRING);
if (key1 == -1) {
perror("添加密钥失败");
printf("注意:可能需要root权限或特定的内核配置\n");
return -1;
}
printf("成功添加密钥,序列号: %d\n", (int)key1);
// 尝试请求同一个密钥
key2 = request_key("user", "my_first_key", NULL, 0);
if (key2 == -1) {
perror("请求密钥失败");
// 清理已添加的密钥
keyctl(KEYCTL_REVOKE, key1);
return -1;
}
printf("成功请求密钥,序列号: %d\n", (int)key2);
// 验证两个密钥是同一个
if (key1 == key2) {
printf("✓ 密钥序列号匹配\n");
} else {
printf("✗ 密钥序列号不匹配\n");
}
// 从密钥中读取数据
result = keyctl(KEYCTL_READ, key2, (unsigned long)retrieved_data, sizeof(retrieved_data));
if (result == -1) {
perror("读取密钥数据失败");
keyctl(KEYCTL_REVOKE, key1);
return -1;
}
retrieved_data[result] = '\0';
printf("读取的密钥数据: %s\n", retrieved_data);
// 验证数据正确性
if (strcmp(key_data, retrieved_data) == 0) {
printf("✓ 密钥数据正确\n");
} else {
printf("✗ 密钥数据错误\n");
}
// 撤销密钥
if (keyctl(KEYCTL_REVOKE, key1) == -1) {
perror("撤销密钥失败");
return -1;
}
printf("密钥已撤销\n");
return 0;
}
int main() {
return demo_basic_key_operations();
}
示例2:不同密钥类型演示 見出しへのリンク
#include <sys/types.h>
#include <keyutils.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/**
* 演示不同类型的密钥
*/
int demo_key_types() {
key_serial_t key1, key2, key3;
const char *user_data = "User key data";
const char *logon_data = "Logon key data";
const char *big_key_data = "Big key with more data for testing purposes";
printf("=== 不同密钥类型演示 ===\n");
printf("支持的密钥类型包括:\n");
printf(" user: 通用用户密钥\n");
printf(" logon: 登录凭证密钥\n");
printf(" trusted: 可信平台模块密钥\n");
printf(" big_key: 大数据密钥\n");
printf(" encrypted: 加密密钥\n");
// 添加用户密钥
key1 = add_key("user", "user_key_example", user_data, strlen(user_data),
KEY_SPEC_SESSION_KEYRING);
if (key1 != -1) {
printf("✓ 成功添加user类型密钥: %d\n", (int)key1);
keyctl(KEYCTL_REVOKE, key1);
} else {
printf("✗ 添加user类型密钥失败: %s\n", strerror(errno));
}
// 添加logon密钥
key2 = add_key("logon", "logon_key_example", logon_data, strlen(logon_data),
KEY_SPEC_SESSION_KEYRING);
if (key2 != -1) {
printf("✓ 成功添加logon类型密钥: %d\n", (int)key2);
keyctl(KEYCTL_REVOKE, key2);
} else {
printf("✗ 添加logon类型密钥失败: %s\n", strerror(errno));
}
// 添加big_key密钥
key3 = add_key("big_key", "big_key_example", big_key_data, strlen(big_key_data),
KEY_SPEC_SESSION_KEYRING);
if (key3 != -1) {
printf("✓ 成功添加big_key类型密钥: %d\n", (int)key3);
keyctl(KEYCTL_REVOKE, key3);
} else {
printf("✗ 添加big_key类型密钥失败: %s\n", strerror(errno));
}
return 0;
}
int main() {
return demo_key_types();
}
示例3:密钥环操作 見出しへのリンク
#include <sys/types.h>
#include <keyutils.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/**
* 演示密钥环操作
*/
int demo_keyring_operations() {
key_serial_t session_ring, user_ring, process_ring;
key_serial_t key1, key2;
char key_data[] = "Keyring test data";
printf("=== 密钥环操作演示 ===\n");
// 获取不同的特殊密钥环
session_ring = KEY_SPEC_SESSION_KEYRING;
user_ring = KEY_SPEC_USER_KEYRING;
process_ring = KEY_SPEC_PROCESS_KEYRING;
printf("特殊密钥环:\n");
printf(" SESSION_KEYRING: %d\n", (int)session_ring);
printf(" USER_KEYRING: %d\n", (int)user_ring);
printf(" PROCESS_KEYRING: %d\n", (int)process_ring);
// 在会话密钥环中添加密钥
key1 = add_key("user", "session_key", key_data, strlen(key_data), session_ring);
if (key1 != -1) {
printf("✓ 在会话密钥环中添加密钥: %d\n", (int)key1);
} else {
printf("✗ 在会话密钥环中添加密钥失败: %s\n", strerror(errno));
return -1;
}
// 在用户密钥环中添加密钥
key2 = add_key("user", "user_key", key_data, strlen(key_data), user_ring);
if (key2 != -1) {
printf("✓ 在用户密钥环中添加密钥: %d\n", (int)key2);
} else {
printf("✗ 在用户密钥环中添加密钥失败: %s\n", strerror(errno));
}
// 尝试请求密钥(在不同密钥环中查找)
key_serial_t found_key;
// 在会话密钥环中查找
found_key = request_key("user", "session_key", NULL, 0);
if (found_key != -1) {
printf("✓ 在会话密钥环中找到密钥: %d\n", (int)found_key);
} else {
printf("✗ 在会话密钥环中未找到密钥\n");
}
// 在用户密钥环中查找
found_key = request_key("user", "user_key", NULL, 0);
if (found_key != -1) {
printf("✓ 在用户密钥环中找到密钥: %d\n", (int)found_key);
} else {
printf("✗ 在用户密钥环中未找到密钥\n");
}
// 清理密钥
if (key1 != -1) keyctl(KEYCTL_REVOKE, key1);
if (key2 != -1) keyctl(KEYCTL_REVOKE, key2);
return 0;
}
int main() {
return demo_keyring_operations();
}
示例4:密钥权限和安全特性 見出しへのリンク
#include <sys/types.h>
#include <keyutils.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
/**
* 密钥信息结构
*/
struct key_info {
key_serial_t serial;
char type[32];
char description[256];
uid_t uid;
gid_t gid;
key_perm_t perms;
int flags;
};
/**
* 获取密钥信息
*/
int get_key_info(key_serial_t key, struct key_info *info) {
struct keyctl_keyring_list list;
key_serial_t *key_ids;
long result;
memset(info, 0, sizeof(struct key_info));
info->serial = key;
// 获取密钥描述信息
char desc[256];
result = keyctl(KEYCTL_DESCRIBE, key, (unsigned long)desc, sizeof(desc));
if (result != -1) {
desc[result] = '\0';
printf("密钥描述: %s\n", desc);
}
return 0;
}
/**
* 演示密钥权限和安全特性
*/
int demo_key_security() {
key_serial_t key;
char secret_data[] = "Very secret data that should be protected";
printf("=== 密钥权限和安全特性演示 ===\n");
// 添加密钥(默认权限)
key = add_key("user", "secure_key", secret_data, strlen(secret_data),
KEY_SPEC_SESSION_KEYRING);
if (key == -1) {
printf("添加密钥失败: %s\n", strerror(errno));
printf("这在没有适当权限的环境中是常见的\n");
return 0; // 不返回错误,因为这可能是预期的
}
printf("成功添加安全密钥: %d\n", (int)key);
// 显示密钥安全特性
printf("\n密钥安全特性:\n");
printf(" 1. 内核空间存储 - 不会交换到磁盘\n");
printf(" 2. 访问控制 - 基于UID/GID的权限\n");
printf(" 3. 自动过期 - 可设置超时时间\n");
printf(" 4. 加密存储 - 敏感数据加密\n");
printf(" 5. 审计日志 - 访问会被记录\n");
// 设置密钥超时(30秒后自动删除)
if (keyctl(KEYCTL_SET_TIMEOUT, key, 30) == -1) {
printf("设置密钥超时失败: %s\n", strerror(errno));
} else {
printf("✓ 设置密钥30秒超时\n");
}
// 显示密钥权限信息
struct key_info info;
get_key_info(key, &info);
// 撤销密钥
if (keyctl(KEYCTL_REVOKE, key) == -1) {
printf("撤销密钥失败: %s\n", strerror(errno));
} else {
printf("✓ 密钥已安全撤销\n");
}
return 0;
}
int main() {
return demo_key_security();
}
示例5:实际应用示例 - 网络认证 見出しへのリンク
#include <sys/types.h>
#include <keyutils.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
/**
* 网络认证凭据结构
*/
typedef struct {
char username[64];
char password[128];
char server[128];
time_t timestamp;
} auth_credential_t;
/**
* 存储网络认证凭据
*/
int store_network_credentials(const char *server, const char *username,
const char *password) {
auth_credential_t cred;
key_serial_t key;
char key_desc[256];
// 构造凭据结构
strncpy(cred.username, username, sizeof(cred.username) - 1);
strncpy(cred.password, password, sizeof(cred.password) - 1);
strncpy(cred.server, server, sizeof(cred.server) - 1);
cred.timestamp = time(NULL);
// 构造密钥描述
snprintf(key_desc, sizeof(key_desc), "net_auth:%s@%s", username, server);
// 添加密钥到用户密钥环
key = add_key("user", key_desc, &cred, sizeof(cred), KEY_SPEC_USER_KEYRING);
if (key == -1) {
printf("存储网络凭据失败: %s\n", strerror(errno));
return -1;
}
printf("成功存储网络凭据到密钥: %d\n", (int)key);
printf(" 服务器: %s\n", server);
printf(" 用户名: %s\n", username);
return 0;
}
/**
* 获取网络认证凭据
*/
int get_network_credentials(const char *server, const char *username,
auth_credential_t *cred) {
char key_desc[256];
key_serial_t key;
long result;
// 构造密钥描述
snprintf(key_desc, sizeof(key_desc), "net_auth:%s@%s", username, server);
// 请求密钥
key = request_key("user", key_desc, NULL, 0);
if (key == -1) {
printf("未找到网络凭据: %s\n", strerror(errno));
return -1;
}
// 读取密钥数据
result = keyctl(KEYCTL_READ, key, (unsigned long)cred, sizeof(auth_credential_t));
if (result == -1) {
printf("读取网络凭据失败: %s\n", strerror(errno));
return -1;
}
printf("成功获取网络凭据\n");
printf(" 服务器: %s\n", cred->server);
printf(" 用户名: %s\n", cred->username);
printf(" 存储时间: %s", ctime(&cred->timestamp));
return 0;
}
/**
* 删除网络认证凭据
*/
int delete_network_credentials(const char *server, const char *username) {
char key_desc[256];
key_serial_t key;
// 构造密钥描述
snprintf(key_desc, sizeof(key_desc), "net_auth:%s@%s", username, server);
// 请求密钥
key = request_key("user", key_desc, NULL, 0);
if (key == -1) {
printf("未找到要删除的网络凭据\n");
return -1;
}
// 撤销密钥
if (keyctl(KEYCTL_REVOKE, key) == -1) {
printf("删除网络凭据失败: %s\n", strerror(errno));
return -1;
}
printf("成功删除网络凭据\n");
return 0;
}
/**
* 演示网络认证凭据管理
*/
int demo_network_auth() {
auth_credential_t cred;
printf("=== 网络认证凭据管理演示 ===\n");
// 存储凭据
printf("1. 存储网络凭据:\n");
if (store_network_credentials("example.com", "john_doe", "secret_password123") == 0) {
printf("✓ 凭据存储成功\n");
}
// 获取凭据
printf("\n2. 获取网络凭据:\n");
if (get_network_credentials("example.com", "john_doe", &cred) == 0) {
printf("✓ 凭据获取成功\n");
// 注意:实际应用中不要打印密码!
printf(" 密码长度: %zu 字符\n", strlen(cred.password));
}
// 删除凭据
printf("\n3. 删除网络凭据:\n");
if (delete_network_credentials("example.com", "john_doe") == 0) {
printf("✓ 凭据删除成功\n");
}
// 验证删除
printf("\n4. 验证凭据已删除:\n");
if (get_network_credentials("example.com", "john_doe", &cred) == -1) {
printf("✓ 凭据确实已被删除\n");
}
return 0;
}
int main() {
return demo_network_auth();
}
request_key 使用注意事项 見出しへのリンク
权限要求: 見出しへのリンク
- 用户权限: 通常需要适当的用户权限
- 内核支持: 需要内核编译时启用密钥管理子系统
- 安全策略: 某些安全策略可能限制密钥操作
错误处理: 見出しへのリンク
- ENOKEY: 密钥不存在
- EACCES: 权限不足
- ENOMEM: 内存不足
- EINVAL: 参数无效
安全考虑: 見出しへのリンク
- 密钥生命周期: 及时撤销不再需要的密钥
- 权限控制: 合理设置密钥访问权限
- 敏感数据: 避免在日志中记录密钥内容
- 超时设置: 为敏感密钥设置适当的超时时间
性能考虑: 見出しへのリンク
- 密钥查找: request_key可能触发回调,有性能开销
- 缓存利用: 合理利用密钥缓存机制
- 批量操作: 尽量减少密钥操作次数
常见密钥类型 見出しへのリンク
1. user类型: 見出しへのリンク
- 用途: 通用用户密钥
- 特点: 可以存储任意用户数据
- 权限: 基于用户ID的访问控制
2. logon类型: 見出しへのリンク
- 用途: 登录凭据存储
- 特点: 专为登录信息设计
- 安全性: 更严格的访问控制
3. trusted类型: 見出しへのリンク
- 用途: TPM(可信平台模块)密钥
- 特点: 硬件级安全存储
- 要求: 需要TPM硬件支持
4. big_key类型: 見出しへのリンク
- 用途: 存储大数据密钥
- 特点: 支持大容量数据
- 存储: 可能使用文件系统存储
总结 見出しへのリンク
request_key
是Linux密钥管理系统的重要接口,提供了:
- 安全的密钥存储: 内核级保护,避免敏感信息泄露
- 标准化的接口: 统一的密钥管理方式
- 灵活的权限控制: 基于UID/GID的细粒度访问控制
- 自动管理: 支持超时、撤销等生命周期管理
通过合理使用密钥管理系统,可以构建更安全的应用程序,避免将敏感信息存储在不安全的位置。在实际应用中,需要注意权限管理、错误处理和安全最佳实践。