密钥对、证书和编码

想象一下,当你创建一个自己的比特币钱包的时候,那个钱包,在计算机里对应的是什么?

对此有了解的人会回答,对应的是一对非对称算法的公私钥,把公钥公开给别人,就是钱包地址。

那你有好奇过这些密钥对长什么样子吗?这就是今天要谈的话题。

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-----

通过 BEGINEND 标识的字符串,我们一眼就能理解这段 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#1SEC 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 (公钥基础设施)体系几乎提供了完整的底层支持,无论是硬件、软件、人员、策略和规程上,还是密钥和证书的产生、管理、存储、分发和撤销的功能上,都拥有久经考验的解决方案。

但是,当我们面对历史所留下的各种形形色色标准和格式时,非对称密码学中这些核心并不复杂的概念却变得令人头疼不已。希望这篇编码格式的笔记,能让这些概念更加清晰一些,简单一些。

百尺竿头,更进一步,与君共勉。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容