一、前言

在当今数字化时代,安全性和信任是任何在线交易和通信的基石。无论是访问一个安全的网站、发送一封加密邮件,还是下载一个可信的软件,数字证书都在背后默默地发挥着至关重要的作用。数字证书作为公钥基础设施(PKI)的核心组件,通过验证身份和加密数据,确保了互联网和其他网络环境中的安全性和完整性。

数字证书不仅仅是一个简单的加密工具,它们代表了一种信任机制,是确保数据传输和身份验证的关键。随着网络威胁的不断演变和复杂化,理解和正确使用数字证书变得比以往任何时候都更加重要。

二、数字证书标准:X.509

ISO、IEC、ITU——国际三大标准化组织

ITU(International Telecommunication Union):负责信息和通信技术(ICT)领域的国际标准化和协调,包括无线电通信、电信网络、互联网技术和多媒体技术。 (ITU-T G.992.1:ADSL 标准、 ITU-R BT.2020:超高清电视(UHDTV)标准、ITU-T H.264:视频压缩标准、ITU-T G.711:音频压缩标准)

ISO(International Organization for Standardization):负责制定和发布广泛领域的国际标准,包括质量管理、环境管理、信息安全等。

IEC(International Electrotechnical Commission):负责制定和发布电工电子技术领域的国际标准,包括电气设备、电子元件、可再生能源等。

除了 ISO、IEC 和 ITU 这三个国际标准化组织外,IETF、IEEE、W3C 和 ANSI 也是重要的国际标准化组织。

数字证书和X.509之间的关系可以总结为:X.509ITU-T制定的证书标准,它定义了数字证书的格式和内容。大多数现代数字证书都是基于X.509标准的。X.509证书已应用在包括TLS/SSL在内的众多网络协议里,同时它也用在很多非在线应用场景里,比如电子签名服务。X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)。

X.509还附带了证书吊销列表和用于从最终对证书进行签名的证书签发机构直到最终可信点为止的证书合法性验证算法。X.509ITU-T标准化部门基于他们之前的ASN.1定义的一套证书标准。

2.1、X.509 证书内容

证书信息主要分为三类:

  • 被颁发者信息:颁发的域名、关联子域以及所颁给的个人、企业、组织信息等等
  • 证书机构信息:证书颁发机构名称、数字签名等等
  • 证书信息:证书的版本号、序列号、签名算法、签发日期、到期日期、公钥等等

2.1.1、主要字段

  1. 版本号(Version):指定证书的版本,当前常用的是版本3

  2. 序列号(Serial Number):由证书颁发机构分配的唯一编号,用于唯一标识证书。

  3. 签名算法标识符(Signature Algorithm Identifier):指定用于签名证书的算法,如SHA-256 with RSA

  4. 发行者(Issuer):证书颁发机构的名称,通常包括组织名、国家等信息。

  5. 有效期(Validity Period):包含证书的起始日期(Not Before)和终止日期(Not After)。

  6. 主体(Subject):证书持有者的名称,通常包括个人或组织名、部门、国家等信息。

  7. 主体公钥信息(Subject Public Key Info):包含主体的公钥及其算法信息。

  8. 扩展字段(Extensions):版本3证书中引入的可选字段,用于添加额外的信息,如密钥使用、证书策略等。

  9. 签名值(Signature Value):证书颁发机构对证书内容的数字签名,用于验证证书的完整性和真实性。

证书的结构示例:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            01:23:45:67:89:ab:cd:ef
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Example CA, O=Example Organization, C=US
        Validity
            Not Before: Jan  1 00:00:00 2023 GMT
            Not After : Jan  1 00:00:00 2024 GMT
        Subject: CN=www.example.com, O=Example Organization, C=US
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:ab:cd:ef:...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: 
                Digital Signature, Key Encipherment
            X509v3 Basic Constraints: 
                CA:FALSE
    Signature Algorithm: sha256WithRSAEncryption
         ab:cd:ef:...

2.1.2、证书撤销列表

证书撤销列表(Certificate Revocation List, CRL)是由证书颁发机构(CA)发布的一个列表,包含所有已被撤销的证书的序列号。CRL用于检查证书的吊销状态,确保证书的有效性。

