鸿蒙网络编程系列40-TLS数字证书查看及验签示例

1. TLS数字证书验签简介

数字证书的验签是网络编程中一个重要的功能,它保证了数字证书的真实性,在此基础上,我们才可以信任该证书,从而信任基于该证书建立的安全通道,所以说,数字证书的验签是通讯安全的基石,了解数字证书验签的原理和方法,有助于我们建立安全的通讯。

用户数字证书的验签是通过签发该数字证书的CA证书完成的,因为用户数字证书是由CA证书的私钥签名的,使用CA的公钥可以验证数字证书的合法性,鸿蒙的X509Cert数字证书类提供了验签方法verify:

verify(key: cryptoFramework.PubKey): Promise<void>

该方法可以通过CA的公钥来验证证书的有效性。

本文将通过一个示例演示数字证书内容的查看方法以及如何对一个数字证书进行验签。

2. TLS数字证书查看及验签演示

本示例运行后的界面如图所示:

单击CA证书后面的“选择”按钮,选择一个CA证书,再单击“查看”按钮可以查看该证书的详细信息,如图所示:

然后再选择一个不是该CA证书签发的用户证书,比如百度的证书,再单击“验签”按钮:

很显然,验签失败了。再选择一个该CA证书签名的用户证书,然后单击“验签”按钮:

这次验签就通过了。

3. TLS数字证书查看及验签示例编写

下面详细介绍创建该示例的步骤。

步骤1:创建Empty Ability项目。

步骤2:在Index.ets文件里添加如下的代码:

