X.509系列(一):X.509 v3格式下的证书 您所在的位置:网站首页 奔驰车载数据线接口在哪里啊 X.509系列(一):X.509 v3格式下的证书

X.509系列(一):X.509 v3格式下的证书

2022-11-11 01:05| 来源: 网络整理| 查看: 265

 

目前手头上接到了一个新的任务,刚好又是和X.509证书打交道的工作,想到刚入职的时候第一份正正经经的开发任务就是写证书签发工具,感觉这部分确实应该踏踏实实做一下总结了。很难说以笔者现在的水平能不能证书这么一个基础工具讲清楚,尽力而为吧。目前规划为三部分内容,本文第一篇,剩下两部分分别为:

ASN.1详解

密码库源码分析(基于mbedtls库)

证书的目的

我们公钥证书可以说是PKI(Public Key Infrastructure)中非常核心的组件之一,而PKI可以说是当代互联网文明安全的基石了。如果这方面的协议出现了漏洞,可以说会对整个世界互联网都造成非常严重的冲击。笔者知识有限,所以本文对CA(Certificate Authority)将简单抽象为单层级的一个证书颁发者。

证书(Certificate) 里面主要包含三个部分:证书信息(TBS Certificate)(TBS = To Be Signed),证书签名算法(signature Algorithm)和证书签名 (signatureValue). 证书信息里包含了证书的ID,证书拥有者的信息,签发者信息与最关键的,证书拥有者公钥信息。而证书的核心功能也是基于该公钥信息展开。

想象两个场景:

Alice和Bob进行通信,想要使用一条得到加密的数据传输通道,防止第三方窃听 Alice给Bob发了个消息,但是他想要向Bob证明这条消息是自己发出的,且没有被别人篡改过 场景1:秘钥协商

第一个场景下,可以把问题简单的规约为Alice和Bob需要拥有同样的对称秘钥,数据传输的通道上只传输由该秘钥加密过的数据。但是对称的秘钥如何传输呢?非对称密码体系解决了这个问题。在完成普通的握手之后:

Alice和Bob分别将自己的证书发给对方

Alice验证Bob的证书,验证成功后提取Bob公钥PUBKEY_B, 之后取随机数 r_A, 计算 s_A := PUBKEY_B(r_A)发送给Alice. PUBKEY_X(n)指使用X的公钥对n完成加密/验签操作. 对应ECC可以视为n(PUBKEY_X), RSA可以视为n^{PUBKEY_X} \mod N

Bob验证Alice的证书,验证成功后提取Alice公钥PUBKEY_A, 之后取随机数 r_B, 计算 s_B := PUBKEY_A(r_B) 发送给Alice

Alice和Bob分别用自己的私钥从s_B/s_A中解出对应的r_B/r_A, r_B := PRIKEY_A(s_B), r_A := PRIKEY_B(s_A),由于私钥都是仅Alice和Bob各自拥有的,网络上其他人无法解出,中间人的窃听将失效(但是中间人攻击依然是可能的,许多https的抓包软件就是基于中间人的攻击。想想为啥)

Alice和Bob拼接随机数串 r = r_A | r_B,使用协定好的秘钥派生算法,将r 作为派生秘钥的种子派生出相同的秘钥,后期将使用该派生的秘钥作为加密通信的秘钥

其实上面的协议就是一个比较简化版的SSL/TLS的握手阶段,当然秘钥协商(DH: Diffie–Hellman key exchange)的方式还有很多, 但原理相差不多,会比直接加密简单一点。包括当前几乎已经是标配的HTTPS协议,底层的安全基础很大程度也是基于SSL的协议。

场景2:数字签名

第二个场景就比较简单了:

Alice会计算自己信息M的摘要值(Digest),选择合适的padding方式,使用自己的私钥对信息的摘要值计算签名值Sig := PRIKEY_A(Pad(DIGEST(M))). 传输阶段将自己的证书,签名值与消息(Cert+Sig+M)一起打包发给Bob Bob拿到这个包后首先需要验证Alice的证书,验证成功后提取Alice的公钥;之后计算M的摘要值D,之后使用公钥计算D' := Depad(PUBKEY_A(Sig)), 最后判断 D' ?= D,完成验签操作

简单来看,消息的摘要值保证了消息的完整性Integrity,而签名的验证保证了消息是来自Alice的不可抵赖性Non-repudiation

好了,看完了上面的问题,有没有一点疑问:那看起来证书好像只是个公钥的壳子而已,为啥不直接发公钥就完事了?还有验证证书是什么意思?

有没有想过,上述的Bob和Alice都是所谓的"好人"而已,这网络上哪有这么多好人。本质上,公钥其实只是一个很大的数,传递时也就是个二进制流。假如互联网上只有裸着的公钥传输,我怎么知道这个公钥是谁发给我的,中间有没有被别人给替换了。

现实中我们证明自己是一个公民的办法通常是去公安局去获取自己的身份证,通过身份证证明我是我,因为身份证上有我的名字、唯一身份证号、照片等等,发证机关将在身份证盖上国家神圣的公章,证明身份证的真实性。那么在网络世界中,我们也需要一张这样的身份证,证明我是该公钥的拥有人,且公钥的信息很有限,所以我们需要打包更多公钥拥有者的信息,同时我们也需要一个组织来进行发证操作,起到公安局的作用,并对证书"盖上公章"。在这种场景下,网络世界的证书自然就呼之欲出了。

证书的颁发 证书的申请文件

现实中我们去获取身份证时候,首先也要填一个申请表吧。我们在申请证书的时候同样需要一个申请文件来发给网络世界的公安局,CA。当然,这个申请文件也是需要遵循格式标准的RFC 2986 - PKCS #10: Certification Request Syntax Specification,缩写为.csr

