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 使用注意事项 链接到标题

权限要求: 链接到标题

  1. 用户权限: 通常需要适当的用户权限
  2. 内核支持: 需要内核编译时启用密钥管理子系统
  3. 安全策略: 某些安全策略可能限制密钥操作

错误处理: 链接到标题

  1. ENOKEY: 密钥不存在
  2. EACCES: 权限不足
  3. ENOMEM: 内存不足
  4. EINVAL: 参数无效

安全考虑: 链接到标题

  1. 密钥生命周期: 及时撤销不再需要的密钥
  2. 权限控制: 合理设置密钥访问权限
  3. 敏感数据: 避免在日志中记录密钥内容
  4. 超时设置: 为敏感密钥设置适当的超时时间

性能考虑: 链接到标题

  1. 密钥查找: request_key可能触发回调,有性能开销
  2. 缓存利用: 合理利用密钥缓存机制
  3. 批量操作: 尽量减少密钥操作次数

常见密钥类型 链接到标题

1. user类型: 链接到标题

  • 用途: 通用用户密钥
  • 特点: 可以存储任意用户数据
  • 权限: 基于用户ID的访问控制

2. logon类型: 链接到标题

  • 用途: 登录凭据存储
  • 特点: 专为登录信息设计
  • 安全性: 更严格的访问控制

3. trusted类型: 链接到标题

  • 用途: TPM(可信平台模块)密钥
  • 特点: 硬件级安全存储
  • 要求: 需要TPM硬件支持

4. big_key类型: 链接到标题

  • 用途: 存储大数据密钥
  • 特点: 支持大容量数据
  • 存储: 可能使用文件系统存储

总结 链接到标题

request_key 是Linux密钥管理系统的重要接口,提供了:

  1. 安全的密钥存储: 内核级保护,避免敏感信息泄露
  2. 标准化的接口: 统一的密钥管理方式
  3. 灵活的权限控制: 基于UID/GID的细粒度访问控制
  4. 自动管理: 支持超时、撤销等生命周期管理

通过合理使用密钥管理系统,可以构建更安全的应用程序,避免将敏感信息存储在不安全的位置。在实际应用中,需要注意权限管理、错误处理和安全最佳实践。