import { BusinessError } from '@kit.BasicServicesKit';
import { cert } from '@kit.DeviceCertificateKit';
import fs from '@ohos.file.fs';
import { picker } from '@kit.CoreFileKit';@Entry
@Component
struct Index {//连接、通讯历史记录@State msgHistory: string = ''//CA证书是否已选择@State caFileSelect: boolean = false//用户证书是否已选择@State certFileSelect: boolean = false//选择的ca文件@State caFileUri: string = ''//选择的用户证书文件@State certFileUri: string = ''scroller: Scroller = new Scroller()build() {Row() {Column() {Text("数字证书查看及验签示例").fontSize(14).fontWeight(FontWeight.Bold).width('100%').textAlign(TextAlign.Center).padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("CA证书").fontSize(14).width(90).flexGrow(1)Button("选择").onClick(async () => {this.caFileUri = await selectSingleDocFile(getContext(this))if (this.caFileUri) {this.caFileSelect = true}}).width(70).fontSize(14)Button("查看").onClick(() => {this.viewCertInfo(this.caFileUri)}).width(70).fontSize(14).enabled(this.caFileSelect)}.width('100%').padding(10)Text(this.caFileUri).width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("用户证书:").fontSize(14).width(90).flexGrow(1)Button("选择").onClick(async () => {this.certFileUri = await selectSingleDocFile(getContext(this))if (this.certFileUri) {this.certFileSelect = true}}).width(70).fontSize(14)Button("查看").onClick(() => {this.viewCertInfo(this.certFileUri)}).width(70).fontSize(14).enabled(this.certFileSelect)Button("验签").onClick(() => {this.verifyCert(this.caFileUri, this.certFileUri)}).width(70).fontSize(14).enabled(this.certFileSelect && this.caFileSelect)}.width('100%').padding(10)Text(this.certFileUri).width('100%').padding(10)Scroll(this.scroller) {Text(this.msgHistory).textAlign(TextAlign.Start).padding(10).width('100%').backgroundColor(0xeeeeee)}.align(Alignment.Top).backgroundColor(0xeeeeee).height(300).flexGrow(1).scrollable(ScrollDirection.Vertical).scrollBar(BarState.On).scrollBarWidth(20)}.width('100%').justifyContent(FlexAlign.Start).height('100%')}.height('100%')}//输出指定证书文件的证书信息async viewCertInfo(filePath: string) {let x509Cert = await this.getCertFromFile(filePath)if (x509Cert != undefined) {this.showCertInfo(x509Cert)} else {this.msgHistory += "错误的证书文件格式:" + filePath + "\r\n";}}//从文件获取X509证书async getCertFromFile(filePath: string): Promise<cert.X509Cert | undefined> {let newCert: cert.X509Cert | undefined = undefined//读取文件内容let certData = readArrayBufferContentFromFile(filePath);if (certData) {let encodingBlob: cert.EncodingBlob = {data: new Uint8Array(certData),encodingFormat: cert.EncodingFormat.FORMAT_PEM};//创建X509数字证书await cert.createX509Cert(encodingBlob).then((x509Cert: cert.X509Cert) => {newCert = x509Cert}).catch((err: BusinessError) => {this.msgHistory += `创建X509证书失败: 错误码 ${err.code}, 错误信息 ${JSON.stringify(err)}\r\n`;})}return newCert}//输出证书信息async showCertInfo(x509Cert: cert.X509Cert) {try {let issuerName = x509Cert.getIssuerX500DistinguishedName().getName()this.msgHistory += `颁发者可分辨名称:${issuerName}\r\n`;let subjectName = x509Cert.getSubjectX500DistinguishedName().getName()this.msgHistory += `证书主题可分辨名称:${subjectName}\r\n`;let subjectCNName = x509Cert.getSubjectX500DistinguishedName().getName("CN")this.msgHistory += `证书主题CN名称:${subjectCNName}\r\n`;this.msgHistory += `证书有效期:${x509Cert.getNotBeforeTime()}${x509Cert.getNotAfterTime()}\r\n`;this.msgHistory += `证书签名算法:${x509Cert.getSignatureAlgName()}\r\n`;} catch (e) {this.msgHistory += '输出证书信息异常: ' + e.message + "\r\n";}}//使用CA证书验证用户证书async verifyCert(caFilePath: string, certFilePath: string) {//获取CA证书let caCert = await this.getCertFromFile(caFilePath)if (caCert == undefined) {this.msgHistory += "错误的证书文件格式:" + caFilePath + "\r\n";return}//获取用户证书let userCert = await this.getCertFromFile(certFilePath)if (userCert == undefined) {this.msgHistory += "错误的证书文件格式:" + certFilePath + "\r\n";}//使用CA证书公玥验证用户证书userCert?.verify(caCert.getPublicKey()).then(() => {this.msgHistory += "证书验签通过\r\n";}).catch((err: BusinessError) => {this.msgHistory += `验签失败:错误码 ${err.code}, 错误信息 ${JSON.stringify(err)}\r\n`;})}
}//选择单个文件并返回选中文件地址
async function selectSingleDocFile(context: Context): Promise<string> {let selectedFilePath: string = ""let documentPicker = new picker.DocumentViewPicker(context);await documentPicker.select({ maxSelectNumber: 1 }).then((result) => {if (result.length > 0) {selectedFilePath = result[0]}})return selectedFilePath
}//从文件读取二进制内容
function readArrayBufferContentFromFile(fileUri: string): ArrayBuffer {let file = fs.openSync(fileUri, fs.OpenMode.READ_ONLY);let fsStat = fs.statSync(file.fd);let buf = new ArrayBuffer(fsStat.size);fs.readSync(file.fd, buf);fs.fsyncSync(file.fd)fs.closeSync(file);return buf
}

步骤3:编译运行,可以使用模拟器或者真机。

步骤4:按照本节第2部分“TLS数字证书查看及验签演示”操作即可。

4. 代码分析

本示例关键点有两个,一个是从证书文件中获取证书信息创建X509Cert对象,这是通过方法getCertFromFile实现的;另一个是使用CA证书验签用户证书,在获取CA公钥的时候使用的是X509Cert的getPublicKey方法,需要注意的是,该方法获取的公钥只能用于验签,不能用来获取公钥的内容,否则会出现异常。

(本文作者原创,除非明确授权禁止转载)

本文源码地址:
https://gitee.com/zl3624/harmonyos_network_samples/tree/master/code/tls/CertVerify