通过OpenSSL可以自己造一个合法格式的csr文件:

正如申请身份证需要先造个人,首先我们需要自己造一个公钥,即制造一对公私钥对,以RSA-2048为例,生成pem格式:

pwner@pwner:~$ openssl genrsa -out rsa_private.pem 2048 Generating RSA private key, 2048 bit long modulus (2 primes) .........................................+++++ .........................................................+++++ e is 65537 (0x010001) pwner@pwner:~$ openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem pwner@pwner:~$ cat rsa_public.pem rsa_private.pem -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6A5bWFoO3bU8apnV6Q4r SmosNvx28JSLz5gdwtrAHTjzqLn7yXu56kp/j8wZEKhe0jgKNCAGIwbY3begyAav ixZY4XUa647L4wtJ9lJzUTVcFdZ2g/WsmQXVY3ssa3NYL7SDnlBxffdrT8s0yRV4 Ojo4CqgJ926qEZERUxnuv5cgf7l3cfbZUoZzgcdw5XF+Mu98y+yvnrqnihfO2DGU HTWCRI93NkCpZRngPWElT1XR8kxSIuquJW54RgFE1RK6v7S8RVHvtwIqpvYV4D/u OgxktmwAblxwF65uPklLgVlNfxKMhFnQoF77vSPdWWaB0x8CQsn+5q4KhGARaT5z fQIDAQAB -----END PUBLIC KEY----- -----BEGIN RSA PRIVATE KEY----- MIIEpgIBAAKCAQEA6A5bWFoO3bU8apnV6Q4rSmosNvx28JSLz5gdwtrAHTjzqLn7 yXu56kp/j8wZEKhe0jgKNCAGIwbY3begyAavixZY4XUa647L4wtJ9lJzUTVcFdZ2 g/WsmQXVY3ssa3NYL7SDnlBxffdrT8s0yRV4Ojo4CqgJ926qEZERUxnuv5cgf7l3 cfbZUoZzgcdw5XF+Mu98y+yvnrqnihfO2DGUHTWCRI93NkCpZRngPWElT1XR8kxS IuquJW54RgFE1RK6v7S8RVHvtwIqpvYV4D/uOgxktmwAblxwF65uPklLgVlNfxKM hFnQoF77vSPdWWaB0x8CQsn+5q4KhGARaT5zfQIDAQABAoIBAQCDaxYKLD59CtWj XWnKaa7UntpZbZMCXm3rbC92maHxKr67EFDq4zn/2J7zVdfgGipRDVGiAXzYO1l3 /zV78mVZ9JbzX/mV67HF7C+/4yPRmtGCwIkv5GMR6j7V7vzSAWmw4p8jelU7zHIm p2NGefUzrKLuTgoO6cpA1pIkKOyP7TclGp9vTGh1MoE2rZjLggo+ESQuLX/GKDAH pV3NamiAgJtrfqTKoI/AnDcGhhy46np/Cwb4ENkFFJ6oHOYgyXexlBCQmjXfaQyp T45uGjuKi45r9c5mvP0Z7uejCKWPs6LjXye3SN2XtWFRJdADBMH+YMqHax8N3IPm 4cUz3l+hAoGBAP+vkZ2+qSECMjudymz9yEiSrrIAnG2G5gCTNsnannXMNzBOOgIb mpvGY8okLeA7pHsOYdyvnCvbRuA6mhtL+tFn84PjQem6Z18KyqwCvHWzsnvrcjbx yiBnSwsyfbfXQqdGhfs62Vko+6OxXSDB10uyHGiga7C26N8HY1F791UlAoGBAOhX WtNx5xubEgGumKPNNdSD/5Toq+Cz+eIuLiTfR4zZYGcjBawcESzkV3EM6HN/LL8N bZ1DFKxIMsGAECmkImKtEkWEpeqJkatjsQbDvzSX0mUPrE4fFJQF3JzzauXKUayC 51S0GS9EN0FLYk0mjXyrJcHaHcFqgVW0eQ/7RNF5AoGBANuLFFy/hpfKO/nGrjbR 3rS6BnjfX3IIX9vkjCncpy18sXKv6M1AiIvzWGIMmLuuWrgzDEKjI1ThDsWgbAy+ O9qtCIKZk1Iu9W29ZXM3Uj06lCola8fT63vRVbWCoEJH+nqJaqfiyxfswc23kMB8 0PG1OQF5pZ5yIBjJTjV8XU5lAoGBAL+M3W2712x0AXlvh5psIfguRzVuSd38o4Rs zFBL4MJnqMn/HrsRfLuFGe4zVSV7cNmmaXuhBVcwQuAzA6BBGLQ/ufOkc+GUP4uM qjNIiMgEb0owjL7vctjCqGqhaL1Aeut+FNhJjwXf+KoVS1sN8NIajAtxFt0SQMT3 AGRDpS4JAoGBAK6hrYUVDDLEDfvfCH8ItOGYozPdDDvJbiZQMdK9tXSnpfoOGOXK 9ofPPSrBoAIt7O0RR5fBR3di8fZbVGJRd2NUsnbFhlj4KBVKusYRjeTl5PcNI6G0 P8wd5+pqIdwAVN77S5MeusApw8A2+L67odt6xzHGugR3pcBzGONUsD3C -----END RSA PRIVATE KEY-----

生成csr文件,输入自己的公钥与私钥,通常还会让你输入自己的个人信息。使用PKCS#10的标准将信息与公钥打包后,由自己私钥进行自签名:

