1+1=10

扬长避短 vs 取长补短

证书相关的 X.509、PEM、DER、CER、KEY 等都是什么鬼?

这堆东西在互联网上无处不在,但是每次遇到它们总还是觉得陌生,每次都需要搜索、搜素、...,还是挺没成就感的。

先梳理梳理,做个记录

术语

  • ASN.1:Abstract Syntax Notation One. 一种接口描述语言(IDL),它是一种描述数据的表示、编码、传输、解码的灵活的记法。

  • X.509:X.509是密码学里公钥证书的格式标准,X.509证书包含公钥、身份信息和签名信息。证书采用ASN.1进行描述。

  • PKCS:Public Key Cryptography Standards。公钥加密标准,此一标准的设计与发布皆由 RSA 资讯安全公司(英语:RSA Security)所制定。PKCS #8 是存储私钥信息的标准语法;PKCS#10定义证书申请标准;PKCS#12定义个人讯息交换标准(定义包含私钥与公钥证书的文件格式,私钥采用密码保护)。

  • PKI:Public Key Infrastructure,公钥基础设施。它是一种用于创建、存储和分发数字证书的系统,用于验证特定的公钥属于某个实体。

  • CA:Certificate Authority,数字证书颁发机构。负责存储、发布和签署数字证书

  • 数字证书:digital certificate,public key certificate,或者 identiry certificate。是一个经证书颁发机构(CA)数字签名的文件,包含拥有者的公钥及相关身份信息。

  • DER:Distinguished Encoding Rules,是ASN.1的一种编码规则。注意,BER,CER 都是ASN.1定义的编码规则。

  • PEM:Privacy-Enhanced Main,一种存放key、证书的文件格式的事实标准。

术语太多,且不同上下文下偏重不同,试图捋一捋:

ASN.1→ X.509 → 数字证书 → DER→ PEM

个人觉得,可以借用C++来类比一下

术语 类比C++ 备注
ASN.1 C++ 语言 ASN.1 一门语言,规定了基本数据类型,扩展机制
X.509 C++ 类 X.509使用ASN.1语言,定义一个类(证书类),明确了类有哪些成员,类型是什么
数字证书 类对象 数字证书时X.509这个类的实例化对象,各个成员都有了具体的值
DER .obj ASN.1定义各序列化或编译规则,类对象存放在硬盘上的形态。数字证书存在的形式之一
PEM 这个和ASN.1似乎没有半毛钱关系。它可以把任何二进制数据用base64进行编码。数字证书存在的形式之一(把DER产物用 base64编码)。

PKI → CA → RA → 数字证书

在非对称加密中,公钥是公开的,但如何保证我拿到的证书(公钥)是可信的,而不是中间人的?

publickey-privatekey

PKI(Public Key Infrastructure)是解决证书(公钥)信任问题的基础和框架。PKI创建数字证书,将公钥与实体进行映射,将这些证书安全地存储在中央存储库中,并在需要时撤销它们。

PKI由以下几部分构成:

  • 证书颁发机构(CA,Certificate Authority):存储、发布和签署数字证书;
  • 注册机构(RA,Registration Authority):验证请求其数字证书存储在CA中的实体的身份;
  • 证书库(LDAP协议列表)
  • 证书撤销列表(CRL)

pki-ra-ca-ldap

.CSR、.key、CRT等

  • CSR:证书请求文件 Certificate Signing Request。

  • KEY:私钥,与证书配对使用

  • CRT:可以是二进制DER,可以是文本格式PEM。只包含证书,不存在私钥。Linux一般用CRT后缀,还有其他后缀格式。

使用openssl的话:

生成私钥

openssl genrsa -out x.key 2048

生成 证书请求文件 (回答它的提问,完成过程)

openssl req -new -key x.key -out x.csr

而后用csr去找CA机构申请正式的证书。

如果用openssl作为CA来生成证书的话(ca的选项可通过openssl的配置文件配置),可以

openssl ca -req -in x.csr -out x.crt

如果有老的证书文件,但是对应的 .csr文件丢失,也可以使用openssl工具,从证书文件中提取出来(注意使用命令行参数-x509toreq)。

openssl x509 -in x.crt -signkey x.key -x509toreq -out x.csr

.CER、.CRT、.DER、.PEM、.P12、.pfx 等

这些都是证书的后缀名。但后缀名和和文件内容并不一一对应。

