深入分析SSL/TLS服务器的证书(C/C++代码实现)

avatar
作者
猴君
阅读量:2

SSL(Secure Sockets Layer)和TLS(Transport Layer Security)是网络安全领域的重要协议,它们在保护网络通信中发挥着至关重要的作用。这些协议通过加密和身份验证机制,确保数据在传输过程中的机密性和完整性,防止数据被窃取或篡改。

这些协议的关键组成部分之一是SSL/TLS服务器的证书,它为服务器提供了一种身份验证和加密的方式

详细解释SSL/TLS的重要性

以下将详细解释SSL/TLS的重要性:

  1. 加密保护:SSL/TLS协议使用对称密钥和非对称密钥技术对数据进行加密,确保只有目标接收者能够解密并阅读信息。这种加密保护使得敏感信息如信用卡详情、医疗记录和个人身份信息在互联网传输时得到保护。
  2. 身份验证:SSL/TLS通过证书的使用提供了身份验证机制。服务器必须出示由可信证书颁发机构签发的证书,客户端可以验证服务器的真实性,以防止中间人攻击。
  3. 数据完整性:这些协议确保数据在传输过程中不被篡改。任何对传输数据的未授权修改都会被检测出来,从而保证了数据的完整性。
证书的基础结构

SSL/TLS服务器的证书是基于公钥基础设施构建的,其中包含以下几个关键部分:

  • 主题:证书的主题指定了证书持有者的详细信息,包括组织名称、城市、国家代码等。
  • 颁发者:颁发者是签发证书的证书颁发机构。
  • 公钥:证书包含一个公钥,用于加密信息或验证数字签名。
  • 签名算法:此部分指明了CA用来签署证书的加密算法。
  • 有效期:证书的有效期起始日期和结束日期,指明了证书的有效期限。
证书链分析是理解SSL/TLS安全性的关键环节

在网络安全中,SSL和TLS协议通过加密保障数据传输的安全性,而这一过程的核心是证书链的验证。

  1. 证书链的基本概念

    • 证书链定义:证书链是指由多个证书组成的信任链,从根证书(Root Certificate)开始,通过一级或多级中间证书(Intermediate Certificates),最终到达服务器证书(Server Certificate)。
    • 根证书的作用:根证书是证书链的起点,由可信的证书颁发机构(CA)签发。根证书的公钥广泛预装在各种操作系统和浏览器中,因此通常被无条件信任。
    • 中间证书的作用:中间证书作为根证书与用户证书之间的中间环节,起到传递信任的作用。它们由根证书签发,并依次签发下级证书,形成完整的证书链。
    • 服务器证书的作用:服务器证书是证书链的末端,直接用于SSL/TLS通信中的身份验证和加密。服务器证书由中间或根证书签发,证明服务器的真实身份。
  2. 证书链的验证过程

    • 证书路径构建:客户端接收到服务器证书后,会检查证书中指定的颁发者信息,并尝试构建从服务器证书到可信任根证书的完整路径。
    • 单向验证与双向验证:在某些情况下,只需验证服务器证书是否由可信CA签发(单向验证)。在其他情况下,还需验证CA的合法性,即从服务器证书到根证书的每一级证书都需要进行验证(双向验证)。
    • 证书吊销状态检查:客户端可以通过查询证书吊销列表(CRL)或在线证书状态协议(OCSP)来检查证书是否被吊销,确保证书的有效性。
    • 签名验证:每个证书都包含上一级证书的签名。客户端会使用上一级证书的公钥验证该签名的合法性,从而确保整个证书链的完整性和真实性。
  3. 证书链的重要性

    • 防止中间人攻击:通过完整的证书链验证,客户端可以确保自己与真正的服务器进行通信,而非被中间人冒充的假服务器。
    • 增强用户信任:当浏览器能够成功验证证书链并显示安全锁标志时,用户对网站的信任度会提高,这在电子商务和敏感信息传输中尤为重要。
  4. 证书链的潜在问题与解决方案

    • 路径验证失败:如果客户端无法构建有效的证书路径或某个证书无法通过验证,会导致路径验证失败。这通常会引起浏览器的安全警告,提示用户证书不可信。
    • 中间证书缺失:如果服务器没有提供完整的证书链,而是仅提供了服务器证书,部分客户端可能无法自动获取和验证中间证书,造成验证失败。解决这一问题的方法是在服务器配置中包含完整的证书链。
    • 根证书不信任:如果客户端不信任根证书,整个证书链也会被认为是不可信的。因此,选择广泛信任的CA颁发的证书至关重要。
  5. 实际案例分析

    • 案例一:Let’s Encrypt:Let’s Encrypt是一个广泛使用的免费CA,其证书链包括一个根证书和一个中间证书。由于其根证书已被大多数现代浏览器预信任,因此在使用时通常不会出现验证问题[1]。
    • 案例二:自签名证书:一些网站可能会选择使用自签名证书来节省成本,但由于这些证书不是由可信CA签发,因此在公共网络上几乎总是会引发浏览器的安全警告。
    • 案例三:过期中间证书:如果服务器的中间证书过期,即使根证书和服务器证书仍然有效,也会导致整个证书链验证失败。解决这个问题需要更新中间证书或重新生成完整的证书链。
