☰
认识数字证书 X509 der 公钥 签名 验签等概念
2026/10/14 20:26:50 网站建设 项目流程

数字证书

数字证书是一种用于安全通信的文件,其中包含与证书持有者相关联的信息,如公钥和证书持有人的身份信息。 数字证书通常用于在互联网上建立安全连接,如 HTTPS,SSL 和 TLS。

数字证书是由一定格式的数据构成的,主要包括以下基本格式:
证书版本号:指明证书的版本号,目前一般采用版本号为3的X.509证书。
证书序列号:由颁发者(CA)生成的唯一的序列号,用于区分同一颁发者下不同证书的唯一编号。
签名算法标识:指明签名使用的算法,比如SHA1withRSA、SHA256withRSA等。
颁发者(CA)信息:包括组织名称、CA名称、联系电话、电子邮件等信息。
证书有效期:包括证书的起始时间和结束时间,用以确定证书的有效期限。
证书主题信息:与证书标识的使用者有关的信息,比如用户的身份、邮箱、组织或企业信息等。
公钥信息:含有公钥,包括算法、主要参数和公钥值等;
扩展信息:用于附加证书的信息,比如Subject Alternative Name、Key Usage等扩展属性。

数字证书分类
根据证书持有者分类
  • 个人数字证书:通常由公共认证机构(CA)颁发,用于个人身份认证和文件签名加密等场景。例如,个人身份证数字证书就是一种非常常见的个人数字证书。
  • 机构数字证书:用于机构身份认证,例如公司的组织机构代码证和营业执照等。机构数字证书也可以由CA颁发。
  • 代码签名证书:用于代码的签名,以证明代码的来源和无篡改。例如,微软的Authenticode证书就是一种代码签名证书。
  • 服务器数字证书:用于验证网站服务器的身份,保护网络通信过程中的数据安全。例如,TLS/SSL协议就需要使用服务器数字证书来确保客户端与服务器之间的通信安全。
  • 设备证书:用于设备身份认证和数据安全保护等场景。例如,苹果公司的设备证书用于验证iPhone和其他设备的身份和安全性。
这些数字证书的主要作用都是进行身份验证和加密数据传输,从而保护个人隐私和技术安全。
根据证书密钥分类
  • 对称密钥证书:这种证书使用相同的密钥来加密和解密数据,因此也称为共享密钥证书。对称密钥证书通常用于加密小范围数据,例如文件传输时的本地文件加密和解密等。但是,用于对称密钥证书加密的密钥需要安全的传输,因此目前对称密钥证书的使用比较有限。
  • 非对称密钥证书:这种证书使用公钥和私钥来加密和解密数据,因此也称为公私钥证书。通过使用非对称密钥证书,数据发送方可以使用接收方的公钥来加密数据,只有接收方可以使用自己的私钥来解密数据。非对称密钥证书广泛用于数字签名、加密通信等场景,通过证书机构的认证可以为公钥证明持有者的身份和信用度。

X509

X.509证书是国际电信联盟电信标准化部门(ITU-T)制定的数字证书标准,用于公钥基础设施(PKI)中以实现身份认证与数据加密。该标准定义了证书的格式、字段及编码方式,包含版本号、序列号、颁发者、有效期、主体公钥等核心信息,采用ASN.1/DER编码规范。X.509证书通过数字签名确保数据完整性,广泛应用于HTTPS、SSL/TLS协议及物联网设备认证等场景。

该标准自1988年发布版本1以来历经3次迭代:版本1确立基础框架;1993年版本2引入颁发者与主体唯一标识符,但应用有限;1996年版本3通过扩展字段增强功能,支持密钥用途限制、备用名称绑定等特性,成为主流实现标准。证书编码涵盖DER二进制与PEM Base64格式,文件扩展名包括.pem、.crt等,其验证机制依赖CA信任链与证书吊销列表(CRL)。

DER

DER格式是一种二进制编码规范,用于存储X.509证书、私钥及其他ASN.1结构化数据。其文件扩展名常为.der或.cer(.cer扩展名也可能用于Base64编码的证书,但本质仍遵循DER结构)。

DER格式严格遵循ASN.1编码规则,采用类型- 长度- 值(TLV)三元组结构。例如,对于一个X.509证书,DER编码会将证书的各个字段(如版本号、序列号、公钥算法等)分别编码为对应的TLV结构。版本号可能表示为一个字节的类型值(如0x02),紧跟一个字节表示长度(通常为1),再接着是版本号的具体值(如0x03,表示版本3)。这种精确的二进制编码使得DER格式在存储上更为紧凑,相比PEM格式,文件体积更小。