CRL 的主要字段:

  1. 版本号(Version):指定CRL的版本,当前常用的是版本2

  2. 签名算法标识符(Signature Algorithm Identifier):指定用于签名CRL的算法,如SHA-256 with RSA

  3. 发行者(Issuer): 证书颁发机构的名称。

  4. 这个更新(This Update)CRL发布的时间。

  5. 下次更新(Next Update):下次发布CRL的预期时间。

  6. 已撤销证书列表(Revoked Certificates):包含所有被撤销证书的序列号和撤销时间。

  7. 扩展字段(Extensions):可选字段,用于添加额外的信息。

  8. 签名值(Signature Value):证书颁发机构对CRL内容的数字签名。

CRL 的结构示例:

Certificate Revocation List (CRL):
    Data:
        Version: 2 (0x1)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Example CA, O=Example Organization, C=US
        This Update: Jan  1 00:00:00 2023 GMT
        Next Update: Jan  1 00:00:00 2024 GMT
        Revoked Certificates:
            Serial Number: 01:23:45:67:89:ab:cd:ef
                Revocation Date: Jan  1 00:00:00 2023 GMT
            Serial Number: 10:20:30:40:50:60:70:80
                Revocation Date: Feb  1 00:00:00 2023 GMT
    Signature Algorithm: sha256WithRSAEncryption
         ab:cd:ef:...

2.1.3、认证框架

X.509还定义了一个认证框架(Authentication Framework),用于在公钥基础设施(PKI)中实现实体身份的认证和信任管理。这个框架包括:

  1. 证书颁发机构(CA):负责签发和管理证书,确保证书的真实性和完整性。

  2. 注册机构(RA):负责验证申请者的身份,并向CA提交签名请求。

  3. 证书持有者(Certificate Holder):持有X.509证书的实体,使用证书进行身份验证和加密通信。

  4. 依赖方(Relying Party):依赖证书进行身份验证和加密通信的实体。

2.1.4、如何读取证书内容

openssl 读取证书内容

openssl x509 -in baidu.com.pem -text -noout

openssl x509 -inform der -in baidu.com.der -text -noout


查看证书的特定部分:

openssl x509 -in baidu.com.pem -noout -subject

openssl x509 -in baidu.com.pem -noout -issuer

openssl x509 -in baidu.com.pem -noout -fingerprint

查看 PEM 格式的 CRL:

openssl crl -in baidu.com.pem -text -noout

查看私钥内容:
openssl rsa -in privatekey.pem -check -noout

Golang读取证书信息Demo

import (
    "crypto/ecdsa"
    "crypto/rsa"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    // 读取PEM格式的证书文件
    certPEM, err := ioutil.ReadFile("./baidu.com.pem")
    if err != nil {
        log.Fatalf("无法读取文件: %v\n", err)
    }
    // 解码PEM块
    block, _ := pem.Decode(certPEM)
    if block == nil {
        log.Fatalf("无法解码PEM块\n")
    }

    // 解析X.509证书
    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        log.Fatalf("无法解析证书: %v\n", err)
    }

    // 打印证书详细信息
    fmt.Printf("证书颁发者:\n\t组织: %v\n\t组织单位: %v\n\t国家: %v\n\t省份: %v\n\t城市: %v\n\t通用名称: %s\n",
        cert.Issuer.Organization, cert.Issuer.OrganizationalUnit, cert.Issuer.Country, cert.Issuer.Province, cert.Issuer.Locality, cert.Issuer.CommonName)
    fmt.Printf("证书主题:\n\t组织: %v\n\t组织单位: %v\n\t国家: %v\n\t省份: %v\n\t城市: %v\n\t通用名称: %s\n",
        cert.Subject.Organization, cert.Subject.OrganizationalUnit, cert.Subject.Country, cert.Subject.Province, cert.Subject.Locality, cert.Subject.CommonName)
    fmt.Printf("有效期自: %s\n", cert.NotBefore)
    fmt.Printf("有效期至: %s\n", cert.NotAfter)
    fmt.Printf("序列号: %s\n", cert.SerialNumber.String())
    fmt.Printf("公钥算法: %s\n", cert.PublicKeyAlgorithm.String())
    fmt.Printf("签名算法: %s\n", cert.SignatureAlgorithm.String())
    fmt.Printf("签名: %s\n", base64.StdEncoding.EncodeToString(cert.Signature))
    fmt.Printf("版本: %d\n", cert.Version)

    // 打印扩展信息
    fmt.Println("扩展信息:")
    for _, ext := range cert.Extensions {
        fmt.Printf("\tID: %s\n\t关键扩展: %v\n\t值 (hex): %x\n", ext.Id.String(), ext.Critical, ext.Value)
    }

    // 打印公钥信息
    switch pub := cert.PublicKey.(type) {
    case *rsa.PublicKey:
        fmt.Printf("RSA公钥位数: %d\n", pub.Size()*8)
        fmt.Printf("RSA指数: %d\n", pub.E)
        fmt.Printf("RSA模数: %x\n", pub.N)
    case *ecdsa.PublicKey:
        fmt.Printf("ECDSA曲线: %s\n", pub.Curve.Params().Name)
        fmt.Printf("ECDSA公钥 X: %x\n", pub.X)
        fmt.Printf("ECDSA公钥 Y: %x\n", pub.Y)
    default:
        fmt.Println("未知公钥算法")
    }

    // 打印证书使用
    fmt.Println("扩展密钥用途:")
    for _, ku := range cert.ExtKeyUsage {
        fmt.Printf("\t%v\n", ku)
    }

    fmt.Println("基本约束:")
    fmt.Printf("\t是否CA: %v\n", cert.IsCA)
    fmt.Printf("\t最大路径长度: %d\n", cert.MaxPathLen)

}

