当前位置: 首页 > news >正文

openssl签名报错

在调用RSA_private_encrypt函数时遇到如下报错。

0:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:309:Type=X509
0:error:2406C06E:random number generator:RAND_DRBG_instantiate:error retrieving entropy:crypto/rand/drbg_lib.c:335:
0:error:2406B072:random number generator:RAND_DRBG_generate:in error state:crypto/rand/drbg_lib.c:588:
0:error:2406C06E:random number generator:RAND_DRBG_instantiate:error retrieving entropy:crypto/rand/drbg_lib.c:335:
0:error:2406B072:random number generator:RAND_DRBG_generate:in error state:crypto/rand/drbg_lib.c:588:
0:error:04088003:rsa routines:RSA_setup_blinding:BN lib:crypto/rsa/rsa_crpt.c:155:
0:error:04066044:rsa routines:rsa_ossl_private_encrypt:internal error:crypto/rsa/rsa_ossl.c:297:

openssl库版本为1.1.1Q。

$ openssl version
OpenSSL 1.1.1q 

查看openssl源码,随机数生成器(DRBG)在获取熵时遇到了错误,错误码RAND_R_ERROR_RETRIEVING_ENTROPY。

int RAND_DRBG_instantiate(RAND_DRBG *drbg,const unsigned char *pers, size_t perslen)
{if (drbg->get_entropy != NULL)entropylen = drbg->get_entropy(drbg, &entropy, min_entropy,   min_entropylen, max_entropylen, 0);if (entropylen < min_entropylen || entropylen > max_entropylen) {RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY);goto end;}

将程序与openssl库做静态链接,放到其它机器上运行一切正常,排除了openssl库的问题,应当是系统问题。

# gcc rsasign.c -L/lib/x86_64-linux-gnu/ libssl.a  libcrypto.a -ldl -lpthread 

使用strace调试,发现问题出在getrandom函数,出错的机器上提示函数未实现。

$ strace ./rsasign
...
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom(0x7f0366004398, 8, GRND_NONBLOCK) = -1 ENOSYS (Function not implemented)
brk(NULL)                               = 0x7f036633b000
brk(0x7f036635c000)                     = 0x7f036635c000

单独写一个getrandom.c测试程序:

#include<stdio.h>
#include <errno.h>
#include <string.h>
#define _GNU_SOURCE        /* See feature_test_macros(7) */
#include <unistd.h>
#include <sys/syscall.h>   /* For SYS_xxx definitions */
#define __NR_getrandom 318int main(int argc, void *argv[])
{unsigned char buf[32];ssize_t result = syscall(__NR_getrandom, buf, sizeof(buf), 0);if (result == -1) {printf("getrandom failed:%s\n", strerror(errno));return 1;}for (int i = 0; i < sizeof(buf); i++)printf("%02x ", buf[i]);printf("\n");return 0;
}

运行测试程序,同样有如下报错:

$ gcc getrandom.c -o rand
$ ./rand
getrandom failed:Function not implemented

其它正常运行的设备上,如下信息,可以正常获取到随机数:

$ ./rand
32 69 78 58 4b c8 8b a4 3d c5 11 95 b6 de 00 29 4f 6f 9e 02 0b 66 28 78 f9 70 e4 53 62 1b 64 e6 

openssl文件crypto/rand/rand_unix.c中函数syscall_random代码如下,linux内核在3.17版本之后开始支持getrandom系统调用。出问题的系统内核为3.10,还不能支持getrandom。