pwner@pwner:~/X509_learning$ openssl req -new -in rsa_public.pem -key rsa_private.pem -out rsa_public.csr.pem You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:CN State or Province Name (full name) [Some-State]:GD Locality Name (eg, city) []:SZ Organization Name (eg, company) [Internet Widgits Pty Ltd]:xxxx Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:xxxx Email Address []:xxxx Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: pwner@pwner:~/X509_learning$ cat rsa_public.csr.pem -----BEGIN CERTIFICATE REQUEST----- MIICtTCCAZ0CAQAwcDELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQH DAJTWjEPMA0GA1UECgwGSFVBV0VJMREwDwYDVQQDDAhTSFVBSUhVQTEjMCEGCSqG SIb3DQEJARYUc2h1YWlodWEyQGh1YXdlaS5jb20wggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDoDltYWg7dtTxqmdXpDitKaiw2/HbwlIvPmB3C2sAdOPOo ufvJe7nqSn+PzBkQqF7SOAo0IAYjBtjdt6DIBq+LFljhdRrrjsvjC0n2UnNRNVwV 1naD9ayZBdVjeyxrc1gvtIOeUHF992tPyzTJFXg6OjgKqAn3bqoRkRFTGe6/lyB/ uXdx9tlShnOBx3DlcX4y73zL7K+euqeKF87YMZQdNYJEj3c2QKllGeA9YSVPVdHy TFIi6q4lbnhGAUTVErq/tLxFUe+3Aiqm9hXgP+46DGS2bABuXHAXrm4+SUuBWU1/ EoyEWdCgXvu9I91ZZoHTHwJCyf7mrgqEYBFpPnN9AgMBAAGgADANBgkqhkiG9w0B AQsFAAOCAQEA5FHk/AAEmiR58aHZJ9dAFMtxEAm4x9WYpxcfzFrXt1h35QFLK3D5 3SkZlTeRNfH3r4eNYit8Hm3efqsfQXfgcuO5RTS4lU7DcAdsgExddxd52NojfnxP qMfBQNZTuglVLGZ3o3O/HQ0YvJjkcLyIyFyU1YwVzWkts/QHKmU2mtyrLN4piolv nZlTSX3qeUio218nwEmXzztcZBR51Z3hriUSIP/+rBWJlZEP+0sTaOmG46gQwS7r jxif4CcoCwPDd8+GeiSSbWHZzNYRISVtQcLHVsUAq6iro3YiQygPBLF4bwa4c8kX bcqeI/q36J+2myc/alFWDGjEsE/6zh6c7w== -----END CERTIFICATE REQUEST-----

-in选项输入公钥,-key输入私钥,-out为输出csr文件名。-new表示新建一个csr。运行命令行后然后会让你输入的个人信息。此处拆分主要为了阐述csr的生成流程。

pwner@pwner:~/X509_learning$ openssl req -new -nodes -sha256 -newkey rsa:2048 -keyout rsa_private.pem -out rsa_public.csr.pem

但是上面的打印啥也看不出来,我们需要用解析完的方式来查看该文件:

pwner@pwner:~/X509_learning$ openssl req -in rsa_public.csr.pem -noout -text Certificate Request: Data: Version: 1 (0x0) Subject: C = CN, ST = GD, L = SZ, O = xxxx, CN = xxxx, emailAddress = xxxx Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:e8:0e:5b:58:5a:0e:dd:b5:3c:6a:99:d5:e9:0e: 2b:4a:6a:2c:36:fc:76:f0:94:8b:cf:98:1d:c2:da: c0:1d:38:f3:a8:b9:fb:c9:7b:b9:ea:4a:7f:8f:cc: 19:10:a8:5e:d2:38:0a:34:20:06:23:06:d8:dd:b7: a0:c8:06:af:8b:16:58:e1:75:1a:eb:8e:cb:e3:0b: 49:f6:52:73:51:35:5c:15:d6:76:83:f5:ac:99:05: d5:63:7b:2c:6b:73:58:2f:b4:83:9e:50:71:7d:f7: 6b:4f:cb:34:c9:15:78:3a:3a:38:0a:a8:09:f7:6e: aa:11:91:11:53:19:ee:bf:97:20:7f:b9:77:71:f6: d9:52:86:73:81:c7:70:e5:71:7e:32:ef:7c:cb:ec: af:9e:ba:a7:8a:17:ce:d8:31:94:1d:35:82:44:8f: 77:36:40:a9:65:19:e0:3d:61:25:4f:55:d1:f2:4c: 52:22:ea:ae:25:6e:78:46:01:44:d5:12:ba:bf:b4: bc:45:51:ef:b7:02:2a:a6:f6:15:e0:3f:ee:3a:0c: 64:b6:6c:00:6e:5c:70:17:ae:6e:3e:49:4b:81:59: 4d:7f:12:8c:84:59:d0:a0:5e:fb:bd:23:dd:59:66: 81:d3:1f:02:42:c9:fe:e6:ae:0a:84:60:11:69:3e: 73:7d Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: sha256WithRSAEncryption e4:51:e4:fc:00:04:9a:24:79:f1:a1:d9:27:d7:40:14:cb:71: 10:09:b8:c7:d5:98:a7:17:1f:cc:5a:d7:b7:58:77:e5:01:4b: 2b:70:f9:dd:29:19:95:37:91:35:f1:f7:af:87:8d:62:2b:7c: 1e:6d:de:7e:ab:1f:41:77:e0:72:e3:b9:45:34:b8:95:4e:c3: 70:07:6c:80:4c:5d:77:17:79:d8:da:23:7e:7c:4f:a8:c7:c1: 40:d6:53:ba:09:55:2c:66:77:a3:73:bf:1d:0d:18:bc:98:e4: 70:bc:88:c8:5c:94:d5:8c:15:cd:69:2d:b3:f4:07:2a:65:36: 9a:dc:ab:2c:de:29:8a:89:6f:9d:99:53:49:7d:ea:79:48:a8: db:5f:27:c0:49:97:cf:3b:5c:64:14:79:d5:9d:e1:ae:25:12: 20:ff:fe:ac:15:89:95:91:0f:fb:4b:13:68:e9:86:e3:a8:10: c1:2e:eb:8f:18:9f:e0:27:28:0b:03:c3:77:cf:86:7a:24:92: 6d:61:d9:cc:d6:11:21:25:6d:41:c2:c7:56:c5:00:ab:a8:ab: a3:76:22:43:28:0f:04:b1:78:6f:06:b8:73:c9:17:6d:ca:9e: 23:fa:b7:e8:9f:b6:9b:27:3f:6a:51:56:0c:68:c4:b0:4f:fa: ce:1e:9c:ef