三、数字证书:文件格式

image.png

证书有多种格式的原因主要与不同应用场景、系统兼容性、存储和传输需求有关。每种格式都有其特定的用途和优点,以下是一些关键因素,解释为什么需要这么多不同的证书格式:

系统兼容性

不同的操作系统和应用程序对证书格式的支持不同。例如:

  • PEM 格式广泛用于Unix/Linux系统和开源软件,如ApacheNginxOpenSSL
  • DER 格式通常用于Windows系统,因为它是二进制编码格式,更适合Windows的文件处理方式。
  • JKS 格式专用于Java应用程序,因为它是Java KeyStore的标准格式。

数据类型和用途

不同的证书格式可以包含不同类型的数据,如公钥、私钥、证书链等。例如:

  • PEMDER 格式可以存储公钥、私钥和证书链。
  • PKCS#12 格式可以存储证书、公钥和私钥,适合导出和导入完整的证书链和密钥对。
  • PKCS#7 格式主要用于存储证书链,不包含私钥,适合传输多个证书。

安全性和效率

不同的编码方式和文件结构在安全性和效率上有所不同。例如:

  • DER 格式是二进制编码,更紧凑,适合高效存储和传输,但不易阅读。
  • PEM 格式是Base64编码,易于阅读和编辑,适合手动配置和调试。

标准和协议要求

不同的标准和协议对证书格式有特定要求。例如:

  • SSL/TLS 协议广泛使用PEMDER格式的证书。
  • S/MIME 协议用于电子邮件加密和签名,通常使用PKCS#7格式。
  • Java 应用程序 使用JKS格式的密钥库来管理证书和密钥。

应用场景

不同的应用场景对证书格式有不同的需求。例如:

  • Web 服务器 需要使用PEMDER格式的证书来配置SSL/TLS
  • 电子邮件客户端 需要使用PKCS#7格式的证书来加密和签名电子邮件。
  • SSH 客户端 需要使用PPK格式的私钥来进行无密码登录。

3.1、证书格式的详细信息

以下是常见证书格式的详细信息,包括扩展名、描述和特点:

