1、概念简介:
- 加密:业务发送方使用接收方的公钥对要发送的明文进行加密。
- 解密:业务接收方使用自己的私钥对密文进行解密
- 签名:签名是发送方为发送的文件写上一个自己的签名,需要使用发送方的私钥
- 验证签名: 验证签名是接收方需要确认自己接收到的密文文件是否真的是发送方发送过来的,需要确认的是中间有没有被篡改,验签最终是根据报文摘要来进行对比。
签名验签过程如下:
- 签名者将验签公钥分发给消息接收者。
- 签名者使用签名私钥,对数据产生签名。
- 签名者将数据以及签名传递给消息接收者。
- 消息接收者获得数据和签名后,使用公钥针对数据验证签名的合法性。
数字签名被广泛用于数据防篡改、身份认证等相关技术领域,使用场景如下:
- 数字签名用于对二进制代码提供完整性保护,代码执行者可以验证代码未被篡改,以提供可信的执行环境。
- 数字证书系统中,证书机构(CA)对颁发的数字证书提供签名,证明数字证书的主体信息、公私钥信息、密钥用途、有效期和签发者等信息。证书私钥持有者使用私钥对消息进行签名,消息接收者使用证书中包含的公钥对消息签名进行验证,同时使用证书签发者的公钥,验证证书本身的合法性。
2、利用阿里云 KMS 对 《文本》 进行验签实践
2.1 实验环境准备:
需求前景:为避免 SSL PriateKey 泄露,因此需要用 KMS 对 SSL PriateKey 进行签名并且验签;
测试环境:
- Nginx服务器(双向认证);
- PCA证书;
- KMS加密实例;
2.2 实验搭建
- 拥有一个做好双向认证PCA的环境(下方测试主要用到证书的文件,实际项目运行与否无所谓),在NGINX上配置PCA双向认证
2.2.1 导出根证书
点击根CA右侧三个点,并点击"详情"
滚动到最下方查看根证书内容,保存为文件名 ca.crt
,后续 客户端 和 服务端 都会用到。
2.2.1.1 导出服务端证书
新版本PCA产品,已更新无需解密,服务端证书直接下载PEM格式,server.pem组合中间CA(子CA)即可使用,server.key直接使用;
进入子CA的"证书列表"
看到已经创建好的服务端证书,点击"详情"
勾选 "查看私钥内容" 并且输入密码后点击 "导出" 可以查看到证书内容。
"证书内容" + "完整证书链内容" 保存为 server.pem
"私钥内容" 保存为 enc_server.key
在服务器中用openssl命令解密:
openssl rsa -in enc_server.pem -out server.key
输入刚才到处用到的密码,即可获得解密后的私钥文件 server.key
2.2.1.2 导出客户端证书
与上方1.2.提示操作一致,可以直接下载客户端证书选择PEM格式,client.pem组合好中间CA(子CA)即可使用,client.key直接使用;(如果是WindowsOS导入需要转换 client.pem 和 client.key 为 PFX,测试win10不用设置密码也可以使用)
与上方导出服务端证书相同操作,一模一样方式,最后得到 client.pem
client.key
并用SSL控制台格式工具转换为.pfx格式的证书(下方旧密码空,并输入新密码),以便windows测试。
最后得到客户端证书 client.pfx
2.2.2 配置证书
2.2.2.1 配置服务端
nginx配置增加双向认证相关,8~11行,保存后重启nginx。
server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name XX.rootyzc.top; # 域名 root /usr/share/nginx/html; ssl_certificate "/etc/nginx/ssl/pca/server.pem"; # 服务端公钥证书 ssl_certificate_key "/etc/nginx/ssl/pca/server.key"; # 服务端私钥 ssl_client_certificate "/etc/nginx/ssl/pca/ca.crt"; # CA根证书 ssl_verify_client on; # 开启双向认证 ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE; ssl_prefer_server_ciphers on; }
此时客户端访问服务端显示:
2.2.2.2 配置客户端
客户端准备好根证书与客户端证书
打开浏览器,例如chrome,点击右上角三个点 -> 设置 -> 隐私设置和安全性 -> 安全 -> 管理设备证书
点击"受信任的根证书颁发机构" -> 点击"导入" -> 选择"ca.crt"导入根证书
点击"个人" -> 点击"导入" -> 选择 "client.pfx" 输入新建的密码,导入客户端证书
2.2.3. 测试生效
浏览器访问域名,选择证书点击确定
至此步骤双向认证成功!
在服务器中利用curl测试也可以成功
curl --cacert ca.crt --cert ./client.pem --key ./client.key https://pca.roo tyzc.top -k -v
3、签名步骤:
3.1 创建KMS - 加密实例
- 点击 实例管理 > 选择 软件密钥管理 > 并点击 创建实例
- 按需选择购买,并启用成功后,如图样所示
3.2 创建KMS - 密钥
- 点击 密钥管理 > 选择创建的 KMS加密实例ID > 并点击 创建密钥
- 选择密钥类型 非对称密钥 > 按需填写各个选项 > 用途选择SIGN/VERIFY > 点击 确定
- 创建成功后,样式如图
4、验签步骤:
4.1. 完成KMS接入指南
- 点击第一步的授应用访问 > 快速创建应用接入点
- 选择KMS加密实例 > 输入接入点名称 > 点击确认
- 创建接入点之后 > 会自动下载应用身份凭证的文件(如果没有自动下载,点击框中按钮手动下载),其中zip包含两个文件,后面都需要用到
- 下载KMS加密实例的CA证书 > 点击下载即可
4.2. 创建脚本进行验签操作
- 《KMS实例SDK》文档参考:https://help.aliyun.com/zh/kms/developer-reference/kms-instance-sdk/
- 此处用Python演示SDK测试过程,其中接入点名称参考文档或者测试样例;
- clientKey_KAAP.json ----> 上方KMS创建接入点下载的应用身份凭证
- PrivateKmsCA.pem -----> 上方下载的KMS实例CA证书
- __init__.py --------------> SDK调用实例测试Python主程序
# -*- coding: utf-8 -*- from openapi.models import Config from sdk.client import Client from openapi_util.models import RuntimeOptions from sdk.models import SignRequest from sdk.models import VerifyRequest import os import base64 # --------->初始化SDK<--------- config = Config() # 连接协议请设置为"https"。KMS实例服务仅允许通过HTTPS协议访问。 config.protocol = "https" # 设置endpoint为<your KMS Instance Id>.cryptoservice.kms.aliyuncs.com。 config.endpoint = "kst-hkk657fb8XXXXtx8vjp3f.cryptoservice.kms.aliyuncs.com" #写入KMS的endpoint # Client Key。 config.client_key_file = "./clientKey_KAAP.json" # Client Key解密口令。 config.password = "5bdbdf01cff8b144b2c8e4acdeXXXXd" #证书的密码,本处做了打码 client = Client(config) # --------->通过配置运行时参数(RuntimeOptions)设置KMS实例的CA证书。<--------- runtime_options = RuntimeOptions() # ca证书路径 runtime_options.verify = "./PrivateKmsCA.pem" # --------->调用Sign接口使用非对称密钥进行数字签名<--------- request = SignRequest() # 密钥的ID或别名(Alias)。 request.key_id = "key-hkk658125e7clXXXj3lds" #录入KMS的实例id # 待签名数据。 # 读取要加签文件 with open('/etc/nginx/ssl/server.key',encoding='utf-8') as file_obj: contents = file_obj.read() file_obj.close() request.message = bytes(contents,encoding='utf-8') # 签名算法。 request.algorithm = "RSA_PSS_SHA_256" sign_response = client.sign_with_options(request, runtime_options) # 签名值。 signature = sign_response.signature # 请求ID。 request_id = sign_response.request_id # --------->调用Verify接口使用非对称密钥验证数字签名<--------- request = VerifyRequest() # 密钥的ID或别名(Alias)。 request.key_id = "key-hkk658125e7cXXXvj3lds" #录入KMS的实例id # 待验证签名的数据。 # 读取要验签的文件 with open("/etc/nginx/ssl/server.key",encoding='utf-8') as file_obj: contents = file_obj.read() file_obj.close() request.message = bytes(contents,encoding='utf-8') # 签名算法。 request.algorithm = "RSA_PSS_SHA_256" # 签名值。 request.signature = signature verify_response = client.verify_with_options(request, runtime_options) print("<--验签签名值-->\n",verify_response) # 验签结果。 value = verify_response.value print("<--验签的结果-->\n",value) # 请求ID。 request_id = verify_response.request_id
4.3. 运行脚本验签测试
- 可以看到验签后的内容,参数print出来了,验签结果: 'Value': True ;