这就有那味儿了,简单解析一下,顺便对应着RFC的标准看一下。先看Data这段,对应的是 CertificationRequestInfo

CertificationRequestInfo ::= SEQUENCE { version INTEGER { v1(0) } (v1,...), subject Name, subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, attributes [0] Attributes{{ CRIAttributes }} }

顺便提一下,RFC的标准都是使用ASN.1格式描述的,而日常使用中的证书等文件同样是基于ASN.1的BER格式,而PEM是对文件进行标识(如-----BEGIN CERTIFICATE REQUEST-----)后,进行base64编码的产物。ASN.1的具体细节将在(二)部分进行分析。

可以发现生成的csr的data部分是可以和CertificationRequestInfo一一对应起来的:

version:csr的版本号,当前通常是version 1,即0

subject:以Name的格式保存,一般会保存证书持有者的国籍(C:Country 两个字母表示,如美国US,中国CN), 省级行政区(ST: State or Province),城市(L:Locality), 公司组织名(O:Organization), 组织部门名(OU: Organization Unit), 通用名(CN: Common Name), email地址等等。其实具体的规范还是比较复杂的,具体标准参考X.501规范。此处不细说了

subjectPKInfo: 最关键的部分,包含了公钥的信息,由公钥算法与公钥值组成:

SubjectPublicKeyInfo { ALGORITHM : IOSet} ::= SEQUENCE { algorithm AlgorithmIdentifier {{IOSet}}, subjectPublicKey BIT STRING }

顺便提一句,AlgorithmIdentifier的标识是ANS.1编码中最与众不同的方式,Object ID. 后续将提到。此处算法被标记为了rsaEncrypt

最后是attributes,他主要提供了一些证书申请者的附加信息。PKCS#9中定义了一些在此可能使用的属性类型,典型的例子是challenge-password属性:它将指定一个密码,实体可以通过该密码请求吊销证书;另一个例子是X.509证书扩展中显示的信息(例如。从PKCS #9获取的extensionRequest属性等)。此处a0:00标识了NULL

Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { type ATTRIBUTE.&id({IOSet}), values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) }

再看完整的csr结构:

CertificationRequest ::= SEQUENCE { certificationRequestInfo CertificationRequestInfo, signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, signature BIT STRING }

certificationRequestInfo对应的就是上面的Data,已完成解释

signatureAlgorithm对应签名算法,此处为sha256WithRSAEncryption,指的是使用待签名的公钥对应的私钥,来完成自签名,签名的对象是certificationRequestInfo的sha256摘要值,签名算法为RSA

最后signature对应的就是签名值了,bit string类型

最后提一点,在证书申请的模式下,申请者只需要将公钥信息发至证书签发机构即可,保证了私钥的本地性与私密性。

CA

完成了申请表的填写,就应该交给身份证办理人员了,类比下来csr文件生成之后,我们就要向CA发送证书申请文件,以获取证书。

CA可以翻译为数字证书认证机构,是PKI体系中的基石。维基百科于是说:

CA是证书的签发机构,它是PKI的核心。CA是负责签发证书、认证证书、管理已颁发证书的机关。它要制定政策和具体步骤来验证、识别用户身份,并对用户证书进行签名,以确保证书持有者的身份和公钥的拥有权。

由上文可以推断,CA正是承担了公安局对身份证"盖章"这一工作,盖上的便是使用CA私钥完成的对证书的数字签名。但是公安局的信用是有国家背书的,所以CA也必须得到网络上所有人的信任。当然拥有CA资格的机构也是相当有限的。

CA获取证书申请之后,首先就要检测csr的合法性,申请人信息的合法性,公钥的合法性等等。这些属于审批的范畴,技术范畴的话就是需要校验csr的签名,即certificationRequestInfo是否被篡改。过程为取出certificationRequestInfo中的公钥信息,计算certificationRequestInfo的待验证哈希值。利用提取的公钥与签名计算出签名哈希值,解padding后,判断是否与待验证哈希值一致,确定该csr的完整性与不可抵赖性。

CA在完成验证后,将下发自己的CA证书以及签发的X.509证书。CA同样是一张X.509格式的证书,往往也是一张自签名的证书,即CA私钥签发CA公钥。事实上,当前网络通讯当中(特别是浏览器)将会内置上很多权威受信任的CA证书,若通信过程中使用的CA证书并不在内置名单中,往往程序会进行提醒:当前站点CA证书不受信任。而且现在CA往往由于需要加快签发速率等原因,会使用多级CA的模式,即CA证书由上级CA签发,最后将校验链上的证书一并发送给申请者,后续校验时将进行证书的逐级校验。

还记得上面场景中提到的:Alice验证Bob的证书这一步吗?Alice正是通过CA证书中的公钥来校验Bob证书签名的。原因正是基于CA是Alice所信任的证书认证者。当然验证证书还需要对certificateInfo校验,确定Bob的身份,下章就会讲到。