文件格式 扩展名 描述 特点
PEM (Privacy-Enhanced Mail) .pem, .crt, .cer, .key 基于 Base64 编码的格式,用于存储 X.509 证书、公钥、私钥和证书链 - Base64 编码
- 以“—–BEGIN CERTIFICATE—–”和“—–END CERTIFICATE—–”包围
- 易于阅读和编辑
DER (Distinguished Encoding Rules) .der, .cer 二进制编码格式,用于存储 X.509 证书 - 二进制编码
- 更紧凑,不易阅读
PKCS#7 / P7B (Public Key Cryptography Standards #7) .p7b, .p7c 用于描述加密和签名数据的格式,可以包含多个证书和证书链 - Base64 编码或二进制编码
- 以“—–BEGIN PKCS7—–”和“—–END PKCS7—–”包围(Base64 编码)
- 不包含私钥
PKCS#12 / PFX (Public Key Cryptography Standards #12) .p12, .pfx 用于存储证书、公钥和私钥的格式,通常用于导出和导入证书 - 二进制编码
- 包含证书、公钥和私钥
JKS (Java KeyStore) .jks Java 应用程序使用的密钥库格式,用于存储证书和私钥 - 二进制编码
- 专用于 Java 应用程序
- 包含证书和私钥
PPK (PuTTY Private Key) .ppk PuTTY SSH 客户端使用的私钥文件格式 - Base64 编码
- 专用于 PuTTY SSH 客户端
- 包含私钥
SPC (Software Publisher Certificate) .spc 用于代码签名的证书文件 - 二进制编码
- 包含证书
- 常用于 Windows 系统的代码签名
P7M (PKCS#7 MIME Message) .p7m 用于存储签名和加密的电子邮件消息 - Base64 编码或二进制编码
- 以“—–BEGIN PKCS7—–”和“—–END PKCS7—–”包围(Base64 编码)
- 包含签名和加密消息
CSR (Certificate Signing Request) .csr 包含公钥和身份信息的证书签名请求文件 - Base64 编码
- 以“—–BEGIN CERTIFICATE REQUEST—–”和“—–END CERTIFICATE REQUEST—–”包围
- 用于请求证书签名
CRT (Certificate) .crt, .cer 用于存储证书,可以是 PEM 或 DER 编码 - Base64 编码或二进制编码
- 以“—–BEGIN CERTIFICATE—–”和“—–END CERTIFICATE—–”包围(Base64 编码)
- 用于存储证书
KEY (Private Key) .key 用于存储私钥,可以是 PEM 或 DER 编码 - Base64 编码或二进制编码
- 以“—–BEGIN PRIVATE KEY—–”和“—–END PRIVATE KEY—–”包围(Base64 编码)
- 用于存储私钥

3.2、格式转换

// 将 DER 格式的证书转换为 PEM 格式:
openssl x509 -inform der -in certificate.der -out certificate.pem

// 将 PEM 格式的证书转换为 DER 格式:
openssl x509 -outform der -in certificate.pem -out certificate.der

// PKCS#12 (PFX) to PEM
openssl pkcs12 -in certificate.pfx -out certificate.pem -nodes

// PEM to PKCS#12 (PFX)
openssl pkcs12 -export -out certificate.pfx -inkey privatekey.pem -in certificate.pem -certfile ca-chain.pem

// 将 CSR (证书签名请求) 从 PEM 转换为 DER
openssl req -outform der -in request.csr -out request.der

// 将 DER 转换为 PEM
openssl req -inform der -in request.der -out request.csr -outform pem

// 将私钥从 PEM 转换为 DER
openssl rsa -in privatekey.pem -outform der -out privatekey.der

// 从 PEM 格式的证书和私钥中生成新的 PEM 格式文件
cat certificate.pem privatekey.pem > combined.pem

// 将 RSA 私钥转换为 PKCS#8 格式
openssl pkcs8 -topk8 -inform PEM -outform PEM -in privatekey.pem -out privatekey-pkcs8.pem -nocrypt

四、数字证书:常用分类

数字证书有多种类别,每种类别都有其特定的用途和应用场景:

证书类别 应用场景 子类别 主要用途和区别
SSL/TLS 证书 网站安全、电子商务、在线服务 - 域名验证(DV)证书
- 组织验证(OV)证书
- 扩展验证(EV)证书
- DV:仅验证域名所有权,颁发速度快
- OV:验证域名和组织身份
- EV:严格验证,包括法律地位,浏览器地址栏显示绿色
代码签名证书 软件发布、驱动程序签名 - 标准代码签名证书
- 驱动程序签名证书
- 标准代码签名:用于常规软件
- 驱动程序签名:用于 Windows 驱动程序
客户端证书 企业内部网络、VPN、安全电子邮件 - 个人证书
- 设备证书
- 个人证书:验证个人用户身份
- 设备证书:验证设备身份
S/MIME 证书 电子邮件通信、企业通信 - 个人 S/MIME 证书
- 企业 S/MIME 证书
- 个人 S/MIME:用于个人电子邮件
- 企业 S/MIME:用于企业电子邮件
根证书和中间证书 构建证书链、证书颁发 - 根证书
- 中间证书
- 根证书:顶端证书,用于签发中间证书
- 中间证书:用于签发终端证书,构建信任链
自签名证书 测试环境、内部应用 - 测试证书
- 内部应用证书
- 测试证书:用于开发和测试
- 内部应用证书:用于内部网络和应用
文档签名证书 合同签署、报告签署 - PDF 签名证书
- Microsoft Office 签名证书
- PDF 签名:用于签署 PDF 文档
- Office 签名:用于签署 Office 文档
时间戳证书 法律文件、软件发布 - 标准时间戳证书
- 合规时间戳证书
- 标准时间戳:用于一般时间戳需求
- 合规时间戳:符合法律和行业标准

4.1、SSL/TLS 证书分类

  1. 域名验证(DV)证书:域名验证(DV)证书是最基本的SSL/TLS证书类型。它们仅验证申请者对域名的所有权,不涉及组织身份的验证。DV证书一般用于个人网站/测试使用,DV证书签发速度快、无需人工审核,确保域名验证信息正确的情况下1-15分钟就能签发。DV证书无法为特殊域名/公网IP签发证书(例如:edu.gov.org.jp(国家缩写)等后缀的域名)。DV证书无法将多个域名合并到一张证书内。

    • 验证级别:低
    • 颁发速度:快,通常几分钟到几小时
    • 适用场景:个人网站、小型企业网站
    • 成本:通常较低
  2. 组织验证(OV)证书:组织验证(OV)证书不仅验证域名的所有权,还验证申请者的组织身份。CA会对申请者的组织信息进行审核。OV证书是企业SSL证书的首选,通过企业认证确保代表企业SSL证书的真实性,拒绝网站风险。OV证书支持特殊域名的签发,例如govedu.gov.org.jp(国家缩写)等。OV证书支持证书合并,多张证书(域名)合并签发。

    • 验证级别:中
    • 颁发速度:中等,通常几天
    • 适用场景:中型企业网站、组织网站
    • 成本:中等
  3. 扩展验证(EV)证书:扩展验证(EV)证书是最高级别的SSL/TLS证书。它们进行严格的验证,包括域名所有权、组织身份和法律地位。浏览器地址栏会显示绿色,并显示公司名称。

    • 验证级别:高
    • 颁发速度:慢,通常几天到几周
    • 适用场景:大型企业网站、金融机构、电子商务网站
    • 成本:较高
  4. 通配符(Wildcard)证书:通配符(Wildcard)证书可以保护一个域名及其所有子域名。它们通常用于需要保护多个子域名的网站。

    • 验证级别:根据是DV还是OV/EV证书而定
    • 颁发速度:根据是DV还是OV/EV证书而定
    • 适用场景:需要保护多个子域名的网站
    • 成本:通常较高
  5. 多域名(SAN/UCC)证书,多域名证书(也称为SANUCC证书)可以保护多个不同的域名。这种证书通常用于需要保护多个域名的网站或服务。

    • 验证级别:根据是DV还是OV/EV证书而定
    • 颁发速度:根据是DV还是OV/EV证书而定
    • 适用场景:需要保护多个域名的网站或服务
    • 成本:通常较高
  6. 自签名证书:自签名证书是由组织或个人自己生成和签发的SSL/TLS证书,不依赖于外部证书颁发机构(CA)。它们通常用于内部测试和开发环境。

    • 验证级别:无外部验证
    • 颁发速度:即时
    • 适用场景:测试环境、内部应用
    • 成本:免费,但不被外部信任
证书类别 描述 验证级别 颁发速度 适用场景 成本
域名验证(DV)证书 仅验证域名所有权,不涉及组织身份验证 个人网站、小型企业网站
组织验证(OV)证书 验证域名所有权和组织身份 中等 中型企业网站、组织网站 中等
扩展验证(EV)证书 严格验证域名所有权、组织身份和法律地位,浏览器地址栏显示绿色 大型企业网站、金融机构、电子商务网站
通配符(Wildcard)证书 保护一个域名及其所有子域名 根据验证级别而定 根据验证级别而定 需要保护多个子域名的网站 较高
多域名(SAN/UCC)证书 保护多个不同的域名 根据验证级别而定 根据验证级别而定 需要保护多个域名的网站或服务 较高
自签名证书 由组织或个人自己生成和签发,不依赖外部 CA 无外部验证 即时 测试环境、内部应用 免费,但不被外部信任

4.2、如何区分 DV、OV、EV

域名验证(DV)证书:仅验证域名所有权,通常在“主题”字段中只包含域名信息,不包含公司或组织信息

image.png

组织验证(OV)证书:验证域名所有权和组织身份,在“主题”字段中包含公司或组织信息

image.png

组织验证(EV)证书:进行严格的验证,包括域名所有权、组织身份和法律地位。在“主题”字段中包含详细的公司或组织信息。

image.png

4.3、SSL/TLS 证书域名

SSL/TLS证书中,域名信息存储在证书的特定字段中,这些字段包括Common Name (CN)Subject Alternative Name (SAN)。域名信息在证书颁发时由证书颁发机构(CA)进行验证,并在客户端(如浏览器)访问网站时进行校验。

4.3.1、域名信息存储位置

  1. Common Name (CN)
    • 描述Common Name字段通常包含主域名,例如 baidu.com
    • 使用情况:早期的 SSL/TLS 证书主要使用CN字段存储域名信息,但现代证书更倾向于使用SAN字段。
  2. Subject Alternative Name (SAN)
    • 描述Subject Alternative Name字段可以包含多个域名和子域名,是现代SSL/TLS证书中存储域名信息的主要位置。
    • 使用情况SAN字段允许一个证书保护多个域名和子域名,例如 baidu.comwww.baidu.cn

以下是一个包含域名信息的SSL/TLS证书示例:

➜  Desktop openssl x509 -in baidu.pem -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            4e:40:03:a6:5e:b6:81:f8:7f:4b:d8:eb
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign RSA OV SSL CA 2018
        Validity
            Not Before: Jul  8 01:41:02 2024 GMT
            Not After : Aug  9 01:41:01 2025 GMT
        Subject: C=CN, ST=beijing, L=beijing, O=Beijing Baidu Netcom Science Technology Co., Ltd, CN=baidu.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                ....
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Basic Constraints: critical
                CA:FALSE
            Authority Information Access:
                CA Issuers - URI:http://secure.globalsign.com/cacert/gsrsaovsslca2018.crt
                OCSP - URI:http://ocsp.globalsign.com/gsrsaovsslca2018
            X509v3 Certificate Policies:
                Policy: 1.3.6.1.4.1.4146.1.20
                  CPS: https://www.globalsign.com/repository/
                Policy: 2.23.140.1.2.2
            X509v3 CRL Distribution Points:
                Full Name:
                  URI:http://crl.globalsign.com/gsrsaovsslca2018.crl
            X509v3 Subject Alternative Name:
                DNS:baidu.com, DNS:baifubao.com, DNS:www.baidu.cn, DNS:www.baidu.com.cn, DNS:mct.y.nuomi.com, DNS:apollo.auto, DNS:dwz.cn, DNS:*.baidu.com, DNS:*.baifubao.com, DNS:*.baidustatic.com, DNS:*.bdstatic.com, DNS:*.bdimg.com, DNS:*.hao123.com, DNS:*.nuomi.com, DNS:*.chuanke.com, DNS:*.trustgo.com, DNS:*.bce.baidu.com, DNS:*.eyun.baidu.com, DNS:*.map.baidu.com, DNS:*.mbd.baidu.com, DNS:*.fanyi.baidu.com, DNS:*.baidubce.com, DNS:*.mipcdn.com, DNS:*.news.baidu.com, DNS:*.baidupcs.com, DNS:*.aipage.com, DNS:*.aipage.cn, DNS:*.bcehost.com, DNS:*.safe.baidu.com, DNS:*.im.baidu.com, DNS:*.baiducontent.com, DNS:*.dlnel.com, DNS:*.dlnel.org, DNS:*.dueros.baidu.com, DNS:*.su.baidu.com, DNS:*.91.com, DNS:*.hao123.baidu.com, DNS:*.apollo.auto, DNS:*.xueshu.baidu.com, DNS:*.bj.baidubce.com, DNS:*.gz.baidubce.com, DNS:*.smartapps.cn, DNS:*.bdtjrcv.com, DNS:*.hao222.com, DNS:*.haokan.com, DNS:*.pae.baidu.com, DNS:*.vd.bdstatic.com, DNS:*.cloud.baidu.com, DNS:click.hm.baidu.com, DNS:log.hm.baidu.com, DNS:cm.pos.baidu.com, DNS:wn.pos.baidu.com, DNS:update.pan.baidu.com
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Authority Key Identifier:
                F8:EF:7F:F2:CD:78:67:A8:DE:6F:8F:24:8D:88:F1:87:03:02:B3:EB
            X509v3 Subject Key Identifier:
                AD:CA:00:54:CA:D8:E5:94:B6:8F:83:DA:27:80:28:4E:59:24:3B:18
            CT Precertificate SCTs:
                ....

4.3.2、域名信息的校验时机

  1. 证书颁发时:证书颁发机构(CA)在颁发SSL/TLS证书之前会进行域名验证,以确保申请者对域名的所有权。验证方法包括:

    • DNS 验证CA要求申请者在域名的DNS记录中添加特定的TXT记录,以证明对域名的控制权。
    • 文件验证CA要求申请者在域名对应的网站根目录中上传一个特定文件,以证明对域名的控制权。
    • 电子邮件验证CA向域名注册信息中的电子邮件地址发送验证邮件,申请者需要点击邮件中的验证链接。
  2. 客户端访问时:当客户端(如浏览器)访问一个使用SSL/TLS的网站时,会进行以下校验:

    • 证书链验证:客户端验证证书链的完整性,确保证书是由受信任的CA颁发的。
    • 域名匹配验证:客户端检查证书中的域名信息(CNSAN字段)是否与用户访问的域名匹配。如果不匹配,浏览器会显示安全警告。

五、证书签发和验签

image.png

5.1、证书签发

image.png

5.2、证书链

5.2.1、什么是证书链?

证书链(Certificate Chain),也称为证书路径,是指一系列相互信任的证书组成的链条,从最终用户的证书(也称为终端证书或叶证书)开始,经过一个或多个中间证书,最终到达根证书(Root Certificate)。每个证书都由上一级证书颁发机构(CA)签名,形成一条信任链。

证书链的组成部分:

  1. 终端证书(End-Entity Certificate)

    • 这是实际用于服务器或客户端的证书,例如网站的SSL/TLS证书。
    • 由中间证书或根证书签发。
  2. 中间证书(Intermediate Certificate)

    • 由根证书或另一个中间证书签发,用于签发终端证书。
    • 中间证书可以有多个层级,形成中间证书链。
  3. 根证书(Root Certificate)

    • 位于证书链的顶端,由受信任的根证书颁发机构(CA)签发。
    • 根证书是自签名的,并且预先安装在操作系统和浏览器中,作为信任的根源。

5.2.2、证书链的作用

  1. 建立信任关系:证书链通过逐级验证,从终端证书到根证书,建立起一个信任关系。客户端(如浏览器)通过验证整个证书链,确保终端证书是由受信任的CA签发的。

  2. 简化证书管理:使用中间证书可以简化证书管理和部署。根证书通常长期有效,而中间证书和终端证书可以更频繁地更新,以提高安全性。

  3. 增强安全性:证书链通过多级验证机制,增加了攻击者伪造证书的难度。即使某个中间证书被泄露,也可以通过吊销该证书来保护整个信任链。

  4. 便于证书撤销:如果某个中间证书或终端证书被发现存在安全问题,可以通过证书撤销列表(CRL)或在线证书状态协议(OCSP)吊销该证书,确保整个信任链的安全性。

5.2.3、证书链的验证过程

  1. 用户访问网站:用户在浏览器中输入网址并访问网站,服务器返回 SSL/TLS 证书和中间证书。

  2. 浏览器接收证书链:浏览器接收终端证书和中间证书,并开始验证证书链。

  3. 验证证书链:浏览器从终端证书开始,逐级验证每个证书的签名,直到到达根证书。浏览器检查每个证书的有效期、签名和吊销状态。

  4. 根证书验证:浏览器检查根证书是否在其预先安装的受信任根证书列表中。如果是,则信任该证书链。

  5. 建立安全连接:如果证书链验证通过,浏览器与服务器之间建立安全的SSL/TLS连接。

以下是一个典型的证书链示例:

Root Certificate (Root CA)
    |
    v
Intermediate Certificate (Intermediate CA)
    |
    v
End-Entity Certificate (www.example.com)

5.3、 交叉证书

交叉证书(Cross-Certificate)是一种数字证书,它用于建立两个不同证书颁发机构(CA)之间的信任关系。通常在涉及多个信任域或CA之间的互操作性时会用到交叉证书。交叉证书使两个不同的PKIPublic Key Infrastructure)体系能够互相信任彼此的证书,从而扩展信任链的范围。