DER格式适用于对存储体积和读取效率要求较高的场景,如移动设备、智能卡以及部分对资源敏感的嵌入式系统。在移动应用开发中,若需要在设备端存储SSL证书进行安全通信,DER格式可有效减少证书存储占用的空间,提升应用的性能表现。同时,一些硬件安全模块(HSM)也更倾向于使用DER格式的证书与私钥,以实现高效的加密运算与安全存储。

ASN.1 (Abstract Syntax Notation One) 是一种用于定义数据结构的抽象语法标记,在数字证书领域,ASN.1被广泛应用于X.509证书和CRL(certificate revocation lists)的编码和解码。
  • 数字证书由一组格式化信息组成,比如证书主题(subject)、证书颁发者(issuer)、公钥、证书序列号(serial number)、有效期(validity period)等等。这些信息用ASN.1格式的数据结构描述。
  • X.509数字证书主要采用DER编码,也可以采用PEM编码。DER编码是二进制格式的ASN.1编码格式,而PEM编码则是将DER编码的数据放在PEM文件(纯文本)中,类似于Base64编码。其中DER编码相对更为紧凑,PEM编码则更方便传输和存储。
  • 在ASN.1中的数据类型有很多种,比如Bit String、Integer、Object Identifier、Sequence等等,在数字证书中常用的数据类型包括:INTEGER、BIT STRING、SEQUENCE、OBJECT IDENTIFIER等。

PEM

PEM格式采用Base64编码,将二进制数据转换为可打印的ASCII字符,以文本形式存储证书与私钥。其文件通常以.pem为扩展名,内容由“-----BEGIN CERTIFICATE-----”与“-----END CERTIFICATE-----”(针对证书)或“-----BEGIN PRIVATE KEY-----”与“-----END PRIVATE KEY-----”(针对私钥)等标记封装。

PKCS#12

PKCS#12格式是一种用于存储用户私钥、证书及相关加密信息的容器标准。其文件通常以.p12或.pfx(PFX是PKCS#12之前的格式,现多被PKCS#12替代,但仍有部分系统支持)为扩展名,可将多个证书(如服务器证书、中间证书链)与私钥整合在一个文件中,并通过密码保护,增强了密钥存储的安全性。

pfx证书包含私钥。

Pfx证书既可以导出为pfx证书,也可以导出为cer证书。

Pfx证书导出时,会提示是否导出私钥,导出私钥即pfx证书,不导出则是cer证书。

公钥

公钥用于验签和证书主体的验证

java解析证书获取公钥源码如下:

