• 走读OpenSSL代码从一张奇怪的证书说起(五)


    上次我们停在
    inl = ASN1_item_i2d(asn, &buf_in, it);
    调用处(注意是第2次中断),此时的调用栈为
    > openssl.exe!ASN1_item_verify
      openssl.exe!X509_verify
      openssl.exe!internal_verify
      openssl.exe!X509_verify_cert
      openssl.exe!check
      openssl.exe!verify_main
      openssl.exe!do_cmd
      openssl.exe!main

    我们目标锁定在函数唯一的入参asn上,只有它才可能引起返回参数错误
    查看上一层函数栈,代码上下文如下

    1 int X509_verify(X509 *a, EVP_PKEY *r)
    2  {
    3  return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF),a->sig_alg,
    4   a->signature,a->cert_info,r));
    5  }

    原来asn是参数a->cert_info,其类型为指向X509_CINF *的指针
    在VC自动变量查看窗口,查看a->cert_info的当前值,如下

    这里简单介绍下,cert_info 是指向结构X509_CINF(x509_cinf_st)的指针,而 X509_CINF 是 OpenSSL 内部表示证书信息的数据结构
    上图中cert_info展开的成员表示证书的某个属性,比如subject表示当前证书持有者的身份信息,等等

    再看serialNumber这个成员,它是asn1_string_st*类型,表示证书的序列号,见下面数据结构定义

    typedef struct x509_cinf_st
        {
        ASN1_INTEGER *version;        /* [ 0 ] default of v1 */
        ASN1_INTEGER *serialNumber;
        X509_ALGOR *signature;
        X509_NAME *issuer;
        X509_VAL *validity;
        X509_NAME *subject;
        X509_PUBKEY *key;
        ASN1_BIT_STRING *issuerUID;        /* [ 1 ] optional in v2 */
        ASN1_BIT_STRING *subjectUID;        /* [ 2 ] optional in v2 */
        STACK_OF(X509_EXTENSION) *extensions;    /* [ 3 ] optional in v3 */
        } X509_CINF;
    
    typedef struct asn1_string_st ASN1_INTEGER;
    
    typedef struct asn1_string_st
        {
        int length;
        int type;
        unsigned char *data;
        /* The value of the following field depends on the type being
         * held.  It is mostly being used for BIT_STRING so if the
         * input data has a non-zero 'unused bits' value, it will be
         * handled correctly */
        long flags;
        } ASN1_STRING;

    当前我们看到证书序列号长度为8(见length成员),内容(由data指出)如下
    0x006053c0  00 a2 42 4a a2 6a 51 df [cd cd fd fd fd fd ab ab] -- []中的内容不是序列号部分
    刚好比证书中的序列号 00 00 a2 42 4a a2 6a 51 df 少一个0x00字节

    现在基本可以肯定,正是这里被截断了一个字节,造成后面的一系列错误并最终导致证书验证不过
    我们可以做个实验,来验证 serialNumber 的 data 内容不对是造成后面错误的原因

    当程序第2次中断在 inl = ASN1_item_i2d(asn, &buf_in, it); 调用处时,我们将内存中序列号的内容临时修改为正确的值
       00 a2 42 4a a2 6a 51 df
    改为
    00 00 a2 42 4a a2 6a 51 df

    F10继续执行,再在 int main(int Argc, char *Argv[]) 中的第8行(注意是显示行)设断点

     1     /* ok, now check that there are not arguments, if there are,
     2      * run with them, shifting the ssleay off the front */
     3     if (Argc != 1)
     4         {
     5         Argc--;
     6         Argv++;
     7         ret=do_cmd(prog,Argc,Argv);
     8         if (ret < 0) ret=0;
     9         goto end;
    10         }

    按F5全速前进,屏幕上终于打出久违的
    openssl.cert.verify.error.pem: OK

    这说明,到此为止我们的猜测都是正确

    剩下的任务很简单,就是追踪为什么serialNumber记录的序列号出错
    而正是从这里开始,我们将进入证书解析Asn1parse命令的Kernel部分

  • 相关阅读:
    分组取最大值SQL 牛XXXX啊 我艹
    windows自带的可生成各种数据库连接字符串工具打开方法
    ashx.cs 读写session
    ASP.NET温故而知新学习系列之深度剖析ASP.NET架构—ASP.NET请求的处理过程(一)
    为什么从5000个数中找出10个最大的堆排序最快?
    net自带wsdl.exe的用法与参数说明
    负载均衡的集中实现方式
    18款 非常实用 jquery幻灯片图片切换
    MSSQL 导入用法总结 太方便了
    爱的无助
  • 原文地址:https://www.cnblogs.com/efzju/p/2443345.html
Copyright © 2020-2023  润新知