X509证书验证研究(2)——GDB跟踪

    根据SSL流程,断点可以打在ssl3_get_server_certificate函数上。
    本函数中,通过一个for循环把获取到的证书存放到一个证书栈sk上,本次跟踪,
只有一个server证书。此后进入 ssl_verify_cert_chain 去验证证书链。
    ssl_verify_cert_chain 先获取一个 verify_store ,此时 verify_store = s->ctx->cert_store
这个还没有研究,后面再看。
    ssl_verify_cert_chain函数从sk中取出第一个证书,即server证书,创建一个X509_STROE_CTX ctx
并通过X509_STORE_CTX_init进行初始化:
    ctx->ctx  = verify_store;
    ctx->cert = x; //server的证书
    ctx->untrusted = sk; //server所在的sk
    初始化了需要认证的ctx->param,并初始化了ctx中的一系列check函数,本例中都是用的默认。
    回到ssl_verify_cert_chain函数中后,又对ctx做了一系列的初始化。
    然后调用 X509_verify_cert 进行验证。
    需要知道关注的是,此时 ctx->param的设置:purpose被设置为 X509_PURPOSE_SSL_SERVER,
trust 被设置为 X509_TRUST_SSL_SERVER ,depth 被设置为 100.

    
    下面是主要函数 X509_verify_cert 的分析
    创建ctx->chain并把ctx->cert放到ctx->chain中。然后在一个for循环中对证书做验证操作。
让我不太理解的是,控制for循环的参数 num = 1,但这里是一个循环,其意义何在?需要深入内部
继续分析。
    for循环中首先对验证深度校验,然后调用cert_self_sign查看证书是否是自签名。如果是自签名
则跳出for循环。

    cert_self_sign-->X509_check_purpose-->x509v3_cache_extensions(处理扩展信息)
    由此可见cert_self_sign不单单去验证是否自签名,还处理了一些扩展项。。。函数功能不唯一。
    这个函数中先生成了服务端证书的fingerprint,放在x->sha1_hash中。
    由于我的server证书中有以下扩展项:
    Authority Information Access、X509v3 Authority Key Identifier、X509v3 Basic Constraints、
    X509v3 CRL Distribution Points、X509v3 Extended Key Usage、X509v3 Key Usage、
    X509v3 Subject Key Identifier
    因此中解析时,x->ex_flags被打上以下标记:EXFLAG_BCONS EXFLAG_KUSAGE EXFLAG_XKUSAGE 
    EXFLAG_SET
    同时以下值被赋值:
    x->ex_kusage = 160
    x->ex_exkusage = XKU_SSL_CLIENT | XKU_SSL_SERVER
    x->skid
    x->akid
    x->crldp
    最终返回到cert_self_sign是通过查看标记来判断的,这里没有打标记,因此不是自签名。
    
    此后有一个判断 if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) ,搜了下该宏的调用处,
是通过命令行参数   -trusted_first 来设置的。搜了下,也没看到这个说明。在这里我们不会走到
此处。

    下面是 if (ctx->untrusted != NULL) 这里的判断。在这里会先用find_issuer来找颁发者。从这里
可以看到num有变更,可以解释上面的循环的问题。即如果ctx->untrusted 这里存的是一个证书链,那么
find_issuer 是可能返回值的,那样就会继续向上找颁发者。本例中,由于只有一个证书,因此这里不会
继续循环处理。

    然后进入do{}while(retry),结合代码的伪代码如下:
    do {
        取出ctx->chain中的最后一个证书x(ctx->chain可能是个证书链)
        if (x是自签名证书) //这里没走到,从代码流程里大概写了下,未必正确,因为从代码逻辑看比较混乱
        {
            if (ctx->chain中只有1个证书)
            {
                判断颁发者信息之类的。
            }
            else
            {
                取出最后的自签名证书x
            }
        }
        for (;;) {
            如果发现证书自签名或者认证深度超出预期则跳出循环。
            通过 ctx->get_issuer (X509_STORE_CTX_get1_issuer) 查找证书的颁发者。构造认证链。
        }
        
        上面的for循环还是什么都没有做,继续走 check_trust函数,这里检查是否有在信任链
        中的证书,仍然返回没有。
        
        if (三个判断) {这里仍然么有处理}
    }while(retry)
    
    这里单独研究一下 X509_STORE_CTX_get1_issuer 这个函数。
    先通过 X509_get_issuer_name 获取 issuer_name ,存到xn中,
    然后调用 X509_STORE_get_by_subject ,这个函数通过 subject 查找X509_OBJECT ,这里会到给定
的dir下和默认dir下找,但是都找不到。这是实际是想从store里找,但是没找到。

    调用 check_chain_extensions 检查扩展项 等等。最后进入internal_verify 。。奇怪,没有验证到
    
    这是因为命令用法不对,指定CApath时,路径存储的证书名字需要使用hash.0的方式。
[root@openssl cacerts]# openssl x509 -hash -in root-ca.crt -noout
5ed7b970
[root@openssl cacerts]# openssl x509 -hash -in sub-ca.crt -noout
c2eb42c3
    把证书重命名:
[root@openssl cacerts]# ll
total 32
-rw-r--r--. 1 root root 6884 Mar  3 15:43 5ed7b970.0
-rw-r--r--. 1 root root 8187 Mar  3 15:43 c2eb42c3.0
-rw-r--r--. 1 root root 6884 Mar  2 16:08 root-ca.crt
-rw-r--r--. 1 root root 8187 Mar  2 16:08 sub-ca.crt

    然后使用