本系列源码地址:
https://gitee.com/zl3624/harmonyos_network_samples

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58373.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

路虎裁员,又玩出了新花样。。

大家好&#xff0c;我是程序员面试刷题平台的鸭鸭&#xff01; 最近裁员的新闻已经不少见了&#xff0c;但鸭鸭没想到&#xff0c;公司裁员的花样真是越来越多了。 最近流言中裁员比例超过 50% 的捷豹路虎&#xff0c;听说就专门为裁员开辟了一个快速离职专区&#xff1a;前一…

C#运算符与表达式详解

在C#编程中&#xff0c;运算符和表达式是构建复杂逻辑和处理数据的关键元素。以下是对C#运算符与表达式的详细解析&#xff1a; 一、运算符 运算符是一种特殊的符号&#xff0c;用于执行各种数学、逻辑和其他操作。C#中的运算符可以分为以下几类&#xff1a; 算术运算符&…

【Linux】使用<信号量>实现<线程互斥>(思维导图&代码演示&思路解析)

前言 大家好吖&#xff0c;欢迎来到 YY 滴Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

【A股小探-01】股指期货交割日对股指的影响

本文来源于量化小论坛策略分享会板块精华帖&#xff0c;作者为刘世宇&#xff0c;发布于2024年5月3日。 以下为精华帖正文&#xff1a; 01 引言 自踏入 A 股市场以来&#xff0c;笔者注意到了众多所谓的“效应”与“魔咒”&#xff0c;例如黑周四、黑四月、财报季魔咒、节前效…

K8S nginx pod结合cronJob实现日志按天切割 —— 筑梦之路

前言 nginx的官方镜像都是把日志重定向到标准输出&#xff0c;如果没有特别需求&#xff0c;已经能满足大多数的使用。 这里我主要对官方镜像进行改造&#xff0c;添加logrotate&#xff0c;结合cronJob来实现nginx日志的自动轮转&#xff0c;以方便排查故障问题。 编写Dock…

ios 快捷指令扩展(Intents Extension)简单使用 swift语言

本文介绍使用Xcode15 建立快捷指令的Extension&#xff0c;并描述如何修改快捷指令的IntentHandler&#xff0c;带参数跳转主应用&#xff1b;以及展示多个选项的快捷指令弹框(配置intentdefinition文件)&#xff0c;点击选项带参数跳到主应用的方法 创建快捷指令 快捷指令是…

GPT论文整理提示词

论文阅读 指令1:粗读论文 请你阅读并理解这篇文献&#xff0c;然后将该篇文章的标题作为一级标题&#xff0c;将摘要和各个大标题作为二级标题&#xff0c;将小标题作为三级标题&#xff0c;将小标题下每一部分内容作为四级标题&#xff0c;给我以markdown的语言输出中文的翻…

【回溯算法】(第七篇)

目录 ⼦集&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 找出所有⼦集的异或总和再求和&#xff08;easy&#xff09; 题目解析 讲解算法原理 编写代码 ⼦集&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;Le…

技术干货|如何巧妙利用数字孪生技术助力口腔保健分析

行业&#xff1a; 口腔医疗 挑战&#xff1a; 传统方法缺乏预测口腔内受力状态&#xff0c;也很难从患者方面获得反馈&#xff0c;因此将口腔扫描、牙齿形状/位置识别和正畸数字模型生成的过程数字化是一个重大机会。 正畸治疗是牙科中最大的类别之一&#xff0c;随着病例的…

ubuntu 挂载 新 硬盘 ext3

ubuntu 挂载 新 硬盘 在Ubuntu中使用新的硬盘并格式化为ext3文件系统&#xff0c;你需要执行以下步骤&#xff1a; 插入硬盘并确认系统已识别。 确定硬盘的设备名称&#xff0c;例如 /dev/sdb。 使用mkfs.ext3命令格式化硬盘为ext3文件系统。 以下是具体的命令&#xff1a…

Spring 设计模式之装饰器模式

