证书生成及验证

常见的加密算法

摘要算法

摘要算法(也称为哈希函数)是用于将任意长度的数据映射为固定长度摘要值的算法。以下是一些常见的摘要算法: MD5 (Message Digest Algorithm 5),摘要长度: 128 位(16 字节) SHA-1 (Secure Hash Algorithm 1),摘要长度: 160 位(20 字节) SHA-2 (Secure Hash Algorithm 2),SHA-2 是一系列摘要算法,包括 SHA-224、SHA-256、SHA-384 和 SHA-512。 SHA-224: 224 位(28 字节),SHA-256: 256 位(32 字节),SHA-384: 384 位(48 字节) ,SHA-512: 512 位(64 字节) SHA-3 (Secure Hash Algorithm 3),SHA-3 是最新的 SHA 系列算法,基于 Keccak 算法。

对称加密算法

对称加密算法使用相同的密钥进行加密和解密,其主要优点是速度快,适用于大数据量的加密。以下是一些常见的对称加密算法: AES (Advanced Encryption Standard),密钥长度: 128 位、192 位、256 位,特点: 高效安全,被广泛使用于各种应用。 DES (Data Encryption Standard),密钥长度: 56 位,特点: 曾是标准,但由于密钥长度较短,安全性不足,现在已被认为不安全。 3DES (Triple DES),密钥长度: 112 位或 168 位(实际强度为 112 位),特点: 基于 DES,通过三次加密提高安全性,但速度较慢。 ChaCha20,密钥长度: 256 位,特点: 设计用于替代 RC4,速度快且安全性高。

非对称加密算法

非对称加密算法使用一对密钥:公钥进行加密,私钥进行解密。其主要优点是密钥管理方便,适用于密钥交换和数字签名。以下是一些常见的非对称加密算法: RSA (Rivest-Shamir-Adleman),密钥长度: 通常为 2048 位或更长,特点: 广泛使用,适用于加密和数字签名,但速度较慢。 DSA (Digital Signature Algorithm),密钥长度: 通常为 1024 位或 2048 位,特点: 主要用于数字签名,不用于加密。

证书的构成

RFC5280规定了X.509证书的语法:

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

TBSCertificate:”TBS”就是”To be signed”的缩写,tbsCertificate的意思就是”要被签名的证书内容”。

证书的结构组成为

  • 版本号 Version 3 (v3),最常用的版本,扩展了 v1 和 v2 的功能,增加了支持扩展字段的能力。允许使用扩展字段(Extensions),如 Basic Constraints、Key Usage、Subject Alternative Name 等,以提供更多的信息和控制证书的使用。

  • 序列号 证书的序列号唯一性原则是每个证书颁发机构(CA)内部独立实施的,这意味着每个 CA 确保其颁发的每个证书的序列号都是唯一的。然而,不同 CA 之间并没有强制要求序列号的全局唯一性。

  • 签名算法 sha256WithRSAEncryption 是一种混合签名算法,表示该签名使用 SHA-256 哈希函数与 RSA 加密算法结合来生成签名。首先,对要签名的数据(例如证书的内容)应用 SHA-256 哈希函数,生成一个 256 位(32 字节)的哈希值。然后,使用 RSA 私钥对生成的哈希值进行加密,生成最终的签名。

  • 发行者

    • 发行者名称

    • 发行者组织

    • 发行者组织单位

    • 发行者组织城市

    • 发行者组织省份

    • 发行者组织国家

    • 发行者组织邮编

    • 发行者组织电子邮件

  • 有效期

  • 主体

    • 主体名称

    • 主体组织

    • 主体组织单位

    • 主体组织城市

    • 主体组织省份

    • 主体组织国家

    • 主体组织邮编

    • 主体组织电子邮件

  • 主体公钥 由私钥生成公钥 openssl rsa -in private.key -pubout -out public.key 查看生成的公钥文件内容 openssl rsa -in public.key -pubin -text -noout

  • 扩展信息

    • 扩展信息类型

    • 扩展信息值

  • 扩展信息

  • 签名值 针对TBSCertificate部分的内容进行签名,包含了证书的基本信息,但不包括签名本身。这些信息通常包括版本、序列号、签发者、有效期、主体等。

证书的生成及解析