X.509

终于到了重头戏,我们的主角,X.509格式的证书。再强调一次,证书是功能性的描述,而X.509只是证书一种国际上通用的格式,基于RFC3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile(X.509 v3), 对应了PKCS#12。

这次我们直接拿上一张Google的证书来看看:

Certificate: Data: Version: 3 (0x2) Serial Number: bc:01:41:05:22:d8:cc:7f:02:00:00:00:00:79:64:7f Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, O = Google Trust Services, CN = GTS CA 1O1 Validity Not Before: Aug 26 08:14:23 2020 GMT Not After : Nov 18 08:14:23 2020 GMT Subject: C = US, ST = California, L = Mountain View, O = Google LLC, CN = www.google.com Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:bc:1c:aa:96:6f:6f:99:48:79:56:61:4b:7f:ff: dc:39:08:3a:d4:4d:e2:d8:87:80:af:3d:18:5e:71: 2d:ce:09:70:57:39:38:5f:2a:ee:a8:35:f4:3a:86: 86:5a:1d:c7:31:32:1b:8d:ac:d0:46:ad:c3:fc:a5: d3:18:36:68:ab ASN1 OID: prime256v1 NIST CURVE: P-256 X509v3 extensions: X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: AF:32:A8:9D:20:98:F3:FD:14:41:FE:F4:C4:74:47:7C:D1:6C:81:B1 X509v3 Authority Key Identifier: keyid:98:D1:F8:6E:10:EB:CF:9B:EC:60:9F:18:90:1B:A0:EB:7D:09:FD:2B Authority Information Access: OCSP - URI:http://ocsp.pki.goog/gts1o1core CA Issuers - URI:http://pki.goog/gsr2/GTS1O1.crt X509v3 Subject Alternative Name: DNS:www.google.com X509v3 Certificate Policies: Policy: 2.23.140.1.2.2 Policy: 1.3.6.1.4.1.11129.2.5.3 X509v3 CRL Distribution Points: Full Name: URI:http://crl.pki.goog/GTS1O1core.crl CT Precertificate SCTs: Signed Certificate Timestamp: Version : v1 (0x0) Log ID : 5E:A7:73:F9:DF:56:C0:E7:B5:36:48:7D:D0:49:E0:32: 7A:91:9A:0C:84:A1:12:12:84:18:75:96:81:71:45:58 Timestamp : Aug 26 09:14:24.417 2020 GMT Extensions: none Signature : ecdsa-with-SHA256 30:45:02:20:77:F3:D6:8B:51:4F:88:71:16:73:ED:36: 2F:64:F4:77:3E:92:D3:CE:97:1F:1C:53:FA:4E:FB:5B: D7:0A:4C:D6:02:21:00:9F:B9:FE:F1:F3:1C:0D:CF:20: 30:B1:1C:0A:01:65:AD:67:90:1F:B5:33:90:8D:49:4D: 2B:ED:1D:90:28:A1:6B Signed Certificate Timestamp: Version : v1 (0x0) Log ID : 07:B7:5C:1B:E5:7D:68:FF:F1:B0:C6:1D:23:15:C7:BA: E6:57:7C:57:94:B7:6A:EE:BC:61:3A:1A:69:D3:A2:1C Timestamp : Aug 26 09:14:24.367 2020 GMT Extensions: none Signature : ecdsa-with-SHA256 30:45:02:21:00:F4:67:8E:8B:ED:3F:B2:D4:EA:72:EB: 53:F1:52:57:98:D6:63:0E:C0:6B:68:46:CE:F3:AD:25: 52:AD:12:83:27:02:20:05:CA:04:76:D6:4F:2A:E5:D3: 96:85:79:A2:F3:85:29:9E:89:30:00:A7:20:99:2D:F7: C9:56:3C:4E:5D:5C:CF Signature Algorithm: sha256WithRSAEncryption 7a:9a:76:80:c9:39:13:8e:60:b1:93:5d:99:49:1b:71:b5:b2: 2e:bd:4b:db:56:f0:eb:fa:f4:ae:93:f6:1b:dd:b0:df:2a:81: 08:fc:4a:a9:ec:b1:ae:09:f0:fa:40:7b:b8:be:dc:08:4c:46: 32:99:29:f8:13:6b:72:af:16:79:63:d3:3f:76:56:57:19:78: 91:86:f8:7a:ee:26:67:98:dc:5e:e4:00:f5:87:a0:01:21:9d: cf:e5:9f:02:f3:2a:fd:0e:fd:78:af:2e:20:29:77:35:e2:c6: 30:ee:ef:be:f2:bb:26:02:52:a2:2d:27:78:ce:a9:8e:39:d0: a2:74:90:11:c5:92:58:3c:7a:88:1d:c7:5a:56:d4:1a:01:00: c3:9d:98:6f:41:02:1f:cb:e2:4d:99:6a:5c:d9:0f:c0:88:08: 15:c5:26:90:a2:a4:15:f6:71:e2:fe:a9:98:dc:40:2a:71:c1: 11:aa:00:73:52:24:74:aa:ae:72:55:2f:0d:31:b7:00:bb:1f: 87:4d:f5:05:ad:ff:7a:93:e0:cf:86:a5:1d:1b:7d:41:fa:10: 99:3b:00:7c:c9:dd:a9:52:5c:06:72:86:96:e7:05:97:77:12: 2f:26:bb:dc:65:c4:48:4d:9c:82:4b:7d:69:27:3f:85:00:2e: b1:5d:8d:dc

同样对照标准定义进行学习字段的意义:

Certificate ::= SEQUENCE { tbsCertificate TBSCertificate, signatureAlgorithm AlgorithmIdentifier, signatureValue BIT STRING }