Spring 设计模式之装饰器模式 装饰器模式用到的场景具体的java例子&#xff1a; 装饰器模式 装饰器模式允许我们在不修改原始类&#xff08;即被装饰对象&#xff09;的情况下&#xff0c;动态地向对象添加新的行为或修改现有行为。 用到的场景 存在一个原始类&#xff0c;在…

星巴克们需要找回节奏

“重返星巴克”需要更多运气。 作者|金豫 编辑|杨舟 国内咖啡市场正上演着一场后浪推前浪的经典剧目。 近期&#xff0c;“太平洋咖啡”传出大规模关店的消息。该品牌在多座城市中仅剩下几家门店&#xff0c;且多数集中在机场。而在2016年前后&#xff0c;太平洋咖啡一度超越…

React 前端框架全面教程:从入门到进阶

React 前端框架全面教程&#xff1a;从入门到进阶 引言 在现代前端开发中&#xff0c;React 作为一款流行的 JavaScript 库&#xff0c;以其组件化、声明式的特性和强大的生态系统&#xff0c;成为了开发者的首选。无论是构建单页应用&#xff08;SPA&#xff09;还是复杂的用…

【日志】网络传输协议TCP/UDP/HTTP // unity泛型类单例模式

2024.10.23 【力扣刷题】 暂无 【数据结构】 暂无 【其他】 TCP&#xff08;传输控制协议&#xff09;&#xff08;长连接&#xff09;&#xff1a; TCP 是一种面向连接的、可靠的协议&#xff0c;它通过三次握手建立连接&#xff0c;确保数据的可靠传输。 第一次是客户端向服…

【力扣 + 牛客 | SQL题 | 每日4题】牛客大厂面试真题W3,W10

1. 牛客大厂面试真题SQLW3&#xff1a;分析客户逾期情况 1.1 题目&#xff1a; 描述 有贷款信息表&#xff1a;loan_tb&#xff08;agreement_id&#xff1a;合同id&#xff0c;customer_id&#xff1a;客户id&#xff0c;loan_amount&#xff1a;贷款金额&#xff0c;pay_a…

在 Windows 中使用 GCC 编译运行 C++

在 Windows 中使用 GCC 编译开发 C 通过 MSYS2 安装 MinGW 工具链 MSYS2&#xff08;Minimal SYStem 2&#xff09;是一个集成了大量的GNU工具链、工具和库的开源软件包集合。它提供了一个类似于 Linux 的shell环境&#xff0c;可以在 Windows 系统中编译和运行许多 Linux 应…

铝基板PCB创建助手

支持在创建元件时创建网表 支持圆形和矩形阵列布局 支持板框信息修改 支持缺口位置修改 支持元件封装预览 支持原理图预览 支持PCB板框和布局预览 支持灯珠方向更改为切向和径向 支持报告输出 支持元件封装选择 铝基板PCB创建助手 V1.0

Nginx 配置基于IP 地址的 Web 服务器

Nginx 配置基于IP 地址的 Web 服务器 1.配置网卡 nmcli connection modify ipv4.address 192.168.232.130/24 ipv4.gateway 192.168.232.2 ipv4.dns 192.168.232.2 ipv4.method manual connection.autoconnect yes 2.添加ip地址 nmcli connection modify ens160 ipv4.address…

如何理解全局和局部的规律

再和大家聊的话题是全局和局部的辩证关系。 研究全局和局部的辩证关系&#xff0c;研究的就是做事的方法。 不过这里说的做事的方法不是具体的执行办法&#xff0c;比如这一步应该怎么做&#xff0c;那一步应该怎么做。 而是重在思考&#xff0c;应该先做什么&#xff0c;后…

GPT-Sovits-2-微调模型

1. 大致步骤 上一步整理完数据集后&#xff0c;此步输入数据, 微调2个模型VITS和GPT&#xff0c;位置在 <<1-GPT-SoVITS-tts>>下的<<1B-微调训练>> 页面的两个按钮分别执行两个文件: <./GPT_SoVITS/s2_train.py> 这一步微调VITS的预训练模型…