public class Base64ToPublicKey { public static PublicKey getPublicKeyFromBase64(String base64Cert) throws Exception { // Step 1: Decode the Base64 string to a byte array byte[] certificateBytes = Base64ToPublicKey.decodeBase64(base64Cert); // Step 2: Load the certificate from the byte array X509Certificate certificate = loadCertificate(certificateBytes); // Step 3: Extract the public key from the certificate return getPublicKeyFromCertificate(certificate); } public static byte[] decodeBase64(String base64String) { return Base64.getDecoder().decode(base64String); } public static X509Certificate loadCertificate(byte[] certificateBytes) throws Exception { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); ByteArrayInputStream inputStream = new ByteArrayInputStream(certificateBytes); return (X509Certificate) certificateFactory.generateCertificate(inputStream); } public static PublicKey getPublicKeyFromCertificate(X509Certificate certificate) { return certificate.getPublicKey(); } public static void main(String[] args) throws Exception { // String base64Cert = "MIIFKTCCBBGgAwIBAgINK2j3HjOIXzI6GIoHVDANBgkqhkiG9w0BAQsFADAxMQswCQYDVQQGEwJDTjENMAsGA1UECgwEQkpDQTETMBEGA1UEAwwKTVNTUENBIFJTQTAeFw0yNTEwMjEwNDQ2MjdaFw0zMDEwMjEwNTQ2MjdaMHMxCzAJBgNVBAYTAkNOMVAwTgYKCZImiZPyLGQBAQxAMDRmNjQyNGNiNjM2NTIwNGVhOGUzNjMxZmZjNGMyM2Y5OTVhZjA5M2M1OWFjMzg3MTVhNjc2OTFjYTg5ODYwZDESMBAGA1UEAwwJ5p2O5pmT6Im6MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvZnhr7yZbcXIxpDrVoOTLmx26RCuAM2VO7z+ohB9zAlvO9viJzbbyEqHTlxvaqD5Y34YZABrGCTtGS0VNiLYBgw1351xTmVDNuK5acGgLTmI+e98cse1FfxjQa/xnmgP3mrgBCvRw5VpXpEmUX+46xzN4/mR8jfkaN06VSolVhh3I/A+QecZUDqpA/3SSg60szg+03Y+46eX0R60/RAFDpoSmnjDYMwnL1rArqhj0mOsvl+wkDlwchkuHsGsRzyPCHXiqMNMUvJPVSqfV3oOMR2bMKrsrGgBUS80E8J0NAIBNXvybWq6jiPLuNWJs024JLTCGxXTXQzQj9dnyMkgcQIDAQABo4IB/DCCAfgwDgYDVR0PAQH/BAQDAgbAMAkGA1UdEwQCMAAwHQYDVR0OBBYEFIgzZleVzgGDtcpEzFOX7dRw7h9AMB8GA1UdIwQYMBaAFDdJ2+awfg5xisXbeZ5jlvi8XFaTMD0GA1UdIAQ2MDQwMgYJKoEchu8yAgIDMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vd3d3LmJqY2EuY24vQ1BTMIGJBgNVHR8EgYEwfzBCoECgPoY8aHR0cHM6Ly9jcmwuYmpjYS5vcmcuY246ODQ0My9jcmwvTVNTUF9SU0FfMzIvTVNTUF9SU0FfMzIuY3JsMDmgN6A1hjNodHRwczovL2NybC5iamNhLm9yZy5jbjo4NDQzL2NybC9NU1NQX1JTQV8zMi84NS5jcmwwgYAGCCsGAQUFBwEBBHQwcjA9BggrBgEFBQcwAoYxaHR0cHM6Ly9yZXBvLmJqY2EuY24vbmF0aW9uYWwvY2VydC9NU1NQQ0FfUlNBLmNydDAxBggrBgEFBQcwAYYlaHR0cHM6Ly9jYW9jc3AuYmpjYS5vcmcuY246ODA2Mi9vY3NwLzBNBghghkgBhvhEAgRBNDI0MWM1NWI5NjJkZDgwOXFiNGQ0dzM2Y2J5NWY3MDg1Y2MmJnAvaDROTWRWbHZDZ2IraStDbTh1cyt1QlFJZz0wDQYJKoZIhvcNAQELBQADggEBAB9MAjEMMjrsck4J8M4SJuwcImwp30Xq2aji/U1e5Wla4rkoWfdOy9TJ1jrpm930eTEKFVkwzQ2j5MGJhMUF9e0R4b+SpAEy6IIPslkJrMBcvWsd/eo9jNioQ42yqwrXlhCt9PQ/gQ264o60bQnnXnpppmfXzeHfbOJhP9z9CHJGq8t1crpLunB61eRJFmnQeCeOabHCqfLoDLjf6c/YXzOd+6wuU72ukkldomCo+qHPbDyg/Mok5fyXsIDmRmTKCKCCVZjWwNqgKnO2i3NPTCLO+C7nKyVN2SpeV4g+dMKSvGCBZzgDN8nHBOCYKbpfnZ6f8j6LP2m/6HsFmv/yrSI="; // Replace with your actual Base64 encoded certificate string PublicKey publicKey = getPublicKeyFromBase64(base64Cert); System.out.println("公钥算法:" + publicKey.getAlgorithm()); System.out.println("公钥格式:" + publicKey.getFormat()); System.out.println("公钥内容:" + Base64.getEncoder().encodeToString(publicKey.getEncoded())); } }

但rsa证书可解析出公钥,sm2的会报错,Unknown named curve: 1.2.156.10197.1.301;因为jdk默认不支持SM2,需要引入第三方库或者使用其他的jdk版本,这里通过引入第三方库的方式解决

maven依赖

<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.68</version> </dependency>

代码调整

static{ Security.addProvider(new BouncyCastleProvider()); } //增加provider的入参 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");

https://blog.csdn.net/weixin_44326073/article/details/134548556

CER&CRT

cer证书只包含公钥。

CER格式是一种通用的证书文件格式,通常用于存储单个证书或证书链。证书链是指从受信任的根证书到最终实体证书的一系列证书,用于验证证书的真实性和有效性。

  1. CER证书

    • 定义:CER文件通常指的是符合X.509标准的二进制编码的证书文件。这种格式主要用于Windows操作系统中的证书存储和管理。
    • 用途:CER证书常用于SSL/TLS加密、电子邮件签名、代码签名等场景。在Windows环境中,它们可以被直接导入到证书存储中以供使用。
  2. CRT证书