[root@openssl bin]# ./openssl s_client -ssl3 -CApath /home/demoCA/cacerts/
CONNECTED(00000003)
depth=2 C = CN, O = Certusnet, CN = Root CA
verify return:1
depth=1 C = CN, O = Certusnet, CN = Sub CA
verify return:1
depth=0 C = CN, ST = Some-State, O = Certusnet, CN = Server
verify return:1
---
Certificate chain
 0 s:/C=CN/ST=Some-State/O=Certusnet/CN=Server
   i:/C=CN/O=Certusnet/CN=Sub CA
 1 s:/C=CN/O=Certusnet/CN=Sub CA
   i:/C=CN/O=Certusnet/CN=Root CA
 2 s:/C=CN/O=Certusnet/CN=Root CA
   i:/C=CN/O=Certusnet/CN=Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEszCCApugAwIBAgIRAPz0LWzyAEf7U/3XDFhLyFowDQYJKoZIhvcNAQELBQAw
MjELMAkGA1UEBhMCQ04xEjAQBgNVBAoMCUNlcnR1c25ldDEPMA0GA1UEAwwGU3Vi
IENBMB4XDTE2MDMwMjA4NTE0MVoXDTE3MDMwMjA4NTE0MVowRzELMAkGA1UEBhMC
Q04xEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAoMCUNlcnR1c25ldDEPMA0G
A1UEAwwGU2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5Awc0N9sd
LSxbWZShMUie5f662MTVDTYzV2eImSdsELtD9eTdJe/ZLrZN2fL/wUj1aRFt//zT
4Q7hNJvC3diVJ3tyn6DD8PD+YQfeRVnZgIFB1b3nM6I5qftb72e3IO6LvFMwF0jE
VxvRYUm6hO01rU0iaMqtqVxO6cF5gs+H3QIDAQABo4IBMTCCAS0wdQYIKwYBBQUH
AQEEaTBnMDIGCCsGAQUFBzAChiZodHRwOi8vc3ViLWNhLmNlcnR1c25ldC5jb20v
c3ViLWNhLmNydDAxBggrBgEFBQcwAYYlaHR0cDovL29jc3Auc3ViLWNhLmNlcnR1
c25ldC5jb206OTA4MTAfBgNVHSMEGDAWgBTQJbdgHNl+Hd9tKj+wOCeuQcYaCzAM
BgNVHRMBAf8EAjAAMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9zdWItY2EuY2Vy
dHVzbmV0LmNvbS9zdWItY2EuY3JsMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDATAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0OBBYEFHBd8lxWlnkeFhw+hxnVkqoT
N3NbMA0GCSqGSIb3DQEBCwUAA4ICAQB9LuXZteSc4E+nHHpYjH2vRJtYlCGV9jjh
bIbFSvJxTU7/Tx8JjcQavm9KtUGoIcMsZ2VELpVXOzW8MlM0yXlQ8bPhZNyVtk6R
n4J3sNtPGJ7vX6aSZP0ba34ObDSd6VSHlXqoa3UaIHCE3oogoGKHfkU5/pn6wAXr
77ebhkLjcBhV4vilrq+xWvABtOB3O/3wI0Yn28HnXWtlwN2XROfK/7sSPDQahKaf
yStY8exY6RRGhzUuNbEbW1AIsuXqeM4KcYYAKwlzFUt7+1/OU7QMpN5F29oasSgS
8F3yTttsx9V6W5buqzDcICF+zY4ssX4EAsIcY2zNOsHC2SojNELFtabKFyXijRKV
VIQoTkic07KBQxrJG6mKanxL1Q8h+2MDt7kbxJz1NxXuQGV4smxMN2ZBUU1Ufnnr
nrjxnZZfBCR0Zt2OjQrTWv3tkF6GNhS1wufh4n9A1JcGr+xfzVP0O9FlAhVtauNS
DwjgAvQhjjemCMowMDTVJei9sCRZjZtQberA4DfGOReTjukMrR+QMaqRx4TfYpqn
mVYyEUPxFau7pJXFtYYPDLOwPvJhK0nM2fC72E4DOHzRMSR9fLUrJXC8q8wK/iKJ
76F6vJcCisGmzPJeltqJvB3KvrKa/at0wkrtym2LNp6j5shhwoXhBh693y0gNLTL
GzcQpVl37Q==
-----END CERTIFICATE-----
subject=/C=CN/ST=Some-State/O=Certusnet/CN=Server
issuer=/C=CN/O=Certusnet/CN=Sub CA
---
No client certificate CA names sent
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 4624 bytes and written 308 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : SSLv3
    Cipher    : ECDHE-RSA-AES256-SHA
    Session-ID: BEB2B5AFCDAAD0B84DEF8F157F61B2FCC7C362FFA5B699B1A0A4E47F1827304A
    Session-ID-ctx: 
    Master-Key: 28D10D8B8FE3702C5529A9F0F13323FC599412E1291C336827921B9427522A613A917FA68AED9DBBCA1F9E8E167FB9F6
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1457003801
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

这把可以看到Verfiy return code是正常的了,是一个自签名证书链。
internal_verify 里面依次验证root-ca、sub-ca、server的证书,最后ok。
需要注意 ctx->get_issuer 里去找颁发者,这里会到知道的目录里面通过hash生成名字去找。
发布了54 篇原创文章 · 获赞 1 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/xingyeping/article/details/50791039