交叉证书的应用场景:

  1. 跨组织信任: 当两个不同的组织或企业希望互相验证对方的用户或设备时,可能会使用交叉证书来建立相互信任的关系。
  2. 过渡期间的信任延续: 当组织从一个CA迁移到另一个CA时,可以使用交叉证书确保新旧CA之间的互操作性和信任过渡。
  3. 多路径验证: 某些大型组织可能会同时依赖多个CA进行证书签发,交叉证书可以使不同的CA信任链互相验证,确保系统兼容性。

交叉证书的工作原理:

  1. 准备证书和密钥

    • 确保你有两个 CACA1CA2
    • CA1 的私钥和公钥证书。
    • CA2 的私钥和公钥证书。
  2. 生成证书签名请求(CSR)

    • 使用CA2的私钥生成一个证书签名请求(CSR)。CSR包含CA2的公钥和一些身份信息。
  3. 使用 CA1 签名 CA2 的 CSR

    • 使用CA1的私钥对CA2CSR进行签名。这一步骤会生成一个新的证书,该证书由CA1签发,并包含CA2的公钥。
  4. 生成交叉证书

    • 生成的证书即为交叉证书,它表明CA1信任CA2,并将CA2的公钥包含在其中。

QQ_1722091218807.png

5.4、证书验证测试