一文读懂PE文件签名并手工验证签名有效性 ASN.1本身只定义了表示信息的抽象句法,但是没有限定其编码的方法。 摘自维基百科 由于ASN.1并没有规定编码方式,因此在实际组织数据的时候,还需要一些编码方式,DER就是最常使用的一种,这种编码方式是大字节序的。 CSR 即证书签名申请(Certificate Signing Request) PEM 文件是以 Base64 编码的 ASCII 文本文件,通常包含 —–BEGIN 和 —–END 标记。它们可以包含各种类型的加密数据,包括证书、私钥、公钥和证书链。文件扩展名: .pem, .crt, .cer, .key 使用 OpenSSL 的 x509 命令生成证书时,涉及的私钥和公钥是指证书颁发机构(CA)的私钥和公钥。

# 生成私钥
openssl genrsa -out private.key 2048
# 从私钥生成公钥
openssl rsa -pubout -in private.key -out public.key
# 从证书中导出公钥
openssl x509 -in certificate.crt -noout -pubkey > public.key
# 根据私钥生成证书申请文件csr
# req命令用来生成证书请求文件, 查看验证证书请求文件,还有就是生成自签名证书。
openssl req -new -key private.key -out cert.csr
# 查看csr文件
openssl req -in test.csr -noout -text
# 使用私钥对证书申请进行签名从而生成crt证书
openssl x509 -req -days 365 -in cert.csr -signkey private.key -out cert.crt
# 查看crt文件
openssl x509 -in cert.crt -text -noout
# 生成pem证书,形式和crt一样
openssl x509 -req -days 365 -in cert.csr -signkey private.key -out cert.pem
# pem也可以包含私钥,合并私钥和证书
cat private.key certificate.pem > full_certificate.pem
# 查看crt证书内容
openssl x509 -in cert.crt -text -noout
# 查看证书结构
openssl asn1parse -i -in test.crt
# pem类型的证书转换为der格式
openssl x509 -in test.crt -outform DER -out test.der
# 从der中剥离tbs
dd if=www.cnblogs.com.der of=www.cnblogs.com.tbs bs=1 skip=4 count=1258
# 生成hash值
sha256sum www.cnblogs.com.tbs
# 将crt中的签名值抠出来转换为2进制
xxd -r -p test.sig test.bin
# 使用公钥进行解密
openssl rsautl -inkey public.key -pubin -in test.bin > test.dec
# 解析
openssl asn1parse -i -inform DER -in test.dec
# 比对hash值
# 验签
openssl verify -CAfile test.crt test.crt

证书结构解析(asn1parse结果解析)

解析的格式为:开头数字是偏移量,d 表示深度(depth),d 相同的表示是同一个层级。hl 表示头部长度(header length),l 表示不包含头部的数据长度(lenght)。开头 0 表示偏移量为 0,就是整个文件的开头。d=0 表示最顶层,为整个证书的对象。根据定义,第一个部分就是待签名证书。因此从第一个 d=1 的地方开始,即文件的第二行。

4:d=1 hl=4 l=1254 cons: SEQUENCE
表示偏移量为 4,头部 4 字节,数据 1254 字节。hash 的时候会连头部都算上,所以总共获取 1258 字节。
dd if=www.cnblogs.com.crt of=www.cnblogs.com.tbs bs=1 skip=4 count=1258
bs=1 表示每次读取一个字节,count 表示读取 1258 次,两者组合起来就是读取 1258 个字节

SSL/TLS协议基本流程

主要步骤:

  • 客户端向服务器索要并验证服务器的公钥。

  • 双方协商生产「会话秘钥」

  • 双方采用「会话秘钥」进行加密通信 前两步也就是 SSL/TLS 的建立过程,也就是 TLS 握手阶段。

