linux下使用openssl检测PE文件数字签名的证书是否有效

linux下使用openssl检测PE文件数字签名的证书是否有效,第1张

第一个坑: 有效期

windows在判断证书是否有效时不检测证书的有效期, 即使该证书超过有效期好几年了, 只要没有被吊销, 微软仍然认为它是有效的. 但在 openssl 提供的 X509_verify_cert 函数会验证证书的有效期, 因此需要注释掉验证有效期的那部分代码并重新编译 openssl...

OK, 从 openssl 官网 上下载最新的版本, 好吧, 现在还是刚刚修复 Heartbleed 漏洞的 1.0.1g 版本...

下载, 解压, 看下 INSTALL 文档, 先试试可以编译不:

./config

make

运伏梁孝缺稿气不错, 不用安装什么依赖直接编译成功. 将代码根目录产生的 libcrypto.a 添加到项目中测试渣衡下, OK, 可以使用, 下面开始折腾了~

在 crypto/x509/x509_vfy.c 的 153 行找到 X509_verify_cert 函数(在线查看), 局部变量 ok 缓存每一步验证是否通过, 它依次调用了:

check_issued

check_chain_extensions

check_name_constraints

check_trust

check_revocation

internal_verify

check_policy

其中 internal_verify (在线查看)验证了证书的有效期, 进入这个函数, 在 1654 行找到这个代码:

ok = check_cert_time(ctx, xs)

if (!ok)

goto end

看看 check_cert_time 函数, 确认是检查 notBefore 和 notAfter, 因此将上面三行代码注释掉, 验证证书时就不会检测有效期了.

然后就是重新编译 openssl, 将 libcrypto.a 集成到项目里了~

第二个坑: unhandled critical extension

搜索了下, 在 openssl 官网上找到这个:

-ignore_critical

Normally if an unhandled critical extension is present which is not supported by OpenSSL the certificate is rejected (as required by RFC5280). If this option is set critical extensions are ignored.

原来是当openssl遇到证书中有它不支持的 未处理的关键扩展(unhandled critical extension ?) 时, 它会拒绝加载该证书.

再搜索下 -ignore_critical, 在 verify.c 中找到如下代码片段:

else if (strcmp(*argv,"-ignore_critical") == 0)

vflags |= X509_V_FLAG_IGNORE_CRITICAL

然后再使用 X509_STORE_set_flags 函数设置标志位:

X509_STORE *ctx

...

X509_STORE_set_flags(ctx, vflags)

即可.

第三个坑: certificate signature failure

这个坑填不上了, openssl 说:

7 X509_V_ERR_CERT_SIGNATURE_FAILURE: certificate signature failure

the signature of the certificate is invalid.

在windows下导出证书文件, 直接用 openssl 验证, 在加载证书就会出错, PEM_read_bio_X509 返回为空....

第四个坑: A certificate was explicitly revoked by its issuer.

A certificate was explicitly revoked by its issuer. 是 Sysinternals 提供的工具sigcheck.exe 的检测结果, 把文件拎出来一看, 证书真的被撤销了...

OK, 只好根据证书上的 CRL Distribution Point(CRL 分发点) 提供的 URL 下载 撤销证书列表 文件, 然后在调用 X509_verify_cert 验证证书链之前, 设置填充被撤销的证书列表:

X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl)// 读取被撤销的证书列表

STACK_OF(X509_CRL) *sk_X509_CRL_new_null()

#define sk_X509_CRL_push(st, val) SKM_sk_push(X509_CRL, (st), (val)) // sk_X509_CRL_push(STACK_OF(X509_CRL) *crls, X509_CRL *crl)

void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c, STACK_OF(X509_CRL) *sk) // 设置被撤销的证书列表

同时, 也要设置检查被撤销证书列表的标志位 X509_V_FLAG_CRL_CHECK, 然后再调用X509_verify_cert 验证证书链即可.

填了第四个坑后又引起了第五个坑(如何获取撤销证书列表)和第六个坑(设置检测撤销证书列表的标识位后, 如果该证书没有撤销证书列表则直接报错)...

第五个坑: 获取撤销证书列表文件

证书上的 CRL Distribution Point(CRL 分发点) 属于扩展属性, 在 PKCS #7: Cryptographic Message Syntax V1.5 上没有相关介绍.

在 StackOverflow 上找到这个问答 Openssl - How to check if a certificate is revoked or not, 其中第二个回答说 CRL 是在 RFC 5280 中定义的, 除了证书中附带被撤销的证书列表以外还有使用 OCSP 协议的, 即使证书撤销列表也分为使用 URL分发点和 LDAP DNs(???)提供的, 目前先考虑使用 URL 作为 CRL分发点 的情况吧.

然而 openssl 没有提供直接获取 CRL 分发点 URL 的API, 那个回答说 Apache 的 mod_ssl 模块有本地 CRL 和 OCSP 检测的实现代码, 但没有说明哪里有检测使用 URL 作为 CRL分发点 的实现方法.