我们用Chrome浏览器打开baidu.com,然后如下图:

QQ_1722056409592.png

我们可以分别导出中间证书(GlobalSignRSAOVSSLCA2018.pem)和网站证书(baidu.com.pem),同时可以看到根证书(GlobalSign)的序列号是04:00:00:00:00:01:21:58:53:08:A2

打开Mac系统的KeyChain Access,找到根证书(GlobalSign.pem)导出用于代码测试证书:

QQ_1722056893671.png

证书校验验证代码如下:

func main() {
    rootCertPath := "./GlobalSign4.pem"
    middleCertPath := "./GlobalSignRSAOVSSLCA2018.pem"
    certPath := "./baidu.com.pem"

    err := verifyCertificate(certPath, middleCertPath, rootCertPath)
    if err != nil {
        log.Fatalf("Certificate verification failed: %v", err)
    }

    fmt.Println("Certificate verification succeeded.")
}

func verifyCertificate(certPath, middleCertPath, rootCertPath string) error {
    roots, err := loadRootCert(rootCertPath)
    if err != nil {
        return err
    }

    intermediates, err := loadRootCert(middleCertPath)
    if err != nil {
        return err
    }

    cert, err := loadCertificate(certPath)
    if err != nil {
        return err
    }

    opts := x509.VerifyOptions{
        Roots:         roots, // 根证书
        Intermediates: intermediates, // 中间证书
    }

    chain1, err := cert.Verify(opts)
    println(chain1)
    return err
}