什么是签名算法

签名算法是一种用于验证数据完整性、数据来源和抗否认的技术。在密码学中,签名算法是利用非对称加密的原理,通过私钥进行签名,而公钥用于验证签名的合法性,从而确保消息的真实性和安全性。

签名算法的核心作用在于提供一个安全的方法来验证信息确实由特定的发送方发出,并且内容自签名后未被篡改。这一过程通常涉及到对原始信息进行哈希处理,然后使用发送方的私钥对哈希值进行加密,形成数字签名。接收方收到信息后,可以使用发送方的公钥对签名进行解密验证。

对于常用的签名算法,主要包括RSA、DSA和ECDSA三种。RSA是一种非常经典的算法,广泛用于SSL证书、代码签名等场景。DSA则专门用于数字签名,不能用于加密和解密,其优点是速度较快。ECDSA则是基于椭圆曲线密码学的签名算法,相对于RSA和DSA,其具有更高的安全性和更快的处理速度。

在实际应用中,数字签名常常应用于软件发布、文件传输、在线交易等领域,以确保信息的完整性和真实性。例如,下载软件时,开发者通常会提供MD5或SHA256散列值,用户可以通过验证这些散列值来确保所下载的文件未被篡改。同样,在线支付过程中,通过数字签名验证可以确保交易信息的安全和真实。

此外,选择适当的签名算法也至关重要。RSA算法因其历史悠久和广泛的支持而被普遍接受,但ECDSA由于其更高的安全性和效率正逐渐受到重视。在选择算法时,除了考虑安全性外,还需考虑性能、兼容性和实现的便利性等因素。

SSL/TLS证书有效期

证书有效期是SSL/TLS证书有效性的时间范围,通常为13个月。 SSL(Secure Sockets Layer)和TLS(Transport Layer Security)证书用于在互联网上保护数据的安全传输,它们通过加密和身份验证机制防止数据被窃取或篡改。证书的有效期是其重要属性之一,决定了证书能够在多长时间内提供安全保障。以下将详细分析证书有效期的各个方面:

  1. 证书有效期的历史变化
    • 早期规定:在2011年之前,SSL/TLS证书的有效期通常为8-10年。随着时间的推移,为了提高安全性,有效期逐渐缩短。
    • 逐步缩短:2011年,CA/B论坛将证书有效期缩短至5年。2015年,有效期进一步缩短至3年。2018年,有效期再次缩短为2年。
    • 最新规定:从2020年9月1日起,主流浏览器厂商如苹果、谷歌和火狐推动了一项新政策,要求SSL/TLS证书的最长有效期不得超过13个月(398天)。
  2. 为什么证书有效期要缩短
    • 安全性提升:缩短证书有效期可以更频繁地更新加密算法和密钥,降低被破解的风险。这有助于应对快速发展的网络安全威胁。
    • 减少旧证书数量:较短的有效期迫使网站管理员定期更新证书,从而减少了被遗忘或被忽视的旧证书数量,提高了整体网络安全性。
    • 快速响应漏洞:一旦发现加密算法或证书管理方面的漏洞,短期证书可以更快地推动修复和更新,确保系统安全。
  3. 证书有效期对企业的影响
    • 安全管理优势:短期证书能够促使企业保持对安全措施的关注和更新,从而使用最新的加密技术和标准。
    • 管理负担加重:需要每年更新证书会增加IT管理人员的工作负担和管理成本。对于拥有大量服务器和证书的企业来说,这一挑战尤为显著。
    • 经济成本增加:频繁更新证书可能会增加企业的运营成本,包括人工费、管理费等。
  4. 如何查看和管理证书有效期
    • 在浏览器中查看:访问网站时,点击地址栏的安全锁标志,可以查看SSL证书的有效期。
    • 使用工具查看:利用各种在线工具,只需输入域名即可检测到SSL证书的详细信息,包括有效期。
    • 自动化管理:对于大量证书的管理,建议采用自动化工具进行监控和更新,以避免因疏忽导致证书过期。
  5. 证书有效期过期的实际案例
    • 特斯拉APP宕机:2020年,特斯拉APP因SSL证书过期导致大面积宕机,用户无法正常使用手机钥匙功能。
    • 美国政府网站故障:2018年,美国国家航空航天局、司法部等80多个政府网站因SSL证书过期出现无法访问的情况。
    • 爱立信手机服务中断:同年,爱立信手机服务因数字证书过期,导致数百万用户无法发短信或打电话。