TLS 的「握手阶段」涉及四次通信,使用不同的密钥交换算法,TLS 握手流程也会不一样的,现在常用的密钥交换算法有两种:RSA 算法 (opens new window)和 ECDHE 算法。 HTTPS工作流程 详细流程如下:

  1. ClientHello 首先,由客户端向服务器发起加密通信请求,也就是 ClientHello 请求。 在这一步,客户端主要向服务器发送以下信息: (1) 客户端支持的 TLS 协议版本,如 TLS 1.2 版本。 (2) 客户端生产的随机数(Client Random),后面用于生成「会话秘钥」条件之一 (3) 客户端支持的密码套件列表,如 RSA 加密算法。

  2. ServerHello 服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello。服务器回应的内容有如下内容: (1) 确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。 (2) 服务器生产的随机数(Server Random),也是后面用于生产「会话秘钥」条件之一 (3) 确认的密码套件列表,如 RSA 加密算法 (4) 服务器的数字证书。

  3. 客户端回应 客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。 如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息: (1) 一个随机数(pre-master key)。该随机数会被服务器公钥加密被公钥加密的是预主秘钥,不涉及前两次随机数,服务器公钥加密预主秘钥只能被保证是服务器私钥才能解密,身份没有被冒充,但是没法保证信息没有被篡改,所以还是需要进行摘要 (2) 加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信 (3) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。 服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。 预主密钥(pre-master secret):是一个随机生成的秘密值,由客户端在握手过程开始时生成,客户端使用服务器的公钥对预主密钥进行加密,以确保只有服务器能够解密。预主密钥的目的是安全地将对称密钥传输给服务器,以便在握手过程完成后建立安全通信所需的主密钥。 主密钥(master secret):是在握手过程中从预主密钥派生的对称密钥,用于加密和解密后续通信中的数据。 主密钥的计算公式: master_secret = PRF(pre_master_secret, “master secret”, ClientHello.random + ServerHello.random) 会话秘钥:是在TLS会话期间用于实际加密和解密数据的对称密钥,使用主密钥和两个随机数,生成会话密钥: session_key = PRF(master_secret, “key expansion”, ServerHello.random + ClientHello.random) 第三次通信主要发送的内容包括:

  • 预主密钥(Pre-Master Secret):如果使用的是RSA加密,预主密钥由客户端生成并使用服务器的公钥加密后发送给服务器。如果使用的是DH或ECDH密钥交换算法,这条消息将包含客户端的公钥。

  • ChangeCipherSpec 消息,这是一个单独的消息,通知服务器客户端将开始使用新协商的会话密钥进行加密通信。这个消息本身并没有被加密或验证,它只是一个信号,表示接下来的消息将使用会话密钥进行加密。

  • Finished 消息:这是握手协议的最后一步,包含了一个验证握手的哈希值(所有先前握手消息的哈希值)。这个消息是用新生成的会话密钥加密的。 如果预主密钥使用的是EDH(Ephemeral Diffie-Hellman)算法,那么就不涉及服务器的公钥了。在使用EDH算法的情况下,密钥交换不依赖于服务器的公钥,而是通过临时的DH密钥对来实现

  1. 服务器的最后回应 服务器收到客户端的第三个随机数(pre-master key)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。 然后,向客户端发送最后的信息:加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。至此,整个 TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。

总结

主密钥是在客户端和服务器端各自通过计算派生得到的,而不是通过传输获取的。 整个过程中涉及服务器的公钥及证书颁发机构的公钥,其中证书颁发机构的公钥是内置于浏览器或者操作系统中的,而服务器的公钥则是在数字证书中。证书颁发机构的公钥主要主要用来进行验签,证明证书是合法的,没有被冒充,服务器的公钥主要用来生成预主秘钥 在TLS的四次通信过程中,前两次握手阶段的通信是明文传输,而第三次和第四次握手之后的通信是使用会话密钥进行加密后传输。 TLS第三次通信后客户端会生成一个随机数,然后使用公钥加密,发送给服务端,服务端解密得到这个随机数,然后客户端和服务端就分别使用三个随机数按照对称加密算法生成相同的会话秘钥进行数据通信 HTTPS 协议本身到目前为止还是没有任何漏洞的,即使你成功进行中间人攻击,本质上是利用了客户端的漏洞(用户点击继续访问或者被恶意导入伪造的根证书),并不是 HTTPS 不够安全 客户端发送的Finished消息中的摘要是以一个hash校验码(verify_data)的形式体现的

证书签发及验证

证书的校验 CA 签发证书的过程,如上图左边部分:

  • 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;

  • 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;

  • 最后将 Certificate Signature 添加在文件证书上,形成数字证书; 客户端校验服务端的数字证书的过程,如上图右边部分:

  • 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;

  • 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;

  • 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。

用户信任 证书的验证过程中还存在一个证书信任链的问题,因为我们向 CA 申请的证书一般不是根证书签发的,而是由中间证书签发的。客户端使用中间证书的公钥来验证服务器证书的签名,客户端使用根证书的公钥来验证中间证书的签名,客户端系统内置了对根证书的信任。

双向认证

一般我们的 HTTPS 是单向认证,客户端只会验证了服务端的身份,但是服务端并不会验证客户端的身份。 如果用了双向认证方式,不仅客户端会验证服务端的身份,而且服务端也会验证客户端的身份。服务端一旦验证到请求自己的客户端为不可信任的,服务端就拒绝继续通信,客户端如果发现服务端为不可信任的,那么也中止通信。 双向认证确保双方都经过验证,从而有效防止中间人攻击。 双向认证