    • 定义:CRT文件也是基于X.509标准的证书文件,但它通常以PEM(Privacy-Enhanced Mail)或Base64编码的形式存在。这种格式在Unix/Linux系统中更为常见。
    • 用途:CRT证书同样适用于SSL/TLS加密、电子邮件签名等场景。然而,由于其文本编码的特性,CRT证书更便于在不同系统之间传输和查看。
  • CER证书:采用DER(Distinguished Encoding Rules)编码,这是一种二进制的编码方式。DER编码紧凑且高效,但不易于人类阅读。CER证书在Windows系统中得到了广泛的支持和应用。然而,在其他操作系统中,可能需要额外的工具来处理和识别这种格式.
  • CRT证书:通常采用PEM编码,这是一种基于Base64的文本编码方式。PEM编码的文件包含开始标记(如-----BEGIN CERTIFICATE-----)和结束标记(如-----END CERTIFICATE-----),并易于通过文本编辑器进行阅读和编辑。CRT证书在多种操作系统和平台上都得到了良好的支持。这使得CRT证书成为跨平台部署的首选格式之一。

虽然CER和CRT有差异,但可以使用工具进行转换。例如,在Windows系统中,可以使用OpenSSL等工具将CER证书转换为CRT证书;反之亦然。

签名&验签

签名: 发送方使用消息摘要算法(例如MD5)对发送的报文原文生成消息摘要,然后用自己的私钥对这个摘要进行加密,得到的密文就是这个报文原文对应的数字签名。通常来说,发送方会把数字签名和报文原文一并发送给接收方,用于接收方对报文原文生成消息摘要,比较二者是否一致,以判断数据是否被篡改。

验签: 接收方同时接收报文原文和数字签名后,会使用发送方的公钥对数字签名进行解密,这个过程就被称为验签。成功解密后得到一个消息摘要A,同时使用相同的消息摘要算法(例如MD5)对报文原文进行hash处理,得到一个消息摘要B,最后对比报文摘要A和报文摘要B是否一致,即可确定报文原文是否被篡改过。


数字签名

非对称加密搭配对称加密使用,实现数字签名,常见的方式如RSA搭配SHA256。

SHA256对称加密,对称加密相对于非对称加密效率高,用于加密原文较长的信息,比如待签原文;RSA是非对称加密,效率比对称加密低。

保证数据的真实性: 如果接收方使用发送方的公钥能够成功解密出数据(即验签),就证明该数据是发送方发送的,因为别人没有发送方的私钥,加密不了数据,就生成不了签名,即假冒不了发送方的签名。
保证数据的完整性: 如果接收方对发送方发送的报文原文使用消息摘要算法(例如MD5)生成hash值,和公钥解密出来的消息摘要一致,就证明数据没有被篡改。

签名和加密的区别


签名: 目的是为了验证身份,检查篡改,防止重放攻击(可通过加时间戳或者nonce的方式),防止中间人假装自己对外发送假信息,不需要对数据进行加密处理(因为加密了也没有,公钥是公开的,谁都可以解密),因此需要私钥进行加密(签名),用公钥进行解密(验签)。(谁都可以解密,但是只有自己能够加密)。

加密: 目的是将明文变成密文进行传输,防止消息在传输中被人破解,因此使用公钥加密(谁都可以加密,但是只有自己能够解密),使用私钥解密。

P10、P1、P12、P7区别

P10、P1、P12、P7 都源自PKCS(公钥密码学标准)系列,由 RSA 实验室制定,用于规范数字证书和密钥的格式与操作。它们各司其职,用途完全不同:P10 用于申请证书,P1 是 RSA 算法的底层规范,P7 用于封装证书链,P12 用于打包私钥和证书。

P10 是证书签名请求的标准格式。当你需要向 CA(证书颁发机构)申请证书时,你会在本地生成一对密钥,然后创建一个包含公钥和身份信息(如域名、组织名)的 CSR 文件。

P10 的核心作用有两个:一是向 CA 提供签发证书所需的身份信息和公钥;二是用你自己的私钥进行签名,向 CA 证明你确实持有对应的私钥(即“持有证明”)。CA 验证通过后,才会签发证书。常见的 P10 文件扩展名有.csr、.p10等。

P1 定义了 RSA 公钥和私钥的数学结构、加密解密机制、签名验签机制,以及密钥的 ASN.1 编码方式。你在其他格式(如 P7、P12)里看到的 RSA 密钥,其内部数据结构就是遵循 P1 标准的。日常工作中,一般不会直接“打开”一个 P1 文件,它更多是作为底层规范被其他格式引用

P7 是一种通用的加密消息语法,核心用途是打包和传输证书链。

它最典型的应用场景是:你从 CA 收到服务器证书时,CA 通常还会一并提供中间 CA 证书,P7 可以把服务器证书和所有中间证书打包在一个文件里(.p7b或.p7c),方便你一次性安装。需要特别注意:P7 只能存储证书,不能存储私钥。它支持 DER 和 PEM 两种编码方式。

P12 是最完整的“证书包”,它把一个实体的私钥、公钥证书,以及完整的证书链全部打包在一个文件里。

由于包含了敏感的私钥,P12 文件通常使用密码进行强加密保护,并带有完整性校验(MAC)。它最常见的扩展名是.p12和.pfx。P12 的核心价值在于迁移和备份:你可以把服务器 A 上的 SSL 证书(含私钥)导出为 P12,再导入到服务器 B,从而无损地转移身份。

参考:https://blog.csdn.net/m0_70731516/article/details/148795580

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询