从文件编码来说,X.509的证书格式有两大类:

  1. DER:以二进制格式保存证书,不包含私钥。常用的后缀有:.DER、.CER和.CRT。
  2. PEM:以ASCII码格式保存证书,可以包含私钥,也可以不包含私钥。常用的后缀有:.PEM、.CER和.CRT。对PEM格式的证书,RFC7468建议的后缀名是 .CRT。

对于证书后缀为.CER或.CRT,可以用记事本打开证书,查看证书内容来区分证书格式。

  • 如果有类似"-----BEGIN xxxxx-----"和"-----END xxxxx-----"的头尾标记,则证书格式为PEM。
  • 如果是乱码,则证书格式为DER

Apache和*nix服务器偏向于PEM格式,而Java和Windows服务器偏向于DER格式。

另外,还有一个:

PKCS#12:以二进制格式保存证书,可以包含私钥,也可以不包含私钥。常用的后缀有:.P12和.PFX。主要用于Windows平台

注意:尽管PEM能存各种东西,但一般不存储PKCS#12的证书。

不同格式证书之间可以互相转换。

OpenSSL中,

  • openssl x509 可用于 DER 和 PEM的互转
openssl x509 -in x.cer -inform der -out x.crt -outform pem
openssl x509 -in x.crt -inform pem -out x.cer -outform der
  • openssl pkcs12 可用于PFX和PEM的互转
openssl pkcs12 -in x.pfx -out x.pem -nodes
openssl pkcs12 -export in x.crt -inkey x.key -out x.pfx -certfile ca.crt

数字证书(digital certificate)

数字证书解决了"公钥持有者到底是谁"的问题。数字签名技术中无法确定公钥是拥有者的身份。

数字证书,是一个经证书颁发机构(CA)数字签名的文件,包含拥有者的公钥及相关身份信息。

    证书
        版本号
        序列号
        签名算法
        颁发者
        证书有效期
            此日期前无效
            此日期后无效
        主题
        主题公钥信息
            公钥算法
            主题公钥
        颁发者唯一身份信息(可选项)
        主题唯一身份信息(可选项)
        扩展信息(可选项)
            ...
    证书签名算法
    数字签名

证书标准 X.509

X.509是一个和数字证书有关的国际标准。一个X.509证书需要提供下列信息:

  • Version:X.509标准的版本
  • Serial Number:赋给每个证书的序列号
  • Signature Algorithm:发布者用于签名的算法
  • Issuer:发布者名字
  • Validity:证书有效期
  • Subject:公钥所有者的名字
  • Subject Public Key Info:公钥及其相关信息

证书内容可以通过openssl工具查看:

openssl x509 -in x.crt -text -noout
openssl x509 -in x.crt -inform der -text -noout

分类1

  • DV类型证书:域名验证型证书(Domain Validated),证书审核方式为通过验证域名所有权即可签发证书。此类型证书适合个人和小微企业申请,价格较低,申请快捷。

  • OV类型证书:企业验证型证书(Organization Validated ),证书审核方式为通过验证域名所有权和申请企业的真实身份信息才能签发证书。目前运用最广,兼容性最好的证书类型。

  • EV类型证书:增强验证型证书(Extended Validation),证书审核级别为所有类型最严格验证方式,在OV类型的验证基础上额外验证其他企业的相关信息,比如银行开户许可证书。EV类型证书多使用于银行,金融,证券,支付等高安全标准行业。

DV证书有很多途径可以免费申请,比如 Let's Encrypt。

不过DV证书的有效期越来越短,目前单个证书有效期一般3个月(2012年之前有效期10年,2012年有效期3年,2018年有效期2年,2020年有效期1年,2023年有效期3个月,...)。

分类2

  • 单域名SSL:这类证书只保护一个域名,这些域名形如example.com;ww.example.com, b.example.com等;如果您为www前缀的域名申请证书时,默认是可以保护不带www的主域名,但是当其他前缀的子域名申请证书时,则只能保护当前子域名,不能保护不带前缀的主域名。

  • 多域名SSL:这种类型的证书可以同时保护多个域名,例如:同时保护ww.example.com, b.example.com、c.example.com等,但是不同品牌的多域名证书默认保护的域名数量不一样。

  • 通配符SSL:通配符证书可以保护一个域名下的同级子域名,并且不限制该子域名的数量。例如:这类证书可以保护b.example.com,也可以保护c.example.com,也就是说他可以保护example.com这个域名下的所有同级子域名。

其他

PEM

PEM格式将二进制数据使用base64进行编码,并定义了头和尾。格式如下:

