目录
X.509证书
当我们提到证书的时候,我们指的是X.509 v3。X.509 v3 现在已经被广泛使用,https使用的就是该证书,并且X.509 v3相关的软件套件和代码库在 TLS 和 HTTPS 客户端和服务器上已经相当成熟,拿来便可以使用。
在车联网安全中,证书是构建安全体系的关键设施,KMS密钥管理系统、车云通信和安全启动等等一系列功能的实现都依赖证书。在不断使用和了解证书的过程中,诞生了几个和证书相关的疑问,本文并不打算全面详细地介绍X509的格式和使用,而是围绕这几个有趣的疑问展开。
问题一:生成证书为什么要指定地址信息
如下来自维基百科的X.509证书示例片段显示了证书代表的主体,其中包含了使用美式格式的地址信息:国家、州和地区。不知到大家是否会产生这样的疑问,用在web基础设施中的证书,为什么需要携带详细的地址信息?我们在使用证书的过程中,地址信息对证书的主要用途几乎是无用的,设计证书的机构难道这么不严谨吗?
主體: C=US, ST=California, L=San Francisco, O=Wikimedia Foundation, Inc., CN=*.wikipedia.org
事出反常必有因,为了搞清楚这个问题,我们需要了解下设计者的想法。X.509是作为X.500的一部分由国际电信联盟提出来的, X.500 也是电信公司制定的,目的是为了建立全球性的电话簿。也就是说X.509 不是为 Web 设计的,它的设计目标是为了帮助电信公司构建电话簿,因此需要携带地区信息。这种设计与我们使用固定电话区号的意图是一样的,我们使用“010”代表北京,“022”代表天津。
问题二:为什么要使用文本格式
在使用证书的时候,我们经常面临的问题是选择PEM格式还是DER格式。其中,DER的全称为“Distinguished Encoding Rules”,中文意思为“唯一编码规则”,由ASN.1定义,目的是将ASN.1格式的文本编码成元字符串。ASN.1是一种类似于Json的数据组织方式,它定义了证书的表示方法,形式如下:
FooProtocol DEFINITIONS ::= BEGIN
FooQuestion ::= SEQUENCE {
trackingNumber INTEGER,
question IA5String
}
FooAnswer ::= SEQUENCE {
questionNumber INTEGER,
answer BOOLEAN
}
END
而DER将文本形式的数据结构编码成二进制形式的bit文件,DER的部分编码规则如下所示:
30 -- 標籤說明 SEQUENCE
13 -- octets長度
02 -- 標籤說明 INTEGER
01 -- octets長度
05 -- value
16 -- 標籤說明 IA5String
0e -- octets長度
DER的目的是为了方便在网络上传输ASN.1格式的数据,如下来自维基百科的示例说明了DER是如何将消息转换成适合在网络上传输的bit流:
消息原始内容:
myQuestion FooQuestion ::= {
trackingNumber 5,
question "Anybody there?"
}
经过DER编码之后:
30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f
注:
41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f -- value
("Anybody there?" in ASCII)
到此为止,我们能够很容易地理解DER格式的内容和目的,但是既然已经有了面向网络传输的二进制格式,为什么还需要PEM这种文本格式呢?为了搞清楚这个问题,我们需要了解下跨平台通信中经常遇到的编码问题。
跨平台编码的问题
从编码的角度来看,很多字符在跨平台传输的场景下是不安全的,比如html中的“<”和“>”,如果直接在标签中嵌入,可能会被解释成标签起始标致。
<html>
<body>
<div>
<p Is 3+4 < 5 ? />
</div>
<div>
<embed src="data:text/plain;base64, SXMgMys0IDwgNSA/" type="text/plain" />
</div>
<div>
<embed src="data:text/plain;base64, SXMgMys0IDwgNSA/" type="text/plain" />
</div>
</body>
</html>
在这个HTML的例子中,直接嵌入“Is 3+4 < 5 ?”的段落将不会被正常解析和显示,而使用了base64编码的段落将可以正常显示,为了区分最终显示的内容,我们将base64编码的段落显示两次,效果如下:
根据最终的网页效果我们可以推断直接嵌入表达式的段落没有被正常解析,因为解析器大概率将小于号“<”解析成了标签的开始,类似这种容易被编码解析器“误会”的字符,我们认为它们是编码不安全的字符。
这种情况同样出现在使用不同编码方式的平台之间传输文件时,最常见的是对换行符的编码,windows使用0x0d0x0a两个字节,unix使用0x0a一个字节。当程序员在Windows上对源文件完成编码之后,如果没有处理换行符直接拷贝到Unix类系统中打开,会发现每一个换行符前都多了一个“^M”,这就是0x0d在unix系统上的显示字符。
为了避免不安全字符在不同平台之间的传输,我们需要使用base64对原始内容进行编码,之后再进行传输。
Base64的作用
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于所以每6个比特为一个单元,对应某个可打印字符。3个字节相当于24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后BinHex的版本使用不同的64字符集来代表6个二进制数字,但是不被称为Base64。
Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。[2]
Base64编码索引表如下所示,因为Base64编码中没有不安全的字符,因此在网络传输的过程中不会存储解释“误会”。
Base64编码对照表(来自维基百科)
最后,让我们来回答“为什么要使用文本格式PEM”,因为证书经常需要通过网络进行分发,并且使用证书的平台是多种多样的,为了避免证书内容在目标平台上被错误地解释,我们使用编码安全的Base64编码证书的二进制内容,以网络保证传输过程中证书内容的安全性(编码解码层面上的安全)。
问题三:X509、PKCS和ASN.1的关系
X.509是密码学里公钥证书的格式标准。X.509证书已应用在包括TLS/SSL在内的众多网络协议里,同时它也用在很多非在线应用场景里,比如电子签名服务。X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)[3]。
X.509定义了证书的内容、类型和用途等一系列证书相关内容:
证书
版本号
序列号
签名算法
颁发者
证书有效期
此日期前无效
此日期后无效
主题
主题公钥信息
公钥算法
主题公钥
颁发者唯一身份信息(可选项)
主题唯一身份信息(可选项)
扩展信息(可选项)
...
证书签名算法
数字签名
PKCS(公钥加密标准)是RSA实验室颁布的一套加密标准,包括证书申请、证书更新、证书作废、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议。这个标准包含多个系列,第一个是 PKCS#7,由 IETF 重新命名为加密消息语法 (CMS),它可以包含一个或多个证书(证书链)。 PKCS#7 通常被 Java 使用,常见的扩展名是 .p7b 和 .p7c。另一种常见的系列是 PKCS#12,它可以包含一个证书链(如 PKCS#7)和一个(加密的)私钥。 PKCS#12 通常被微软产品使用,常见的扩展名是 .pfx 和 .p12。同样,PKCS#7 和 PKCS#12 也使用 ASN.1进行编码。
综上,X.509规定了证书应该包含什么内容,PKCS标准则规定了如何将证书应用到公钥加密标准中,ASN.1则可以理解为定义证书数据结构的语法,用来组织证书的内容。
参考文章
[1].互联网工程任务组: https://zh.wikipedia.org/wiki/%E4%BA%92%E8%81%94%E7%BD%91%E5%B7%A5%E7%A8%8B%E4%BB%BB%E5%8A%A1%E7%BB%84
[2]. base64维基百科:https://zh.wikipedia.org/wiki/Base64
[3]. X.509维基百科:https://zh.wikipedia.org/wiki/X.509