然后又在 frank4dd.com上找到这个代码 certextensions.c, 他给出了一个如何使用 openssl 从 X.509v3 版本的证书文件中提取扩展内容的示例程序, 太感谢 Frank4DD 这位仁兄了~~~

到这里后, 可以直接使用他的示例程序, 根据关键字 Full Name 和 URI 定位 CRL 分发点 的 URL, 也可以看看 openssl 是如何提取这个 URL 的, 然后自己实现一个接口.

如果自作孽使用第二种方法的话, 就编译个 debug 版的 openssl 库, 然后调试跟进X509V3_EXT_print 函数, 一步一步的向下走, 直到走到 GENERAL_NAME_print 函数, 这里就是终点了...然后就知道了 CRL 分发点 的 URL 的编号为 6, 也就是 GEN_URI, 直接取结果吧.

第六个坑: CRL有效期

在windows环境下每次查看PE文件的数字签名时, windows 都会从 CRL分发点 下载吊销证书列表做验证, 一般来说, 每个 CRL的有效期是非常短的, 大概只有 5~20 天的有效期吧, 然而我们不可能像 windows 一样每次查看数字签名时就从 CRL分发点 下载最新的吊销列表.

另外, windows 遇到过期的 CRL 时不会产生证书链无效的结果, 但 openssl 在遇到过期的 CRL 时就会导致证书链验证失败, 因此在加载和验证 CRL 时, 要忽略 CRL 的有效期.

分析 openssl 源代码, X509_verify_cert 调用 check_revocation , 之后调用 check_cert , 然后再调用 check_crl , 在这个函数里有检测 CRL 有效期的代码:

if (!(ctx->current_crl_score &CRL_SCORE_TIME))

{

ok = check_crl_time(ctx, crl, 1)

if (!ok)

goto err

}

将其注释掉即可忽略检测 CRL 有效期.

第七个坑: CRL 列表为空导致 openssl 认为没有加载 CRL

9 初始化顺序

10 证书名: key_id

PE文件格式

1.PE文件的含义

PE文件的意思是Portable Executable(可移植,可执行),它是win32可执行文件的标准格式.它的一些特性继承unix的COFF文件格式,同时保留了与旧版MS-DOS和WINDOWS的兼容.其可移植可执行意味着是跨win32平台的.

2.PE文件的层次结构

PE文件最前面紧随DOS MZ文件头侍返的是一个DOS可执行文件(Stub).这使得PE文件成为一个合法的MS-DOS可执行文件.DOS MZ文件头后面是一个32位的PE文件标志0x50450000(IMAGE_NT_SIGNATURE),即PE00.接下来的是PE的映像文件头,包含的信息有该程序的运行平台,有多少个节,文件链接的时间,文件的命名格式.后面还紧跟一个可选映像头,包含PE文件的逻辑分布信息,程序加载信息,开始地址,保留的堆栈数量,数据段大小等.可选头还有一个重要的域,称为:数据目录表"的数组,表的每一项都是指向某一节的指针.可选映像头后面紧跟的是节表和节.节通过节表来实现索引.实际上,节的内容才是真正执行的数据和程序.每一个节都有相关的标志.每一个节会被一个或多个目录表指向,目录表可通过可选头的"数据目录表"的入口找到.就像输出函数表或基址重定位表.也存在没有目录表指向的节.

3.PE文件层次解释

A.DOS STUB和DOS头

DOS插桩程序在大多数情况下由汇编器/编译器自动产生.通常它调用INT 21H服务9来显示上述字符串.可以通过IMAGE_DOS_HEADER结构来识别一滚孙个合法的DOS头.这个结构的头两个字节肯定是"MZ".可通过该结构的e_lfanew成员来找到PE文件的开始标志.MS-DOS头部占据了PE文件的头64个字节.在微软的WINNT.H中可以找到其内容结构的描述.

B.PE文件头

在DOS STUB后是PE文件头(PE header).PE文件头是PE相关结构IMGAE_NT_HEADERS的简称,即NT映像头,存放PE整个文件信息发布的重要字段,包含了PE装载器用到的重要域.执行体在 *** 作系统中执行时,PE装载器老备饥将从DOS MZ头中找到PE头文件的起始偏移量e_lfanew,从而跳过DOS STUB直接定位真正的PE文件.它由3部分组成:

(1)PE文件标志(4H字节)

PE文件标志0x50450000即PE00,标志着NT映像头的开始,也是PE文件中与windows有关内容的开始.

(2)映像文件(14H字节)

是NT映像文件的主要部分,包含PE文件的基本信息

(3)可选映像头

包含PE文件的逻辑分布信息.

C.节表

节表其实是紧跟NT映像文件的一个结构数组.其成员数目由映像文件头结构NumberOFSectios域的值来决定.

D.节

PE文件的真正内容划分为块,称之为节.节的划分基于各组数据的共同属性.惟有节的属性设置决定了节的特性和功能.典型的windows NT应用程序可以具有9个节:.texr,.bss.rdata,.data,.rsrc,edata,idata,pdata,.debug


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12142691.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存