想象一下,当你创建一个自己的比特币钱包的时候,那个钱包,在计算机里对应的是什么?
对此有了解的人会回答,对应的是一对非对称算法的公私钥,把公钥公开给别人,就是钱包地址。
那你有好奇过这些密钥对长什么样子吗?这就是今天要谈的话题。
1. 私钥
从原理上来讲,目前密码学中非对称算法主要分为两种:
- 一种是利用质因数分解难题的 RSA 算法。
- 一种是基于椭圆曲线乘法逆运算难题的 ECC 算法。
但是 RSA 算法出现的时间要比 ECC 早得多,PKCS#1(RFC 8017) 很早就对 RSA 算法做了一些标准化工作,其中就包含了 RSA 的二进制私钥结构标准:
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
但是这个结构是使用 ASN1 编码进行组织的,ASN1 是一种二进制的字节编码方式,如果需要将二进制进行方便的存储和传输,就需要一种将二进制编码为可见字符的编码方式,Base64 无疑是一种很好的编码方式。
不过 Base64 在阅读时毕竟跟乱码没什么区别,人们更希望能够知道一串 Base64 具体指代的含义,以便能够理解和解析 Base64 编码的内容,于是 PEM(RFC7468)编码应运而生,PEM 通过在 Base64 字符串首尾添加标识字符串,来指示一段 Base64 字符串具体指代的内容,例如,一个上述结构的 RSA 私钥使用 PEM 编码后是这样的:
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAKR9vHzaDTe2vNbYBA5iwPa7LcoxT2Thjj/qof3Jf+ai8WxllhfX
ZnxmfkFG9A5zhMt2tTbagiDrXEsvLXpDN2ECAwEAAQJANJwmigQv0A75TPngKj25
m/B4D8A/tXNSzOydjQ9CgiA8VstvdCGLUY6uZxGIi7ty889oUw+Fd744JoWDeLrz
MQIhAPLfN3XNwBpNFCKvgFi13t6jAtlgNAgAmUXjY4/hjth1AiEArWHpZlAQMj4s
Q+2FlrOnfFAE0KhgZDmOjmDjBz/ipb0CIQDrAwPvgkC5MoyhY6GWNaaLWMGRBn5S
oAGwlu/ociJ/YQIgPlD5tYdDOvuzpzqAkDjEEt8jy+cotf0l6rCSCLICgTUCIQCX
2F9lPk3ybKmBFfvvjN0/B3OmUG1AHloS1q8n+RQ9zQ==
-----END RSA PRIVATE KEY-----
通过 BEGIN 和 END 标识的字符串,我们一眼就能理解这段 Base64 指代了一个 PKCS#1 规范中规定的 RSA 私钥结构。
💡 PS:像不像我们平时对数据打标签,没错,PEM 的本质就是给一段不易识别的数据打标签来标识数据类型。
但是 PKCS#1 的 RSA 私钥结构中并没有字段标识具体的密钥算法,这是因为在标准制定时,还没有其他的非对称算法被提出来,这也造成了后来这个私钥结构的局限性。
随着 ECC 算法的提出,人们同样需要对 ECC 的密钥结构进行组织编码,于是在 SEC 1 中,标准化了 ECC 私钥的结构:
ECPrivateKey ::= SEQUENCE {
version INTEGER { ecPrivkeyVer1(1) },
privateKey OCTET STRING,
parameters [0] EXPLICIT ECDomainParameters OPTIONAL,
publicKey [1] EXPLICIT BIT STRING OPTIONAL
}
同样的,我们可以对 ECC 私钥进行 PEM 编码:
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIK0nZGahAeDb44kK/+WTwDQ3K0Nx6OFSuXocVvXTVIG+oAoGCCqBHM9V
AYItoUQDQgAE++rM4WtAH9cA7sVI3Hcl0nDV5OIUpBY7p6Hp6wgg7Qr96bcarJia
RN2YcNGFBXcBZmH+lDtYq6HGxwDux3+zEA==
-----END EC PRIVATE KEY-----
可以看到,通过读取 PEM 头,我们就可以知道应该用何种算法和标准来解析 Base64 编码的内容。
不同的非对称算法私钥都有各自的格式,从本质上来讲,私钥在应用时作用都是一样的,只是算法上存在区别,那有没有一种格式能够同时表示不同算法的私钥格式呢?当然有,PKCS#8(RFC 5208) 被提了出来,PKCS#8 提出的私钥结构可以表示为:
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
privateKey PrivateKey,
attributes [0] Attributes OPTIONAL }
Version ::= INTEGER {v1(0)} (v1,...)
PrivateKey ::= OCTET STRING
}
通过添加 AlgorithmIdentifie 算法标识,PKCS#8 在结构中便指示了私钥的算法和相关参数,而 PrivateKey 则包装了各种不同算法的标准私钥内容,通过在外面包装一层的做法,做到了结构的统一性和后期的扩展性(万物皆可 Wrapper 😂)。
因此,我们上面的 RSA 和 ECC 私钥,再经过一次 PKCS#8 的包装,就可以表示成:
-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEApH28fNoNN7a81tgE
DmLA9rstyjFPZOGOP+qh/cl/5qLxbGWWF9dmfGZ+QUb0DnOEy3a1NtqCIOtcSy8t
ekM3YQIDAQABAkA0nCaKBC/QDvlM+eAqPbmb8HgPwD+1c1LM7J2ND0KCIDxWy290
IYtRjq5nEYiLu3Lzz2hTD4V3vjgmhYN4uvMxAiEA8t83dc3AGk0UIq+AWLXe3qMC
2WA0CACZReNjj+GO2HUCIQCtYelmUBAyPixD7YWWs6d8UATQqGBkOY6OYOMHP+Kl
vQIhAOsDA++CQLkyjKFjoZY1potYwZEGflKgAbCW7+hyIn9hAiA+UPm1h0M6+7On
OoCQOMQS3yPL5yi1/SXqsJIIsgKBNQIhAJfYX2U+TfJsqYEV+++M3T8Hc6ZQbUAe
WhLWryf5FD3N
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgrSdkZqEB4NvjiQr/
5ZPANDcrQ3Ho4VK5ehxW9dNUgb6gCgYIKoEcz1UBgi2hRANCAAT76szha0Af1wDu
xUjcdyXScNXk4hSkFjunoenrCCDtCv3ptxqsmJpE3Zhw0YUFdwFmYf6UO1irocbH
AO7Hf7MQ
-----END PRIVATE KEY-----
因为本身包装的结构一致,而且结构内部已经包含了算法标识,在 PEM 的头尾就不需要特别去说明私钥的算法了,所以不同种类的私钥可以被统一成相同的 PEM 头。
💡 PS:我们把一组拥有相同特性的标签归成了一类,并打了个新标签上去。
2. 证书的格式
2.1 公钥
同样的,由于算法基于的原理不同,PKCS#1 和 SEC 1 中定义的公钥二进制结构也并不相同,那么与私钥的解决思路一样,我们需要在外层统一包装一层,让不同算法的公钥都可以拥有一个统一的结构。
因为非对称算法的公钥通常会被包含到数字证书中分发,数字证书的标准化工作就把这事儿顺手给干了,在 RFC 5280 中,数字证书对如何组织不同算法的公钥进行了设计,RFC 5280 给出的公钥 ASN1 结构标准为:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
你看,其实没有什么新意,又是包装了一层,RFC 5280 也是通过添加了一个 AlgorithmIdentifier 算法标识来存放对应算法的类型和相关参数,以达到对各种不同算法的兼容。
将上面结构进行 PEM 编码后,就可以得到我们常见的公钥信息了,例如一个 RSA 的公钥的 PEM 格式是:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyl6q6BkEcEUi9V1/Q7il
bngnh1YzG1tM4Hd6XCZQ35OzDN4my9eXWtjoL8YvLYqlYTJqhTHpuptgjF/lmlhg
WIMKNNcuDAbvmWExRyZateVrjO9OtgkyJCuGhaum0TIUC+dbZ9L9xsdK/fU1L5BB
nPRSYMloH8uE1CbK/DhFUiKp36aHZFfqLPicY3c6/N+k2kIJCEWBY0SROqpqy2Iz
yCIP54JSoOoGz6pdtWhd5cEeicr9e7f/WixEES6fgavqIHzhSJBVctpMgFPjFZ/x
JJhQVf23WKb3YQQ/0Uc8O7OTDXoUfuJP9UgqvKNh4hPfJA+a4nxkDYhTPfrLHfKY
YwIDAQAB
-----END PUBLIC KEY-----
2.2 X.509 证书
另外在 RFC 5280 中,同样对数字证书的格式做了很多标准化工作,目前主流的 v3 版本的证书格式,定义的 ASN1 结构为:
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING
}
我们看到数字证书中那么多信息项,其实从最顶层看就是三项数据,在上面的结构中,TBSCertificate 表示的是证书信息,signatureAlgorithm 表示的是签发证书时使用的签名算法标识,signatureValue 则指代的是对证书信息进行密码学签名运算得到的签名值。
那公钥在哪里呢?
我们思考下数字证书是用来解决什么问题的?数字证书实际的作用是为了证明 我是我 的问题,对应到密码学上,其实就是将 某些信息 与 某个公钥 绑定,通过公证方(即 CA)签名运算的抗否认特性,来证明某个公钥属于某个实体。
那么,很自然的,被签名的信息就是需要被证明可信的信息,进而可以猜测,上文的 某些信息 和 某个公钥 就是在需要被证明可信的信息中,也就是在 TBSCertificate 中。
我们来看看 TBSCertificate 的 ASN1 结构:
TBSCertificate ::= SEQUENCE {
version [0] Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] Extensions OPTIONAL
-- If present, version MUST 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
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
-- contains the DER encoding of an ASN.1 value
-- corresponding to the extension type identified
-- by extnID
}
我们关注 TBSCertificate 的结构即可,能发现里面包含了证书的版本、序列号、签发者、主题、公钥和扩展等信息。
证书的签发者描述了证书是被那个可信的主体签发的,证书的主题则表示绑定在这张证书中的各种需要被证明的信息,他是一个 X500Name 结构,在一个签发主体(Issuer)下是唯一的,Validity 表示证书的有效期,Extensions 则表示证书的扩展项,扩展项有很多类型,可以进一步精细化控制证书的用途。
完成了对这些信息的编码,再请求 Issuer 对这些信息进行签名得到 Certificate 中的 signatureValue ,将信息与签名组合起来,就得到一张数字证书了。
同样的,PEM(RFC7468) 编码同样为数字证书分配了 Header,将以上数字证书的 ASN1 结构的二进制数据进行 Base64 编码,添加数字证书的 PEM 头尾(CERTIFICATE),就得到了我们常见的用于分发的数字证书了,例如 didiglobal.com 网站的 HTTPS 证书就是下面的样子:
-----BEGIN CERTIFICATE-----
MIIHozCCBougAwIBAgIQA6Lc5oapN/YMIwdni6wYojANBgkqhkiG9w0BAQsFADBE
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMR4wHAYDVQQDExVH
ZW9UcnVzdCBSU0EgQ04gQ0EgRzIwHhcNMjMxMDEzMDAwMDAwWhcNMjQxMDE1MjM1
OTU5WjCBgTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCeWMl+S6rOW4gjFDMEEGA1UE
ChM6QmVpamluZyBEaWRpIEluZmluaXR5IFRlY2hub2xvZ3kgYW5kIERldmVsb3Bt
ZW50IENvLiwgTHRkLjEZMBcGA1UEAwwQKi5kaWRpZ2xvYmFsLmNvbTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMKlJoG8fteTtwvUW4BW8Xx+UK8RfjFz
2SXTQNwL2sAX+v9jqgbd7Vax07DddXqgquqE+wJKm/2N+wPzhNQeAxzO+m+0sUat
11hiKIQmsUgaFwsTR0fUUxlxYvlNfUaaUdwf4V644Utipm283TPf7bj1Do7etmnC
vlnO8zcd7O/xXwdegRzHlXBmL44XlSFT3CeAI7WhUyA95oUikXS7oG53l3blkmhH
OIuDBhr8RA9W9JMAtSi6jICUyVIvO8ullJDZ2FbggyBNyyO4v+vqhkCuxxURG4nJ
h5T2ClX0OS8qktB8iU/jjg7ePVCgW3rCCcvRk99uP1fs+qEgorKBQccCAwEAAaOC
BFEwggRNMB8GA1UdIwQYMBaAFCRvkT+Jh4cOMsJAGN/FTOtPyEkyMB0GA1UdDgQW
BBRKM2fcuBznFEQNbx6Ueeic9vmyGzCCAVcGA1UdEQSCAU4wggFKghAqLmRpZGln
bG9iYWwuY29tgg4qLjk5cGF5LmNvbS5icoIJOTlhcHAuY29tggsqLjk5YXBwLmNv
bYIOZGlkaWdsb2JhbC5jb22CGCouZGlkaXBheS5kaWRpZ2xvYmFsLmNvbYIWKi5p
bnRyYS5kaWRpZ2xvYmFsLmNvbYIlbm90ZWJvb2suYmlnZGF0YS5pbnRyYS5kaWRp
Z2xvYmFsLmNvbYIbKi5kYXRhLmludHJhLmRpZGlnbG9iYWwuY29tgh4qLmRhdGEt
ZGUuaW50cmEuZGlkaWdsb2JhbC5jb22CHiouZGF0YS1ydS5pbnRyYS5kaWRpZ2xv
YmFsLmNvbYISd3d3LmRpZGlnbG9iYWwuY29tggVkZC5tZYIHKi5kZC5tZYIOKi45
OXRheGlzLm1vYmmCFCouaW50cmEuOTl0YXhpcy5tb2JpMD4GA1UdIAQ3MDUwMwYG
Z4EMAQICMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwuZGlnaWNlcnQuY24vR2VvVHJ1
c3RSU0FDTkNBRzIuY3JsMHEGCCsGAQUFBwEBBGUwYzAjBggrBgEFBQcwAYYXaHR0
cDovL29jc3AuZGlnaWNlcnQuY24wPAYIKwYBBQUHMAKGMGh0dHA6Ly9jYWNlcnRz
LmRpZ2ljZXJ0LmNuL0dlb1RydXN0UlNBQ05DQUcyLmNydDAMBgNVHRMBAf8EAjAA
MIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdgB2/4g/Crb7lVHCYcz1h7o0tKTN
uyncaEIKn+ZnTFo6dAAAAYsn5uRLAAAEAwBHMEUCIQCRoltWHfV28chl2IHlMYIL
ru4Sg6v3ZQo6yQziIDjgbwIgDKmf9lE7KU19ubTaL6+ipRIyKWqYg+oRif6qPx1P
Ce8AdwBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAYsn5uQjAAAE
AwBIMEYCIQDf9tM4UMN+oS39W4e1b7w2sr8N/ZrPGRzxuEbkkIrtjgIhALvDS0jR
au2ZfJWw1Z9MqN6c8CGlkY1N2VjVlYtVtLnIAHYA2ra/az+1tiKfm8K7XGvocJFx
bLtRhIU0vaQ9MEjX+6sAAAGLJ+bkGgAABAMARzBFAiBCarYzocrOvSSUEDxAC8Lj
JGoiQwJPZ/Qw4myg5uMU3gIhANBAEXF2NKll3QrMKDA/x5pWZ0RO+rzmAxOM50ZV
xSVaMA0GCSqGSIb3DQEBCwUAA4IBAQCHdgDOjFxa0mTwwKwgU2R3Bas4BiwEKE+y
6QvFmpmi05IEF4uD1minGINFKOLOH7XfKkAciDXwj3cyiGGhA6K7im3juNkz1bSW
KdBb/wJhtVnDwXax+g7IttwSg2zCO/wDThJyME72rpMk+PdwoN77Py5ZNSrI9wQ8
4LntOPe8Ty4hqob/0GuqlFDJA1wKd1ByERp0AQWoCDw+Pl4QIzV1R4oooq8VJ1RJ
V0qLCvfSUwH57GJsgNm8a6P+oPBph4qCwtcQzBnGAue1dl2fOMY1d+tj8ltJ02L1
+PD/g2Ys2daq0aGp4diexFNb9uvlFl/OANFMMz1p0yyPyp724Gha
-----END CERTIFICATE-----
将它解析为 ASN1 的结构后的样子是(为方便查看,移除了一些庞大的扩展项):
SEQUENCE
{
SEQUENCE
{
TAGGED [0]:
INTEGER=2
INTEGER=
03 A2 DC E6 86 A9 37 F6 0C 23 07 67 8B AC 18 A2
SEQUENCE
{
OBJECT IDENTIFIER=Sha256WithRSAEncryption (1.2.840.113549.1.1.11)
NULL
}
SEQUENCE
{
SET
{
SEQUENCE
{
OBJECT IDENTIFIER=CountryName (2.5.4.6)
PRINTABLE STRING='US'
}
}
SET
{
SEQUENCE
{
OBJECT IDENTIFIER=OrganizationName (2.5.4.10)
PRINTABLE STRING='DigiCert Inc'
}
}
SET
{
SEQUENCE
{
OBJECT IDENTIFIER=CommonName (2.5.4.3)
PRINTABLE STRING='GeoTrust RSA CN CA G2'
}
}
}
SEQUENCE
{
UTC TIME=13/Oct/2023 08:00:00 CST (231013000000GMT+00:00)
UTC TIME=16/Oct/2024 07:59:59 CST (241015235959GMT+00:00)
}
SEQUENCE
{
SET
{
SEQUENCE
{
OBJECT IDENTIFIER=CountryName (2.5.4.6)
PRINTABLE STRING='CN'
}
}
SET
{
SEQUENCE
{
OBJECT IDENTIFIER=StateOrProvinceName (2.5.4.8)
UTF8 STRING='北京市'
}
}
SET
{
SEQUENCE
{
OBJECT IDENTIFIER=OrganizationName (2.5.4.10)
PRINTABLE STRING='Beijing Didi Infinity Technology and Development Co., Ltd.'
}
}
SET
{
SEQUENCE
{
OBJECT IDENTIFIER=CommonName (2.5.4.3)
UTF8 STRING='*.didiglobal.com'
}
}
}
SEQUENCE
{
SEQUENCE
{
OBJECT IDENTIFIER=RsaEncryption (1.2.840.113549.1.1.1)
NULL
}
BIT STRING, encapsulates:
SEQUENCE
{
INTEGER=
00 C2 A5 26 81 BC 7E D7 93 B7 0B D4 5B 80 56 F1
7C 7E 50 AF 11 7E 31 73 D9 25 D3 40 DC 0B DA C0
17 FA FF 63 AA 06 DD ED 56 B1 D3 B0 DD 75 7A A0
AA EA 84 FB 02 4A 9B FD 8D FB 03 F3 84 D4 1E 03
1C CE FA 6F B4 B1 46 AD D7 58 62 28 84 26 B1 48
1A 17 0B 13 47 47 D4 53 19 71 62 F9 4D 7D 46 9A
51 DC 1F E1 5E B8 E1 4B 62 A6 6D BC DD 33 DF ED
B8 F5 0E 8E DE B6 69 C2 BE 59 CE F3 37 1D EC EF
F1 5F 07 5E 81 1C C7 95 70 66 2F 8E 17 95 21 53
DC 27 80 23 B5 A1 53 20 3D E6 85 22 91 74 BB A0
6E 77 97 76 E5 92 68 47 38 8B 83 06 1A FC 44 0F
56 F4 93 00 B5 28 BA 8C 80 94 C9 52 2F 3B CB A5
94 90 D9 D8 56 E0 83 20 4D CB 23 B8 BF EB EA 86
40 AE C7 15 11 1B 89 C9 87 94 F6 0A 55 F4 39 2F
2A 92 D0 7C 89 4F E3 8E 0E DE 3D 50 A0 5B 7A C2
09 CB D1 93 DF 6E 3F 57 EC FA A1 20 A2 B2 81 41
C7
INTEGER=65537 (0x10001)
}
}
TAGGED [3]:
SEQUENCE
{
SEQUENCE
{
OBJECT IDENTIFIER=AuthorityKeyIdentifier (2.5.29.35)
OCTET STRING, encapsulates:
SEQUENCE
{
TAGGED [0] IMPLICIT :
OCTET STRING=
24 6F 91 3F 89 87 87 0E 32 C2 40 18
DF C5 4C EB 4F C8 49 32
}
}
SEQUENCE
{
OBJECT IDENTIFIER=SubjectKeyIdentifier (2.5.29.14)
OCTET STRING, encapsulates:
OCTET STRING=
4A 33 67 DC B8 1C E7 14 44 0D 6F 1E
94 79 E8 9C F6 F9 B2 1B
}
SEQUENCE
{
OBJECT IDENTIFIER=CertificatePolicies (2.5.29.32)
OCTET STRING, encapsulates:
SEQUENCE
{
SEQUENCE
{
OBJECT IDENTIFIER=2.23.140.1.2.2
SEQUENCE
{
SEQUENCE
{
OBJECT IDENTIFIER=Cps (1.3.6.1.5.5.7.2.1)
IA5 STRING='http://www.digicert.com/CPS'
}
}
}
}
}
SEQUENCE
{
OBJECT IDENTIFIER=KeyUsage (2.5.29.15)
BOOLEAN=true
OCTET STRING, encapsulates:
BIT STRING=10100000
}
SEQUENCE
{
OBJECT IDENTIFIER=ExtKeyUsage (2.5.29.37)
OCTET STRING, encapsulates:
SEQUENCE
{
OBJECT IDENTIFIER=ServerAuth (1.3.6.1.5.5.7.3.1)
OBJECT IDENTIFIER=ClientAuth (1.3.6.1.5.5.7.3.2)
}
}
SEQUENCE
{
OBJECT IDENTIFIER=CRLDistributionPoints (2.5.29.31)
OCTET STRING, encapsulates:
SEQUENCE
{
SEQUENCE
{
TAGGED [0]:
TAGGED [0]:
TAGGED [6] IMPLICIT :
OCTET STRING=
68 74 74 70 3A 2F 2F 63
72 6C 2E 64 69 67 69 63
65 72 74 2E 63 6E 2F 47
65 6F 54 72 75 73 74 52
53 41 43 4E 43 41 47 32
2E 63 72 6C
}
}
}
SEQUENCE
{
OBJECT IDENTIFIER=BasicConstraints (2.5.29.19)
BOOLEAN=true
OCTET STRING, encapsulates:
SEQUENCE
{
}
}
}
}
SEQUENCE
{
OBJECT IDENTIFIER=Sha256WithRSAEncryption (1.2.840.113549.1.1.11)
NULL
}
BIT STRING=
87 76 00 CE 8C 5C 5A D2 64 F0 C0 AC 20 53 64 77
05 AB 38 06 2C 04 28 4F B2 E9 0B C5 9A 99 A2 D3
92 04 17 8B 83 D6 68 A7 18 83 45 28 E2 CE 1F B5
DF 2A 40 1C 88 35 F0 8F 77 32 88 61 A1 03 A2 BB
8A 6D E3 B8 D9 33 D5 B4 96 29 D0 5B FF 02 61 B5
59 C3 C1 76 B1 FA 0E C8 B6 DC 12 83 6C C2 3B FC
03 4E 12 72 30 4E F6 AE 93 24 F8 F7 70 A0 DE FB
3F 2E 59 35 2A C8 F7 04 3C E0 B9 ED 38 F7 BC 4F
2E 21 AA 86 FF D0 6B AA 94 50 C9 03 5C 0A 77 50
72 11 1A 74 01 05 A8 08 3C 3E 3E 5E 10 23 35 75
47 8A 28 A2 AF 15 27 54 49 57 4A 8B 0A F7 D2 53
01 F9 EC 62 6C 80 D9 BC 6B A3 FE A0 F0 69 87 8A
82 C2 D7 10 CC 19 C6 02 E7 B5 76 5D 9F 38 C6 35
77 EB 63 F2 5B 49 D3 62 F5 F8 F0 FF 83 66 2C D9
D6 AA D1 A1 A9 E1 D8 9E C4 53 5B F6 EB E5 16 5F
CE 00 D1 4C 33 3D 69 D3 2C 8F CA 9E F6 E0 68 5A
}
可以很清晰的看到 X.509 证书的各个结构。
3. 一些思考
相对于计算机的历史来讲,现代密码学算是出现的非常早了,RSA 算法早在 1977 年就被提了出来,接着在 1985 年,ECC 算法也被提出,这些算法的年龄可能都超过了你我的年龄,在这数十年的发展当中,公钥密码已经成为现代计算机通信的基础。
数字证书本身已经是一个非常成熟的体系,在需要进行可信认证的场景下,PKI (公钥基础设施)体系几乎提供了完整的底层支持,无论是硬件、软件、人员、策略和规程上,还是密钥和证书的产生、管理、存储、分发和撤销的功能上,都拥有久经考验的解决方案。
但是,当我们面对历史所留下的各种形形色色标准和格式时,非对称密码学中这些核心并不复杂的概念却变得令人头疼不已。希望这篇编码格式的笔记,能让这些概念更加清晰一些,简单一些。
百尺竿头,更进一步,与君共勉。