工作中需要建立一套HSM的HTTPS双向认证通道,即通过硬件加密机(Ukey)进行本地加密运算的HTTPS双向认证,和银行的UKEY认证类似。
NodeJS可以利用openSSL的HSM plugin方式实现,但是需要编译C++,太麻烦,作者采用了利用Node Socket接口,纯JS自行实现Https/Http协议的方式实现
具体实现可以参考如下 node-https-hsm
TLS规范自然是参考RFC文档 The Transport Layer Security (TLS) Protocol Version 1.2
概述
本次TLS双向认证支持以下加密套件(*为建议使用套件):
四种加密套件流程完全一致,只是部分算法细节与报文略有差异,体现在
目前业界推荐使用TLS v1.2, TLS v1.1不建议使用。
流程图
以下为 TLS 完整握手流程图
* =======================FULL HANDSHAKE====================== * Client Server * * ClientHello --------> * ServerHello * Certificate * CertificateRequest * <-------- ServerHelloDone * Certificate * ClientKeyExchange * CertificateVerify * Finished --------> * change_cipher_spec * <-------- Finished * Application Data <-------> Application Data
流程详解
客户端发起握手请求
TLS握手始于客户端发起 ClientHello 请求。
struct { uint32 gmt_unix_time; // UNIX 32-bit format, UTC时间 opaque random_bytes[28]; // 28位长度随机数 } Random; //随机数 struct { ProtocolVersion client_version; // 支持的最高版本的TLS版本 Random random; // 上述随机数 SessionID session_id; // 会话ID,新会话为空 CipherSuite cipher_suites<2..2^16-2>; // 客户端支持的所有加密套件,上述四种 CompressionMethod compression_methods<1..2^8-1>; // 压缩算法 select (extensions_present) { // 额外插件,为空 case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ClientHello; // 客户端发送支持的TLS版本、客户端随机数、支持的加密套件等信息
服务器端回应客户端握手请求
服务器端收到 ClientHello 后,如果支持客户端的TLS版本和算法要求,则返回 ServerHello, Certificate, CertificateRequest, ServerHelloDone 报文
struct { ProtocolVersion server_version; // 服务端最后决定使用的TLS版本 Random random; // 与客户端随机数算法相同,但是必须是独立生成,与客户端毫无关联 SessionID session_id; // 确定的会话ID CipherSuite cipher_suite; // 最终决定的加密套件 CompressionMethod compression_method; // 最终使用的压缩算法 select (extensions_present) { // 额外插件,为空 case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ServerHello; // 服务器端返回最终决定的TLS版本,算法,会话ID和服务器随机数等信息 struct { ASN.1Cert certificate_list<0..2^24-1>; // 服务器证书信息 } Certificate; // 向客户端发送服务器证书 struct { ClientCertificateType certificate_types<1..2^8-1>; // 证书类型,本次握手为 值固定为rsa_sign SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>; // 支持的HASH 签名算法 DistinguishedName certificate_authorities<0..2^16-1>; // 服务器能认可的CA证书的Subject列表 } CertificateRequest; // 本次握手为双向认证,此报文表示请求客户端发送客户端证书 struct { } ServerHelloDone // 标记服务器数据末尾,无内容
客户端收到服务器后响应
客户端应校验服务器端证书,通常用当用本地存储的可信任CA证书校验,如果校验通过,客户端将返回 Certificate, ClientKeyExchange, CertificateVerify, change_cipher_spec, Finished 报文。
CertificateVerify 报文中的签名为 Ukey硬件签名 , 此外客户端证书也是从Ukey读取。
struct { ASN.1Cert certificate_list<0..2^24-1>; // 服务器证书信息 } Certificate; // 向服务器端发送客户端证书 struct { html" target="_blank">select (KeyExchangeAlgorithm) { case rsa: EncryptedPreMasterSecret; // 服务器采用RSA算法,用服务器端证书的公钥,加密客户端生成的46字节随机数(premaster secret) case dhe_dss: case dhe_rsa: case dh_dss: case dh_rsa: case dh_anon: ClientDiffieHellmanPublic; } exchange_keys; } ClientKeyExchange; // 用于返回加密的客户端生成的随机密钥(premaster secret) struct { digitally-signed struct { opaque handshake_messages[handshake_messages_length]; // 采用客户端RSA私钥,对之前所有的握手报文数据,HASH后进行RSA签名 } } CertificateVerify; // 用于服务器端校验客户端对客户端证书的所有权 struct { enum { change_cipher_spec(1), (255) } type; // 固定值0x01 } ChangeCipherSpec; // 通知服务器后续报文为密文 struct { opaque verify_data[verify_data_length]; // 校验密文,算法PRF(master_secret, 'client finished', Hash(handshake_messages)) } Finished; // 密文信息,计算之前所有收到和发送的信息(handshake_messages)的摘要,加上`client finished`, 执行PRF算法
Finished 报文生成过程中,将产生会话密钥 master secret,然后生成Finish报文内容。
master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random) verify_data = PRF(master_secret, 'client finished', Hash(handshake_messages))
PRF为TLS v1.2规定的伪随机算法, 此例子中,HMAC算法为 SHA256
PRF(secret, label, seed) = P_<hash>(secret, label + seed) P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + HMAC_hash(secret, A(2) + seed) + HMAC_hash(secret, A(3) + seed) + ... // A(0) = seed // A(i) = HMAC_hash(secret, A(i-1))
服务器完成握手
服务收到请求后,首先校验客户端证书的合法性,并且验证客户端证书签名是否合法。根据服务器端证书私钥,解密 ClientKeyExchange,获得pre_master_secret, 用相同的PRF算法即可获取会话密钥,校验客户端 Finish 信息是否正确。如果正确,则服务器端与客户端完成密钥交换。 返回 change_cipher_spec, Finished 报文。
struct { enum { change_cipher_spec(1), (255) } type; // 固定值0x01 } ChangeCipherSpec; // 通知服务器后续报文为密文 struct { opaque verify_data[verify_data_length]; // 校验密文,算法PRF(master_secret, 'server finished', Hash(handshake_messages)) } Finished; // 密文信息,计算之前所有收到和发送的信息(handshake_messages)的摘要,加上`server finished`, 执行PRF算法
客户端会话开始
客户端校验服务器的Finished报文合法后,握手完成,后续用 master_secret 发送数据。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍详解iOS开发 - 用AFNetworking实现https单向验证,双向验证,包括了详解iOS开发 - 用AFNetworking实现https单向验证,双向验证的使用技巧和注意事项,需要的朋友参考一下 自苹果宣布2017年1月1日开始强制使用https以来,htpps慢慢成为大家讨论的对象之一,不是说此前https没有出现,只是这一决策让得开发者始料未及,博主在15年的时候就做过
概述 Istio Auth的目标是提高微服务及其通信的安全性,而不需要修改服务代码。它负责: 为每个服务提供强大的身份,代表其角色,以实现跨集群和云的互通性 加密服务间通信和终端用户到服务的通信 提供密钥管理系统来自动执行密钥和证书的生成、分发、轮换和撤销 架构 下图展示Istio Auth架构,其中包括三个主要组件:身份、密钥管理和通信安全。它描述了Istio Auth如何用于加密服务间通信,在
本文向大家介绍PHP HTTP 认证实例详解,包括了PHP HTTP 认证实例详解的使用技巧和注意事项,需要的朋友参考一下 HP来实现HTTP的强制认证是十分简单的,只需简单的几行代码就可以实现,下面我们来看一个例子,然后结合这里例子我向大家详细介绍一下PHP实现HTTP认证。 1.实现说明 怎么样,看到上面的代码了吧,就这么几行添加到你的程序页面上就可以实现了. 它是通过利用header()函数
作者:陈希章 发表于 2018年3月22日
在安装指南中,我们展示了如何启用边车之间的双向TLS认证。 这些设置将应用于网格中的所有边车。 在本教程中,您将学习: 注解Kubernetes服务以禁用(或启用)一个选定服务的双向TLS身份验证。 修改Istio网格配置以解除控制服务的相互TLS身份验证。 在开始前 了解Isio双向TLS认证的概念。 熟悉验证Istio双向TLS认证。 参考安装指南中的说明,通过双向TLS认证安装Istio。
本文向大家介绍Android中socketpair双向通信详解,包括了Android中socketpair双向通信详解的使用技巧和注意事项,需要的朋友参考一下 Android很多地方会涉及到进程间的通信,比如输入系统,那么进程间通信会涉及哪些内容呢? 1、进程:负责读取和分发事件 2、应用程序:负责处理输入事件 上面这两个进程会涉及哪些双向通信呢: 1.进程会发送输入事件 2.应用程序会告知事件处