func loadRootCert(path string) (*x509.CertPool, error) {
    rootPEM, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("failed to read root CA file: %v", err)
    }

    roots := x509.NewCertPool()
    if !roots.AppendCertsFromPEM(rootPEM) {
        return nil, fmt.Errorf("failed to add root CA to pool")
    }

    return roots, nil
}

func loadCertificate(path string) (*x509.Certificate, error) {
    certPEM, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("failed to read certificate file: %v", err)
    }

    block, _ := pem.Decode(certPEM)
    if block == nil || block.Type != "CERTIFICATE" {
        return nil, fmt.Errorf("failed to decode PEM block containing certificate")
    }

    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        return nil, fmt.Errorf("failed to parse certificate: %v", err)
    }

    return cert, nil
}

六、如何申请数字证书

阿里云证书申请:

QQ_1722080736834.png

acme.sh 免费证书申请:

使用 ACME.SH 申请证书

export Ali_Key="abcd"
export Ali_Secret="xxxxxxxxxx"
# RSA 证书
acme.sh --issue --dns dns_ali -d fanlv.fun -d fanlv.fun  -d "*.fanlv.fun"  --debug

# 更新证书
$HOME/.acme.sh/acme.sh --renew -d fanlv.fun --force


# 安装证书
$HOME/.acme.sh/acme.sh  --install-cert -d fanlv.fun  -d "*.fanlv.fun"  \
--cert-file      $GOPATH/src/xx/cert.pem  \
--key-file       $GOPATH/src/xx/key.pem

七、参考资料

网络安全科普:奇妙的 SSL/TLS 证书

Cross-Signing and Alternate Trust Paths; How They Work