-----BEGIN xxxxx-----

-----END xxxxx-----

xxxxx的常见值见 RFC7468

  • CERTIFICATE:X.509数字证书,它编码的内容必须是BER/DER格式。 [RFC5280]
  • X509 CRL :证书撤销列表(Certificate Revocation Lists),要求BER/DER [RFC5280]
  • CERTIFICATE REQUEST:证书请求(对应PKCS#10) ,要求BER/DER [RFC2986]
  • PKCS7 :签名密文格式 [RFC2315]
  • CMS [RFC5652]
  • PRIVATE KEY:非加密的PKCS#8,要求BER/DER [RFC5208] [RFC5958]
  • ENCRYPTED PRIVATE KEY加密的PKCS8,要求BER/DER [RFC5958]
  • ATTRIBUTE CERTIFICATE [RFC5755]
  • PUBLIC KEY:X.509公钥 [RFC5280]

在OpenSSL中,xxxxx的定义值有(定义在crypto/pem/pem.h):

# define PEM_STRING_X509_OLD     "X509 CERTIFICATE"
# define PEM_STRING_X509         "CERTIFICATE"
# define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE"
# define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST"
# define PEM_STRING_X509_REQ     "CERTIFICATE REQUEST"
# define PEM_STRING_X509_CRL     "X509 CRL"
# define PEM_STRING_EVP_PKEY     "ANY PRIVATE KEY"
# define PEM_STRING_PUBLIC       "PUBLIC KEY"
# define PEM_STRING_RSA          "RSA PRIVATE KEY"
# define PEM_STRING_RSA_PUBLIC   "RSA PUBLIC KEY"
# define PEM_STRING_DSA          "DSA PRIVATE KEY"
# define PEM_STRING_DSA_PUBLIC   "DSA PUBLIC KEY"
# define PEM_STRING_PKCS7        "PKCS7"
# define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA"
# define PEM_STRING_PKCS8        "ENCRYPTED PRIVATE KEY"
# define PEM_STRING_PKCS8INF     "PRIVATE KEY"
# define PEM_STRING_DHPARAMS     "DH PARAMETERS"
# define PEM_STRING_DHXPARAMS    "X9.42 DH PARAMETERS"
# define PEM_STRING_SSL_SESSION  "SSL SESSION PARAMETERS"
# define PEM_STRING_DSAPARAMS    "DSA PARAMETERS"
# define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY"
# define PEM_STRING_ECPARAMETERS "EC PARAMETERS"
# define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY"
# define PEM_STRING_PARAMETERS   "PARAMETERS"
# define PEM_STRING_CMS          "CMS"

文件后缀常见的有 .pem,.cer, .crt, .key 等,后缀意义不大,可辨识性不高,远没有文件内的这些标签有用。

注意:OpenSSH的私钥PEM格式与此处不同,它的私钥以-----BEGIN OPENSSH PRIVATE KEY-----开头。这应该不是问题,只要ssh客户端认可即可。详见这里

查看PEM文件内容

确定文件类别后,可以通过openssl的对应命令来查看pem文件内容,比如

  • 查看CSR
openssl req -text -noout -in blog.debao.me.csr
  • 查看crt
openssl x509 -text -noout -in blog.debao.me.crt
  • 查看私钥
openssl rsa -text -noout -in blog.debao.me.key

提取公钥

可以从RSA 私钥文件、CSR文件、X.509证书中提取公钥

  • 从RSA私钥提取公钥
openssl rsa -in x.key -pubout
  • 从.CSR文件提取公钥
openssl req -in x.csr -pubkey -noout
  • 从X.509数字证书提取公钥
openssl x509 -in x.crt -pubkey -noout

参考

  • https://en.wikipedia.org/wiki/X.509
  • https://www.openssl.org/docs/man3.2/man1/openssl-x509.html
  • http://www.herongyang.com/crypto/Certificate_Formats_X509_DER_PEM.html
  • http://serverfault.com/questions/9708/what-is-a-pem-file-and-how-does-it-differ-from-other-openssl-generated-key-file
  • https://support.ssl.com/Knowledgebase/Article/View/19/0/der-vs-crt-vs-cer-vs-pem-certificates-and-how-to-convert-them
  • http://www.cnblogs.com/guogangj/p/4118605.html
  • OpenSSL 入门:密码学基础知识
  • https://blog.51cto.com/u_15316394/5004231
  • [X.509、PKCS文件格式介绍](https://segmentfault.com/a/1190000019008423)