颁发者可信度

颁发者可信度是评估SSL/TLS证书安全性的重要指标之一。在网络安全中,SSL和TLS证书通过加密和身份验证机制保护数据传输的安全性。而证书的颁发者,即证书颁发机构(CA),在信任链中扮演着至关重要的角色。以下将详细分析颁发者可信度的各个方面:

  1. CA的信任基础
    • 法律授权:CA的合法性通常基于国家法律或国际认可,确保其具备合法的资格签发受信任的证书。
    • 技术能力:CA需要具备强大的加密技术和管理能力,以保证证书的生成、分发和吊销过程的安全性和可靠性。
    • 中立性:CA必须保持严格的中立性,不受任何第三方影响,公正地处理证书相关事务。
  2. CA的验证流程
    • 域名验证:对于域验证(DV)证书,CA只需验证申请者是否控制了相应的域名。
    • 组织验证:对于组织验证(OV)证书,CA会进一步验证组织的身份和合法性,确保申请者是合法实体。
    • 扩展验证:扩展验证(EV)证书要求最严格,包括详尽的背景调查和法律文件审核,确保申请者的合法身份和业务真实性。
  3. CA的公信力
    • 市场认可度:知名CA如VeriSign、DigiCert、GlobalSign等因其长期的良好表现和广泛预装在各种设备上的根证书而享有较高声誉。
    • 用户反馈:用户对CA服务的评价也会影响其公信力,包括响应速度、技术支持和问题解决能力。
    • 透明度:CA的透明度越高,用户越能了解其运营和策略,从而增强信任感。
  4. CA的安全记录
    • 历史安全事件:CA历史上是否发生过重大安全事件,如未经授权的证书签发,会对可信度产生重大影响。
    • 漏洞响应:CA面对发现的漏洞和安全威胁时,其响应速度和处理方式也是衡量可信度的重要标准。
    • 持续监控:CA是否拥有持续的安全监控和改进机制,以确保长期保持高水平的安全性。
  5. 颁发者可信度的实际案例
    • DigiNotar事件:2011年,荷兰CA DigiNotar遭受黑客攻击,导致其信任基础完全崩溃,最终破产。
    • Symantec的公信力问题:2018年,Symantec因未能妥善管理其PKI基础设施而被浏览器厂商逐步不信任其旧证书,损害了其公信力。
    • Let’s Encrypt的崛起:作为一个免费、自动化和开放的CA,Let’s Encrypt以其创新和透明性迅速获得了广泛的市场认可。
公钥强度

