openssl中的一个bug--附带asn1的点点滴滴

简介:
openssl的源代码中有一个我自认为的bug,可能作者有意这么做,然而我却认为它是bug,起码我在验证证书序列号的号的时候,它出了问题。问题是这样的:用以下命令
openssl x509 -in somecert -serial -noout
可以输出一个证书的序列号,然而当该证书的序列号的第一个字节与数字0x80按位与之后的结果非0的话,那么就会将该数作为负数来对待,如果不信的话,那么你挑选几个序列号的第一个字节和0x80按位与非0的证书来用x509验证试一下,肯定会出现一个负数的序列号,这个错误相对不好重现,因为0x80只有一个位是1。
首先说一下openssl中的d2i和i2d操作,所谓的d就是der,所谓的i就是internal,d2i就是将证书的序列化格式化为内部的c语言数据结构格式,反过来亦然,这个看来令人不知所云的东西看起来是如此的简单,这正归功于asn结构的简洁(虽然它有很长的规范文档,我可没工夫看)。asn的结构基本就是(类型,长度,值)的三元组(我记得曾经在长春的一家公司搞过snmp,然后因为不愿加班离职了),而且是一个递归的嵌套结构,所谓的i2d其实并不需要什么内部运算,只需要将数据按照事先规定好的类型,长度,规则好就是了,d所表达的归根结底是一个字符串,这个字符串通过i结构体的类型长度进行规划,同时根据asn结构的内部含义进行分割,最终的d的形式就是一个char数组,这里面最根本的就是asn结构,另外具有语义意义的是i的结构体。首先看一下openssl中的普遍的结构ASN1_STRING,别的不管,asn-interger就是这个结构定义的:
typedef struct asn1_string_st {
    int length;
    int type;
    unsigned char *data;
    long flags;
} ASN1_STRING;
但是再看看c2i_ASN1_INTEGER这个函数:
ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long len) 
{
    ASN1_INTEGER *ret=NULL;
    const unsigned char *p, *pend;
    unsigned char *to,*s;
    int i;
    if ((a == NULL) || ((*a) == NULL)) {
        if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL);
        ret->type=V_ASN1_INTEGER;
    } else
        ret=(*a);
    p= *pp;
    pend = p + len;
    s=(unsigned char *)OPENSSL_malloc((int)len+1);
    to=s;
    if(!len) {
        ret->type=V_ASN1_INTEGER;
    } else if (*p & 0x80) {
        ret->type=V_ASN1_NEG_INTEGER;
        ...
    } else {
        ...
    }
...
err:
...
    return(NULL);
}
由于asn完全不依赖外部结构,因此哪怕一个数据结构的类型都是由asn-interger定义的,如果一个证书的serial是由一个asn-interger表示的话,那么这个asn-interger的type也是一个asn-interger(一切都是递归的),于是看看上面的代码,else if (*p & 0x80)这一句,如果一个*p和0x80按位与不为0的话,那么该数就会被认为是负数,这是不应该的啊,事实是,只有一个asn-interger的type字段和0x80按位与不为0才能被认为是负数,于是这段代码是一段很可悲的代码,我的改进如下:

1.添加一个first_malloc变量,只有在一个变量被malloc的时候才置1,而只有在first_malloc置1的时候才验证*p和0x80按位与的情况;2.将ret->type=V_ASN1_INTEGER这个设置放到函数的最后,然后只有在ret->type为0的情况下才验证*p其与0x80按位与的值,这个策略也正和acl的策略一致,可以完全解除这个可悲的局面。



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271998

相关文章
|
6月前
|
运维 Ubuntu Linux
GLIBC修复笔记(文末送书)
GLIBC修复笔记(文末送书)
GLIBC修复笔记(文末送书)
|
9月前
|
Shell Go 网络安全
openssl 证书生成学习笔记(go 1.15版本以上) | 周末学习
golang 1.15+版本上,用 gRPC通过TLS实现数据传输加密时,会报错证书的问题
114 0
openssl 证书生成学习笔记(go 1.15版本以上) | 周末学习
|
边缘计算 JSON Kubernetes
k8s+kubeedge+sedna安装全套流程+避坑指南+解决办法
最近在学习边缘计算要用到kubeedge,安装了好多次总会遇到各种各样的问题,因此在这里一一列出,以方便下次安装。则里面可能出错的地方太多,如果有问题,请私信联系。
1793 0
|
Ruby Perl
Cocoapods迄今为止的安装使用方法,更新下网上众多有些过时的操作
Cocoapods迄今为止的安装使用方法,更新下网上众多有些过时的操作
843 0
|
程序员 Python Windows
全网首发:安装Python(或其他软件)出现0x80072f7d错误的解决办法
全网首发:安装Python(或其他软件)出现0x80072f7d错误的解决办法
436 0
|
Ubuntu Linux Shell
Linux安装及管理程序:rpm软件包、源代码安装( 时间最美的地方,就是让你我成为了我们)(一)
Linux安装及管理程序:rpm软件包、源代码安装( 时间最美的地方,就是让你我成为了我们)(一)
306 0
Linux安装及管理程序:rpm软件包、源代码安装( 时间最美的地方,就是让你我成为了我们)(一)
|
Linux Apache Windows
Linux安装及管理程序:rpm软件包、源代码安装( 时间最美的地方,就是让你我成为了我们)(二)
Linux安装及管理程序:rpm软件包、源代码安装( 时间最美的地方,就是让你我成为了我们)(二)
111 0
Linux安装及管理程序:rpm软件包、源代码安装( 时间最美的地方,就是让你我成为了我们)(二)
|
缓存 Linux 数据库
Linux安装软件时90%的人会遇到这个报错,如何解决?
Linux安装软件时90%的人会遇到这个报错,如何解决?
154 0
Linux安装软件时90%的人会遇到这个报错,如何解决?
|
存储 数据可视化 Linux
PHP 依赖镜像出问题后,阿里工程师的一顿“神操作“令人叫绝!
上个月,PHP开发者在网上纷纷反映出现 Composer 镜像无法访问的问题。阿里云内部一位 90 后工程师顾咏连夜开工排查,快速解决问题后,他在问题群里收到了一大波来自用户的红包。顾咏最后谢绝了红包,接受了阿里技术的邀请,来聊一聊这次事件问题背后的技术。
14706 0
PHP 依赖镜像出问题后,阿里工程师的一顿“神操作“令人叫绝!