/* syscall_random(): Try to get random data using a system call* returns the number of bytes returned in buf, or < 0 on error.*/
static ssize_t syscall_random(void *buf, size_t buflen)
{/* Linux supports this since version 3.17 */
#  if defined(__linux) && defined(__NR_getrandom)return syscall(__NR_getrandom, buf, buflen, 0);

另外,对于linux系统,随机数还可以从以下设备文件中获取。

#  define DEVRANDOM "/dev/urandom", "/dev/random", "/dev/hwrng", "/dev/srandom"

在由设备文件读取随机数之前,函数wait_random_seeded等待设备有足够的种子(seed)。

size_t rand_pool_acquire_entropy(RAND_POOL *pool)
{
#   if defined(OPENSSL_RAND_SEED_DEVRANDOM)if (wait_random_seeded()) {size_t bytes_needed;unsigned char *buffer;bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); i++) {ssize_t bytes = 0; int attempts = 3;    /* Maximum number of consecutive unsuccessful attempts */const int fd = get_random_device(i);if (fd == -1) continue;while (bytes_needed != 0 && attempts-- > 0) {buffer = rand_pool_add_begin(pool, bytes_needed);bytes = read(fd, buffer, bytes_needed);

从内核4.8(DEVRANDOM_SAFE_KERNEL)开始,当/dev/random(DEVRANDOM_WAIT)可读时,不确保设备/dev/urandom被正确的Seed。这里使用uname获取系统的内核版本,如果版本号大于4.8,返回0。

否则,检查/dev/random是否可读,来判断/dev/urandom是否正确的Seed。

static int wait_random_seeded(void)
{static int seeded = OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID < 0;static const int kernel_version[] = { DEVRANDOM_SAFE_KERNEL };if (!seeded) {     /* See if anything has created the global seeded indication */if ((shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, 0)) == -1) {/** Check the kernel's version and fail if it is too recent.* Linux kernels from 4.8 onwards do not guarantee that* /dev/urandom is properly seeded when /dev/random becomes* readable.  However, such kernels support the getentropy(2)* system call and this should always succeed which renders* this alternative but essentially identical source moot.*/if (uname(&un) == 0) {kernel[0] = atoi(un.release);p = strchr(un.release, '.');kernel[1] = p == NULL ? 0 : atoi(p + 1);if (kernel[0] > kernel_version[0] || (kernel[0] == kernel_version[0] && kernel[1] >= kernel_version[1]))return 0;}/* Open /dev/random and wait for it to be readable */if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) {if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) {FD_ZERO(&fds);FD_SET(fd, &fds);while ((r = select(fd + 1, &fds, NULL, NULL, NULL)) < 0 && errno == EINTR);} else {while ((r = read(fd, &c, 1)) < 0 && errno == EINTR);

出现问题的系统使用的内核为3.10,但是uname系统调用获取到的内核版本为5.16,导致了问题的产生。修复uname的问题,获取内核版本号为实际的版本号3.10之后,问题得到解决。

命令strace跟踪,不再调用getrandom,而是使用了urandom来获取随机数。

$ strace ./rsasign
open("/dev/urandom", O_RDONLY|O_NOCTTY|O_NONBLOCK) = 3
http://www.lryc.cn/news/467387.html

相关文章:

  • 如何在不使用 VPN 的情况下通过 SOCKS 隧道安全地路由 Web 流量
  • android openGL ES详解——缓冲区VBO/VAO/EBO/FBO
  • 计算机网络——传输层服务
  • gin入门教程(8):渲染与静态文件
  • Fast Simulation of Mass-Spring Systems in Rust 论文阅读
  • javaWeb项目-ssm+vue志愿者招募网站功能说明介绍
  • Selenium + Titanium代理获取请求的接口数据
  • ELK Stack与Graylog:强大的日志分析和可视化工具
  • 安全见闻(6)——开阔眼界,不做井底之蛙
  • GRU神经网络理解
  • Windows 10、Office 2016/2019 和 PPTP 和 L2TP协议即将退役,企业应尽早做好准备
  • 论文阅读:Guided Linear Upsampling
  • 深度图和RGB图对齐
  • 滑动窗口与TCP的缓冲区(buff)的关系
  • 一款好用的搜索软件——everthing(搜索比文件资源管理器快)
  • C#WPF的App.xaml启动第一个窗体的3种方式
  • 【JAVA毕设】基于JAVA的酒店管理系统
  • 聚类--机器学习西瓜书阅读笔记(六)
  • OpenHarmony(1)开发环境搭建
  • Triton服务在ASR语音识别系统中的实现
  • Typora一款极简Markdown文档编辑、阅读器,实时预览,所见即所得,多主题,免费生成序列号!
  • python机器人编程——用python调用API控制wifi小车的实例程序
  • 面试学习整理-线程池
  • Debian会取代CentOS成为更主流的操作系统吗?
  • 网络安全领域推荐证书介绍及备考指南
  • SpringBoot项目ES6.8升级ES7.4.0
  • 深度学习 之 模型部署 使用Flask和PyTorch构建图像分类Web服务
  • MFC工控项目实例二十六创建数据库
  • springmvc源码流程解析(一)
  • 【论文阅读】SRGAN