公钥强度是衡量非对称加密算法安全性的关键指标,它决定了密码破解的难易程度和计算复杂度。在密码学中,公钥和私钥成对出现,公钥用于加密数据,而私钥则用于解密。已知私钥可以推导出公钥,但公钥不能反推私钥,从而确保了加密信息的安全性。以下将详细分析公钥强度的各个方面:

  1. 密钥长度与强度
    • RSA算法:RSA算法是最广泛使用的非对称加密算法之一,其强度主要取决于密钥长度。目前,RSA 1024位密钥已不再安全,逐渐被2048位及以上的密钥替代。RSA 2048位密钥可提供约112位的安全强度,而3072位密钥提供128位安全强度。
    • ECC算法:相比于RSA,椭圆曲线密码(ECC)算法具有更高的单位比特安全强度。例如,256位的ECC密钥强度已经比2048位的RSA密钥强度要高。
    • SM2算法:作为国产密码标准,SM2算法也是基于椭圆曲线的,其256位密钥即可达到较高的安全强度。
  2. 密码算法与强度
    • 对称式加密算法:这类算法的密钥长度直接决定了穷举攻击的复杂度,例如AES算法的密钥长度即代表其安全强度。
    • 非对称式加密算法:RSA和ECC等算法的密钥长度不仅影响加密速度,还决定破解难度。长密钥意味着更高的安全强度。
    • Hash算法:如SHA-2系列算法,其强度体现在抗碰撞和雪崩效应上。
  3. 国际与国产算法
    • RSA与SM2:RSA算法由美国NSA提出,密钥长度不断增加以应对安全威胁;SM2则是中国自主研发的,基于椭圆曲线,相对于RSA在同等安全强度下运算速度更快。
    • ECC与SM2:SM2与国际上的ECC算法相对应,其签名、密钥交换和公钥加密功能分别对应于ECC算法的ECDSA、ECDH、ECIES。
  4. 不同应用场景的密钥要求
    • 金融级应用:根据国际建议,金融级应用的加密算法密钥强度应达到112位,长期保护则需128位或更高。
    • 国家安全应用:美国NSA对SECRET级别信息的密钥强度要求为128位,TOP SECRET级别则需192位。
  5. 密码算法发展趋势
    • 对称密码算法:如AES算法,密钥长度将逐渐从128位增加到192位、256位。
    • 非对称密码算法:ECC算法将逐渐占据重要地位,密钥长度从224位增加;RSA算法密钥长度也在增加。
    • 轻量级密码:适用于资源受限环境,如物联网设备。这些算法包括DESL、HIGHT等对称密码,及NTRU、BlueJay等非对称密码。
  6. 国密算法与安全性
    • SM2:基于椭圆曲线,设计时考虑多种攻击手段,具有较高的安全性。
    • SM3:输出长度为256比特的散列算法,抗碰撞能力强,设计上考虑了雪崩效应。
    • SM4:分组密码算法,128比特密钥和分组长度,经过多轮安全性评估,尚未有公开的有效攻击方法。
证书扩展

证书扩展是数字证书中的一个重要组成部分,它提供了一种机制,允许在证书中包含额外的属性和信息,以增强证书的功能性和灵活性。

自签名证书可以进行私有扩展,这对于内部使用或测试环境非常有用。标准扩展则适用于由CA机构签发的证书,这些扩展项包括SAN(Subject Alternative Name)、密钥标识符、密钥用法和基本约束等,它们大大增加了证书的使用场景和灵活性。特别是SAN扩展,它允许一张证书绑定多个域名、IP地址或电子邮件地址,这对多域名支持尤其重要。

X.509标准定义了公钥证书的字段和扩展名,其中版本3引入了对证书扩展的支持,这为证书提供了更多属性与公钥关联的方法。例如,subjectAltName扩展可以包含电子邮件地址、域名、IP地址等,并且这些值可以有多个,这在实际应用中非常重要。

当一个网站使用TLS证书进行身份标记时,如果证书中包含subjectAltName,系统将优先使用这些信息来识别证书持有者,而不是依赖于Subject子项。这种机制在现代网站的TLS实现中非常常见,以确保网站身份的准确识别。

证书吊销列表(CRL)和在线证书状态协议(OCSP)

证书吊销列表(CRL)和在线证书状态协议(OCSP)都是用于验证数字证书有效性的重要机制,它们各自以不同的方式帮助维护网络安全和信任。

CRL是一种由证书颁发机构(CA)定期发布的文件,其中列出了所有已吊销的证书序列号及其吊销日期。这种机制允许网站管理员和浏览器检查特定证书是否已被吊销。CRL的访问方式通常是通过下载最新的CRL文件,并与本地证书进行比对来确认其有效性。这种方法是静态的,意味着它需要定期手动更新CRL文件,以确保信息的最新性。