可以看到Data对应了tbsCertificate, 也是整张证书最关键的部分,该字段包含证书拥有者信息、颁发者信息、公钥信息、有效期信息等,后面单独拿出来详细解析。

剩下的两个部分与csr完全一致,同样是表明了签名的算法与tbsCertificate的签名。这里要注意,签发者issuer信息表明了证书签发人,一般为受信任的CA。

TBSCertificate

核心字段,一点点手撕;先看定义

TBSCertificate ::= SEQUENCE { version [0] EXPLICIT Version DEFAULT v1, serialNumber CertificateSerialNumber, signature AlgorithmIdentifier, issuer Name, validity Validity, subject Name, subjectPublicKeyInfo SubjectPublicKeyInfo, issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version shall be v2 or v3 subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version shall be v2 or v3 extensions [3] EXPLICIT Extensions OPTIONAL -- If present, version shall be v3 } Version ::= INTEGER { v1(0), v2(1), v3(2) } CertificateSerialNumber ::= INTEGER Validity ::= SEQUENCE { notBefore Time, notAfter Time } Time ::= CHOICE { utcTime UTCTime, generalTime GeneralizedTime } UniqueIdentifier ::= BIT STRING SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING }

这里顺便提一句ASN.1下的定义中SEQUENCE和SET的区别在于:通常SEQUENCE是一个有序集合,即编码时必须按照顺序排列,SET则可以为无序的集合。通常解析SEQUENCE时都将按序解析。

version:X.509标准下版本,例子中证书为0x2,即v3版本。注意证书存在extensions时,版本一定是v3版本,故extension通常也称为X.509 v3 extension。

serialNumber:证书的序列号,它必须是一个唯一的整数。需要注意一点,他是一个大端数字,所以有时候他可能高位填一些0,但不影响其对比。比如例子中的证书,实际编码中高位填上了0:

/* 解析结果 */ Serial Number: bc:01:41:05:22:d8:cc:7f:02:00:00:00:00:79:64:7f /* 编码 */ Tag:[02] Length:[11] Value:[00 BC 01 41 05 22 D8 CC 7F 02 00 00 00 00 79 64 7F]

序列号的作用主要在CRL中体现唯一标识的作用。可以对照到身份证上的身份证号:)

signature: 标记了证书的签名算法,与csr一样,不做赘述。

issuer:标记证书签发者CA的信息,例子中可以看到为Google Trust Services签发。具体格式类似上面的subject。

validity:标识了证书的生效时间,以起始时间与结束时间表述。可以看到例子中的证书的生效起始时间为格林威治时间的2020/08/26, 有效期至2020/11/18。时间的ASN.1通常以 YYMMDDHHMMSS来标识,结尾以Z或者时区差标识时区。Z是Zulu时间的意思,和格林威治时间同步。

subject:证书拥有者信息,同issuer。上面提到校验Bob的信息,也就是对这一段的验证。

subjectPublicKeyInfo:证书公钥信息,也和csr中的一致。

UniqueID:可选字段,这个字段必须要v2及以上版本才有,主要是用来防止issuer与subject重名的情况。例子中的证书是没有的

Extension

extension是最重头戏的字段:

Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension Extension ::= SEQUENCE { extnID OBJECT IDENTIFIER, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING }

通过描述可以看到Extensions是一个可选字段,其内部可以有最多MAX个拓展字段,这里当然无法单独完成阐述,挑一些例子中的标准拓展字段描述。

Authority Key Identifier/Subject Key Identifier: 这两个字段主要是在多证书的场景提供一种快速确定所需要公钥的标记。Authority Key Identifier唯一标记了该证书签发私钥对应的公钥,而Subject Key Identifier则是唯一标记了当前证书中的公钥。举个例子,一个设备当中可能有好多个证书,但是每一个app可能只需要对应证书中的公钥,那么就可以将这一串ID内置在app中,证书也不需要完整解析,先去看看对应Key Identifier字段是不是匹配即可。通常计算方式为计算公钥的SHA1值,本例子中的Subject Key Identifier即为这种方式:

X509v3 Subject Key Identifier: AF:32:A8:9D:20:98:F3:FD:14:41:FE:F4:C4:74:47:7C:D1:6C:81:B1 from hashlib import sha1 hash = sha1() hash.update(b"\x04\xbc\x1c\xaa\x96\x6f\x6f\x99\x48\x79\x56\x61\x4b\x7f\xff\xdc\x39\x08\x3a\xd4\x4d\xe2\xd8\x87\x80\xaf\x3d\x18\x5e\x71\x2d\xce\x09\x70\x57\x39\x38\x5f\x2a\xee\xa8\x35\xf4\x3a\x86\x86\x5a\x1d\xc7\x31\x32\x1b\x8d\xac\xd0\x46\xad\xc3\xfc\xa5\xd3\x18\x36\x68\xab") hash.hexdigest() >>>'af32a89d2098f3fd1441fef4c474477cd16c81b1'

Key Usage/Extended Key Usage: 确定证书中公钥的用途。以前一个为主,extended字段作为补充。例子中的证书主要就是用来做TLS通讯中的数字签名功能。Key Usage主要类型有以下几种,详细描述可以参考标准中的描述,这里不展开说了:

KeyUsage ::= BIT STRING { digitalSignature (0), nonRepudiation (1), keyEncipherment (2), dataEncipherment (3), keyAgreement (4), keyCertSign (5), cRLSign (6), encipherOnly (7), decipherOnly (8) }