相比之下,OCSP提供了一种动态的证书状态检查方法。通过实时向CA发送请求,OCSP能够即时返回证书的状态,包括“正常”、“吊销”或“未知”。这种即时性使得OCSP在需要快速验证证书状态的场景中特别有用,如在线事务处理时。

CRL的更新频率通常较低,这可能导致其信息可能不是最即时的。更新的频率取决于CA的政策,可能是每天一次或每月一次。因此,尽管CRL提供了一种可行的证书状态检查方式,但它不能提供实时的证书状态信息。

而OCSP正好弥补了CRL的这一不足,它通过实时查询,能够提供即时的证书状态信息。当用户需要确保交易时对方证书的即时有效性时,OCSP提供了一个可靠的解决方案。然而,OCSP的响应时间受到服务器性能和网络延迟的影响,可能在高并发场景下影响性能。

从应用场景来看,CRL更适合于不频繁变更证书的场景,或者在对实时性要求不高的环境中使用。例如,一些企业内部系统可能会选择CRL作为验证员工证书状态的方式。相反,对于那些要求高安全性和即时性的应用场景,如电子商务平台,更倾向于使用OCSP来确保每次交易的安全性。

在选择使用CRL还是OCSP时,还应考虑系统的性能和网络环境。CRL由于需要定期下载,可能会增加网络负担,特别是在网络条件受限的环境下。而OCSP虽然提供了实时的验证,但需要维护稳定的网络连接到OCSP服务器,并且其响应速度必须足够快以支持大量的实时查询。

使用OpenSSL工具分析SSL/TLS证书

使用OpenSSL工具分析SSL/TLS证书可以提供证书的详细信息,包括其结构、内容、有效性等。以下是一些常用的OpenSSL命令示例,用于分析证书:

1. 显示证书信息
要查看证书的详细信息,可以使用以下命令:

openssl x509 -in certificate.crt -text -noout 

这个命令将显示证书的文本表示形式,包括版本、序列号、签名算法、有效期、主题信息、颁发者信息等。

2. 检查证书链
要验证证书链,可以使用-untrusted选项和中间CA证书或链中的其他证书:

openssl verify -CAfile intermediate.crt certificate.crt 

如果证书链有效,命令将显示类似certificate.crt: OK的消息。

3. 检查证书有效期
要快速查看证书的有效期,可以使用:

openssl x509 -in certificate.crt -dates -noout 

这将输出证书的"notBefore"和"notAfter"日期。

4. 提取证书的公钥
要提取并显示证书的公钥,可以使用:

openssl x509 -in certificate.crt -pubkey -noout 

这将显示证书公钥的详细信息。

5. 验证证书签名
要验证证书的签名,可以使用:

openssl x509 -in certificate.crt -check_ss_sig 

如果证书是由其颁发者正确签名的,命令将显示签名验证成功的消息。

6. 检查证书是否被吊销
要检查证书是否被吊销,可以使用CRL或OCSP。对于CRL,可以使用:

openssl crl -in crl_number.crl -noout -text 

对于OCSP,可以使用:

openssl ocsp -issuer issuer_certificate.pem -cert certificate_to_check.crt -url http://ocsp.certificateAuthority.com 

这些命令将检查证书是否在CRL中或OCSP响应中被标记为吊销。

7. 显示证书的指纹
要显示证书的指纹,可以使用:

openssl x509 -in certificate.crt -noout -fingerprint -sha256 

这将输出证书的SHA-256指纹,可用于比较和验证。

8. 导出证书为DER格式
如果需要将证书导出为DER格式,可以使用:

openssl x509 -outform der -in certificate.crt -out certificate.der 

这将证书从PEM格式转换为DER格式。

9. 从证书中提取证书策略
要查看证书的CPS(证书策略)或任何其他扩展,可以使用:

openssl x509 -in certificate.crt -extfile <(echo "[ v3_ca ]") -extensions v3_ca -noout -text 

这将显示证书中的自定义扩展信息。

10. 显示证书的主题备用名称(SAN)

要查看证书的SAN扩展,可以使用:

openssl x509 -in certificate.crt -text -noout -subject_alt_name 

这将列出证书支持的所有备用域名或IP地址。

这些命令提供了对SSL/TLS证书进行深入分析的基础,可以帮助你了解证书的属性、验证其安全性和信任链,以及确保它适用于你的安全需求。