Certificate Policies:以OID格式体现,主要是表现申请证书时的缘由和预期的用途。例子中的2.23.140.1.2.2和1.3.6.1.4.1.11129.2.5.3是典型的OID格式,每个点隔开一个属性层级,可以通过 http://www.oid-info.com/ 进行Object的查询,如2.23.140.1.2.2表示为organization-validated,即

Certificates issued in accordance with the CA/Browser Forum's Baseline Requirements - Organization identity asserted

Authority Information Access:标识了CA Issuer的信息,包括OCSP服务的网址与CA证书的下载地址。该部分在TLS很重要。OCSP服务会在后续CRL中提到。

CRL Distribution Points:CRL(Certificate Revocation List), 标识了当前CA下吊销列表文件的下载地址,也是TLS握手阶段重要的过程。后续将继续分析。

CT Precertificate SCTs:证书透明度(Certificate Transparency); 这个是标准中没有提到的一个比较新的拓展。CT主要搭配了CA服务器上公开的Log,将记录CA的行为日志,而每一个与当前证书相关的日志将被计入此字段,并被CA进行签名。校验阶段可以根据Log ID和timestamp查找日志中的对应操作,对证书进行审计以确定当前证书的合法性。该字段的提出主要就是防止CA被入侵者利用后获取大量非法签发证书,而透明性的日志保证了证书的签发是到受到严格监控的。

CRL

证书的有效期似乎已经能够防止回退之内的攻击了,但是万一在有效期内发生了对应私钥的泄漏事件,该怎么取消掉证书的有效性呢?这时候就需要crl出场了。

上面已经提到了CRL Distribution Points,直接从对应地址下载个crl:

Certificate Revocation List (CRL): Version 2 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, O = Google Trust Services, CN = GTS CA 1O1 Last Update: Sep 19 02:13:00 2020 GMT Next Update: Sep 29 02:13:00 2020 GMT CRL extensions: X509v3 CRL Number: 1001 X509v3 Authority Key Identifier: keyid:98:D1:F8:6E:10:EB:CF:9B:EC:60:9F:18:90:1B:A0:EB:7D:09:FD:2B Revoked Certificates: Serial Number: 049950FB5DD23C3502000000007A32AD Revocation Date: Sep 10 15:53:36 2020 GMT CRL entry extensions: X509v3 CRL Reason Code: Affiliation Changed Serial Number: 05303980A9456025080000000056050B Revocation Date: Sep 10 15:53:42 2020 GMT CRL entry extensions: X509v3 CRL Reason Code: Affiliation Changed ...... Signature Algorithm: sha256WithRSAEncryption 00:37:3c:7e:ba:71:d2:92:52:3a:f6:4d:86:c0:a2:c2:18:78: 34:0e:ea:80:41:08:82:32:54:42:f0:2c:d7:f7:e0:81:93:dc: 0d:e5:0b:71:1f:ae:7e:bf:1c:05:3c:3c:f8:2b:cb:99:20:21: 80:29:a9:81:1d:f4:33:f4:21:95:70:f1:4c:38:30:34:28:32: be:0a:0b:0d:09:5d:81:33:72:fb:40:16:db:26:a1:7d:e9:11: 56:74:11:58:e3:4d:37:93:23:68:6a:85:8c:89:05:7d:55:67: 8c:da:3c:02:cb:46:3b:4e:7d:c6:38:12:02:cc:a8:ff:57:04: 9d:0a:bf:07:30:36:5d:85:b7:4c:9e:a1:52:b8:2c:4a:ec:91: ba:ba:8f:74:60:f4:06:84:8b:d9:a7:08:3d:2a:cf:ee:66:c6: de:1e:ae:68:24:ed:0d:ca:d6:73:0e:40:b2:5c:91:00:dc:32: 72:04:8b:46:65:12:9c:56:9d:aa:76:89:7b:c2:74:a8:b0:a3: de:e6:d6:d1:12:87:16:34:98:9b:2e:bd:38:ea:1c:59:03:40: 0d:ba:0c:0c:f2:9e:31:64:33:1b:28:43:4e:3b:78:41:2e:d9: 82:21:39:97:fe:c0:ab:9f:82:8d:18:02:26:c4:b0:44:c5:74: 25:30:6a:50

还是先对应ASN.1对于crl格式的描述看一下:

CertificateList ::= SEQUENCE { tbsCertList TBSCertList, signatureAlgorithm AlgorithmIdentifier, signatureValue BIT STRING } TBSCertList ::= SEQUENCE { version Version OPTIONAL, -- if present, MUST be v2 signature AlgorithmIdentifier, issuer Name, thisUpdate Time, nextUpdate Time OPTIONAL, revokedCertificates SEQUENCE OF SEQUENCE { userCertificate CertificateSerialNumber, revocationDate Time, crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 } OPTIONAL, crlExtensions [0] EXPLICIT Extensions OPTIONAL -- if present, MUST be v2 }

可以看到这时候crl的解析出来的格式顺序已经和标准的定义略有区别,但是不影响,只要知道所有的吊销列表信息肯定都是被CA签名了的。

signatureAlgorithm和signatureValue 没啥好说的,和之前证书和申请文件没有区别。

CertList

这一段可分为主要的两个部分:吊销文件信息和吊销证书列表,这也是解析出来crl没有按照顺序排列的原因,为了打印的好看,这一段被拆分成了两部分

先看吊销文件信息:

version、signature和issuer 和之前完全一样,不再赘述。

thisUpdate:指定了本次crl签发的的时间。主要用来保证crl证书的时效性

nextUpdate:可选项,指定了下一次crl签发的时间

crlExtensions:包含了拓展信息,注意这个字段在实际的证书中是放在revokedCertificates后面的。在用例的google证书的crl中可以看到吊销证书的数量(CRL Number: 1001)和Authority Key Identifier,可以看到这个Authority Key Identifier和X.509证书中的相同字段是一模一样的。注意这个地方CRL Number是不一定等于revokedCertificates中被吊销列表数量的,其实为了加快查找效率,已经过期的被吊销证书是可以从列表中移除以减小列表的大小。