...  int main (int argc, char **argv)  {  ... 	static struct option long_options[] = { 		{ "bits", no_argument, 0, 'b' }, 		{ "chain", no_argument, 0, 'c' }, 		{ "cipher", no_argument, 0, 'C' }, 		{ "issuer", no_argument, 0, 'i' }, 		{ "method", no_argument, 0, 'm' }, 		{ "no-sni", no_argument, 0, 'N' }, 		{ "quiet", no_argument, 0, 'q' }, 		{ "raw", no_argument, 0, 'r' }, 		{ "serial", no_argument, 0, 'S' }, 		{ "signature-algorithm", no_argument, 0, 'A' }, 		{ "subject", no_argument, 0, 's' }, 		{ "validity", no_argument, 0, 'V' }, 		{ "help", no_argument, 0, 'h' }, 		{ "version", no_argument, 0, 'v' }, 	};  	while ((opt_value = getopt_long(argc, argv, "bcCimNqrSAsVhv", long_options, &long_opt_index)) != -1) { 		switch (opt_value) {  			case 'b': 				bits = 1; 				continue;  			case 'c': 				chain = 1; 				continue;  			case 'C': 				cipher = 1; 				continue;  			case 'i': 				issuer = 1; 				continue;  			case 'm': 				method = 1; 				continue;  			case 'N': 				no_sni = 1; 				continue;  			case 'q': 				quiet = 1; 				pad_fmt = 0; 				continue;  			case 'r': 				raw = 1; 				continue;  			case 'S': 				serial = 1; 				continue;  			case 'A': 				sig_algo = 1; 				continue;  			case 's': 				subject = 1; 				continue;  			case 'V': 				validity = 1; 				continue;  			case 'h': 				usage(); 				exit(EXIT_SUCCESS);  			case 'v': 				fprintf(stdout, "%s\n", KEUKA_VERSION); 				exit(EXIT_SUCCESS); 			case '?': 				usage(); 				exit(EXIT_FAILURE); 			default: 				break; 		} 	} ...  	/** 	 * 限制作为参数给定的主机名的长度 	 */ 	if (length(argv[last_index]) > MAX_HOSTNAME_LENGTH) { 		fprintf(stderr, "Error: Hostname exceeds maximum length of 256 characters.\n"); 		exit(EXIT_FAILURE); 	}  	/** 	 * argv中的最后一个元素应该是对等主机名 	 */ 	hostname = argv[last_index];  	/** 	 * 组装请求的URL 	 */ 	copy(url, protocol); 	concat(url, "://"); 	concat(url, hostname);  	/** 	 * 运行OpenSSL初始化任务 	 */ 	SSL_load_error_strings(); 	ERR_load_crypto_strings(); 	OpenSSL_add_all_algorithms(); 	OpenSSL_add_all_digests(); 	SSL_library_init();  	/** 	 * Start execution clock. 	 */ 	start = clock();  	/** 	 * 初始化新的BIO. 	 */ 	bp = BIO_new_fp(stdout, BIO_NOCLOSE);   	ssl_method = SSLv23_client_method();  	if (!quiet) { 		BIO_printf( 			bp, 			"%s [%fs] Establishing SSL context.\n", 			KEUKA_NEUTRAL_INDICATOR, 			get_elapsed_ticks(start) 		); 	}  	/** 	 * 建立新的SSL上下文 	 */ 	if (is_null(ctx = SSL_CTX_new(ssl_method))) { 		/** 		 * 以进度格式显示错误,除非给出--quiet。 		 */ 		if (!quiet) { 			BIO_printf( 				bp, 				"%s [%fs] Error: Unable to establish SSL context.\n", 				KEUKA_NEUTRAL_INDICATOR, 				get_elapsed_ticks(start) 			); 		} else { 			BIO_printf(bp, "Error: Unable to establish SSL context.\n"); 		}  		goto on_error; 	}  	if (!quiet) { 		BIO_printf( 			bp, 			"%s [%fs] SSL context established.\n", 			KEUKA_NEUTRAL_INDICATOR, 			get_elapsed_ticks(start) 		); 	}  	/** 	 * 建立TCP套接字连接 	 */ 	server = mksock(url, bp);  	if (!quiet) { 		BIO_printf( 			bp, 			"%s [%fs] Establishing connection to %s.\n", 			KEUKA_OUTBOUND_INDICATOR, 			get_elapsed_ticks(start), 			hostname 		); 	}  	/** 	 * 如果建立连接时出现问题,请退出。 	 */ 	if (is_error(server, -1)) {  		if (!quiet) { 			BIO_printf( 				bp, 				"%s [%fs] Error: Unable to resolve hostname %s.\n", 				KEUKA_INBOUND_INDICATOR, 				get_elapsed_ticks(start), 				hostname 			); 		} else { 			BIO_printf(bp, "Error: Unable to resolve hostname %s.\n", hostname); 		}  		exit(EXIT_FAILURE); 	}  	if (!quiet) { 		BIO_printf( 			bp, 			"%s [%fs] Connection established.\n", 			KEUKA_INBOUND_INDICATOR, 			get_elapsed_ticks(start) 		); 	}  	/** 	 * 建立连接,在客户端模式下设置状态。 	 */ 	ssl = SSL_new(ctx); 	SSL_set_connect_state(ssl);  	/** 	 * Disable SNI support if --no-sni was given. 	 */ 	if (!no_sni) { 		SSL_set_tlsext_host_name(ssl, hostname); 	}  	if (!quiet) { 		BIO_printf( 			bp, 			"%s [%fs] Attaching SSL session to socket.\n", 			KEUKA_NEUTRAL_INDICATOR, 			get_elapsed_ticks(start) 		); 	}  	attach = SSL_set_fd(ssl, server);  	/** 	 * 将SSL会话连接到TCP套接字。 	 */ 	if (is_error(attach, -1)) {  		if (!quiet) { 			BIO_printf( 				bp, 				"%s [%fs] Error: Unable to attach SSL session to socket.\n", 				KEUKA_NEUTRAL_INDICATOR, 				get_elapsed_ticks(start) 			); 		} else { 			BIO_printf(bp, "Error: Unable to attach SSL session to socket.\n"); 		}  		goto on_error; 	}  	if (!quiet) { 		BIO_printf( 			bp, 			"%s [%fs] SSL session attached, handshake initiated.\n", 			KEUKA_OUTBOUND_INDICATOR, 			get_elapsed_ticks(start) 		); 	}  	status = SSL_connect(ssl);   	if (status != 1) {  		if (!quiet) { 			BIO_printf( 				bp, 				"%s [%fs] Error: Could not build SSL session with %s. Handshake aborted.\n", 				KEUKA_NEUTRAL_INDICATOR, 				get_elapsed_ticks(start), 				url 			); 		} else { 			BIO_printf( 				bp, 				"Error: Could not build SSL session with %s. Handshake aborted.\n", 				url 			); 		}  		goto on_error; 	}  	ssl_cipher = SSL_get_current_cipher(ssl);  	if (!quiet) { 		BIO_printf( 			bp, 			"%s [%fs] %s negotiated, handshake complete.\n", 			KEUKA_INBOUND_INDICATOR, 			get_elapsed_ticks(start), 			SSL_CIPHER_get_version(ssl_cipher) 		);  		if (pad_fmt) { 			BIO_printf(bp, "\n"); 		} 	}  	/** 	 * 如果给定了--cipher,则打印使用的密码。 	 */ 	if (cipher) { 		BIO_printf( 			bp, 			"--- Cipher: %s\n", 			SSL_CIPHER_get_name(ssl_cipher) 		); 	}  	/** 		如果给定了--method选项,则输出用于握手的方法的版本 	 */ 	if (method) { 		BIO_printf( 			bp, 			"--- Method: %s\n", 			SSL_get_version(ssl) 		); 	}  	/** 	 * 如果给定了--chain,则打印完整的chain。 	 */ 	if (chain) { 		/** 		 * 获取对等证书链。 		 */ 		if (is_null(fullchain = SSL_get_peer_cert_chain(ssl))) { 			BIO_printf(bp, "Error: Could not get certificate chain from %s.\n", url); 			goto on_error; 		}  		BIO_printf(bp, "--- Certificate Chain:\n");  		/** 		 * 输出证书链 		 */ ....  			/** 			 * 证书的输出签名算法 			 */ 			if (sig_algo) { 				if (pad_tfmt) { 					BIO_printf(bp, "%s%7s", "\n", ""); 				} else { 					pad_tfmt = 1; 				}  #if OPENSSL_VERSION_NUMBER >= 0x10100000L 				X509_get0_signature(&asn1_sig, &sig_type, tcrt); #else 				sig_type = tcrt->sig_alg; 				asn1_sig = tcrt->signature; #endif  				BIO_printf(bp, "--- Signature Algorithm: "); 				sig_type_err = i2a_ASN1_OBJECT(bp, sig_type->algorithm);  				if (is_error(sig_type_err, -1) || is_error(sig_type_err, 0)) { 					BIO_printf(bp, "Could not get signature algorithm."); 				} 			}   ...  		crtname = X509_get_subject_name(crt); 		pubkey = X509_get_pubkey(crt);  		/** 		 * 输出证书主题信息 		 */ 		if (subject) { 			BIO_printf(bp, "--- Subject: "); 			X509_NAME_print_ex(bp, crtname, 0, XN_FLAG_SEP_COMMA_PLUS); 			BIO_printf(bp, "\n"); 		}  		/** 		 * 输出证书颁发者信息。 		 */ 		if (issuer) { 			BIO_printf(bp, "--- Issuer: "); 			X509_NAME_print_ex(bp, X509_get_issuer_name(crt), 0, XN_FLAG_SEP_CPLUS_SPC); 			BIO_printf(bp, "\n"); 		}  		if (bits) { 			BIO_printf(bp, "%s%d\n", "--- Bits: ", EVP_PKEY_bits(pubkey)); 		}  ...  		/** 		 * If --signature-algorithm option was given, 		 * 证书的输出签名算法 		 */ 		if (sig_algo) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L 			X509_get0_signature(&asn1_sig, &sig_type, crt); #else 			sig_type = crt->sig_alg; 			asn1_sig = crt->signature; #endif  			BIO_printf(bp, "--- Signature Algorithm: "); 			sig_type_err = i2a_ASN1_OBJECT(bp, sig_type->algorithm); 			BIO_printf(bp, "\n");  			if (is_error(sig_type_err, -1) || is_error(sig_type_err, 0)) { 				BIO_printf(bp, "Error: Could not get signature algorithm.\n"); 			} 		}  		/** 		 * 输出不在前/不在后时间戳的范围 		 */ 		if (validity) { 			BIO_printf(bp, "%s", "--- Validity:\n"); 			BIO_printf(bp, "%4s%s", "", "--- Not Before: "); 			ASN1_TIME_print(bp, X509_get_notBefore(crt)); 			BIO_printf(bp, "\n"); 			BIO_printf(bp, "%4s%s", "", "--- Not After: "); 			ASN1_TIME_print(bp, X509_get_notAfter(crt)); 			BIO_printf(bp, "\n"); 		}  		/** 		 * 输出原始证书内容 		 */ 		if (raw) { 			BIO_printf(bp, "\n"); 			PEM_write_bio_PUBKEY(bp, pubkey); 			BIO_printf(bp, "\n"); 			PEM_write_bio_X509(bp, crt); 			BIO_printf(bp, "\n"); 		} 	}  ....  	return EXIT_FAILURE; }  

If you need the complete source code, please add the WeChat number (c17865354792)



用于建立一个安全的SSL/TLS连接。它接受一系列命令行参数,如–bits, --chain, --cipher, --issuer, --method, --no-sni, --quiet, --raw, --serial, --signature-algorithm, --subject, --validity, --help, 和 --version。这些参数允许用户指定他们想要从服务器获取的信息类型。一旦建立了与SSL/TLS服务器的连接,将根据用户指定的参数获取证书信息。

总结

SSL/TLS服务器的证书是网络安全不可或缺的一部分,不仅提供了身份验证和数据加密,还增强了用户对网站安全性的信心。随着网络攻击的日益复杂和频繁,理解和正确实施SSL/TLS证书变得尤为重要。

We also undertake the development of program requirements here. If necessary, please follow the WeChat official account 【程序猿编码】and contact me

参考:1.https://www.idc.net/help/229710/
2.https://learn.microsoft.com/zh-cn/azure/iot-hub/reference-x509-certificates

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!