revokedCertificates

这是crl的核心部分,包含了被吊销证书的唯一序列号(userCertificate CertificateSerialNumber),证书的吊销时间(revocationDate),以及一些扩展,用例中包含了典型用例:吊销原因码(CRL Reason Code)。

主要看一下唯一序列号这个段,这个段是刚好对应X.509证书中的serialNumber段,这也是为什么这个段需要唯一的原因:他标识了一张独一无二的证书。

其实这时候查询一个列表是否吊销的流程已经很简单了:

握手阶段获取crl 通过CA证书校验crl签名 查询对端证书的序列号是否在revokedCertificates中

但是这是唯一的方法吗?如果碰到像当年heartbleed一样的大型泄漏事件,吊销列表是不是特别大,特别大会造成两个问题:下载慢、查询慢,最终导致握手超时。

第二点问题是crl有更新不及时的问题:CA机构在吊销一张证书后,不会立刻去更新CRLs文件,客户端定期缓存的CRLs文件也不是及时更新的,所以会导致一种情况是,某张证书被吊销后,由于CRLs文件没有及时更新的缘故,身份校验通过了,认为该张证书没有问题。

所以为了解决对应的问题,SSL中包含一种新协议

OCSP

OCSP(Online Certificate Status Protocol),即在线证书状态协议。同样是用来做服务器身份校验,由CA机构管理,使用数字签名技术保护,浏览器可以从中获得证书的吊销状态和吊销原因,方式是由身份校验方浏览器发送OCSP请求,等待响应来完成证书状态获取。当然OCSP的格式同样要遵照标准rfc6960。这里就不细解析OCSP格式了,可以参考标准文档。 当然OCSP最为协议当然也有request和response(其实csr就是请求,申请下来的证书就是答复),这里贴一下request的格式

OCSPRequest ::= SEQUENCE { tbsRequest TBSRequest, optionalSignature [0] EXPLICIT Signature OPTIONAL } TBSRequest ::= SEQUENCE { version [0] EXPLICIT Version DEFAULT v1, requestorName [1] EXPLICIT GeneralName OPTIONAL, requestList SEQUENCE OF Request, requestExtensions [2] EXPLICIT Extensions OPTIONAL } Signature ::= SEQUENCE { signatureAlgorithm AlgorithmIdentifier, signature BIT STRING, certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL} Version ::= INTEGER { v1(0) } Request ::= SEQUENCE { reqCert CertID, singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } CertID ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier, issuerNameHash OCTET STRING, -- Hash of issuer's DN issuerKeyHash OCTET STRING, -- Hash of issuer's public key serialNumber CertificateSerialNumber } 尾声

看起来X.509这一系列好像很简单的样子,然而这里打出来的其实都是完成解析之后的样子,那么解析之前的DER格式的证书是啥样子的呢:

00000000: 3082 04c8 3082 03b0 a003 0201 0202 1100 0...0........... 00000010: bc01 4105 22d8 cc7f 0200 0000 0079 647f ..A."........yd. 00000020: 300d 0609 2a86 4886 f70d 0101 0b05 0030 0...*.H........0 00000030: 4231 0b30 0906 0355 0406 1302 5553 311e B1.0...U....US1. 00000040: 301c 0603 5504 0a13 1547 6f6f 676c 6520 0...U....Google 00000050: 5472 7573 7420 5365 7276 6963 6573 3113 Trust Services1. 00000060: 3011 0603 5504 0313 0a47 5453 2043 4120 0...U....GTS CA 00000070: 314f 3130 1e17 0d32 3030 3832 3630 3831 1O10...200826081 00000080: 3432 335a 170d 3230 3131 3138 3038 3134 423Z..2011180814 00000090: 3233 5a30 6831 0b30 0906 0355 0406 1302 23Z0h1.0...U.... 000000a0: 5553 3113 3011 0603 5504 0813 0a43 616c US1.0...U....Cal 000000b0: 6966 6f72 6e69 6131 1630 1406 0355 0407 ifornia1.0...U.. 000000c0: 130d 4d6f 756e 7461 696e 2056 6965 7731 ..Mountain View1 000000d0: 1330 1106 0355 040a 130a 476f 6f67 6c65 .0...U....Google 000000e0: 204c 4c43 3117 3015 0603 5504 0313 0e77 LLC1.0...U....w 000000f0: 7777 2e67 6f6f 676c 652e 636f 6d30 5930 ww.google.com0Y0 00000100: 1306 072a 8648 ce3d 0201 0608 2a86 48ce ...*.H.=....*.H. 00000110: 3d03 0107 0342 0004 bc1c aa96 6f6f 9948 =....B......oo.H 00000120: 7956 614b 7fff dc39 083a d44d e2d8 8780 yVaK...9.:.M.... 00000130: af3d 185e 712d ce09 7057 3938 5f2a eea8 .=.^q-..pW98_*.. 00000140: 35f4 3a86 865a 1dc7 3132 1b8d acd0 46ad 5.:..Z..12....F. 00000150: c3fc a5d3 1836 68ab a382 025c 3082 0258 .....6h....\0..X 00000160: 300e 0603 551d 0f01 01ff 0404 0302 0780 0...U........... 00000170: 3013 0603 551d 2504 0c30 0a06 082b 0601 0...U.%..0...+.. ...

啥啥啥,这是啥??

其实这就是反复提到的ASN.1格式。系列下一章就是手撕ASN.1, 做一个人肉decoder(想多了...)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有