鸿蒙网络编程系列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;前一…

【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;例如黑周四、黑四月、财报季魔咒、节前效…

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

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

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

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

星巴克们需要找回节奏

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

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

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

【力扣 + 牛客 | 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

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

再和大家聊的话题是全局和局部的辩证关系。 研究全局和局部的辩证关系&#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的预训练模型…

【LeetCode】两数之和、大数相加

主页&#xff1a;HABUO&#x1f341;主页&#xff1a;HABUO 1.两数之和 题目&#xff1a;给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一…

根据输入的详细地址解析经纬度

摘要&#xff1a; 今天遇到一个需求&#xff1a;就是做客户导入的时候因为导入的客户地址的时候没有经纬度的&#xff0c;但是同步的时候需要经纬度的&#xff0c;所以还是要根据客户提供的详细地址解析出来对应的经纬度&#xff01;回填到对应的经纬度的表单之中进行客户的同步…

【文心智能体 | AI大师工坊】如何使用智能体插件,完成一款旅游类智能体的开发,来体验一下我的智能体『​​​​​​​背包客』

&#x1f680;『背包客』点击前往体验&#xff1a;https://mbd.baidu.com/ma/s/d7RHMlWh 最近参加了百度文心智能体平台AI大师工坊&#x1f389;活动&#xff0c;在这个活动中&#xff0c;我利用文心平台提供的各种插件、大模型等工具&#xff0c;打造了一个工具类的智能体应用…

WPF的触发器(Trigger)

WPF&#xff08;Windows Presentation Foundation&#xff09;是微软.NET框架的一部分&#xff0c;用于构建Windows客户端应用程序。在WPF中&#xff0c;触发器&#xff08;Triggers&#xff09;是一种强大的功能&#xff0c;允许开发者根据控件的状态或属性值来动态改变控件的…

ChatGPT、Python和OpenCV支持下的空天地遥感数据识别与计算——从0基础到15个案例实战应用

在科技飞速发展的时代&#xff0c;遥感数据的精准分析已经成为推动各行业智能决策的关键工具。从无人机监测农田到卫星数据支持气候研究&#xff0c;空天地遥感数据正以前所未有的方式为科研和商业带来深刻变革。然而&#xff0c;对于许多专业人士而言&#xff0c;如何高效地处…

Java中String的length与Oracle数据库中VARCHAR2实际存储长度不一致的问题

目录 一、根本原因 二、解决方案 一、根本原因 Oracle数据库新增数据的时候报如下错误&#xff1a; 先给大家看个小案例&#xff0c;这样更好去理解&#xff0c;下面是一段测试代码&#xff1a; 这里面我分别列举了三种字符串&#xff0c;中文&#xff0c;英文和数字以及两种…

动态规划 —— 路径问题-礼物的最大价值

1. 剑指offer-JZ47-路径问题-礼物的最大价值 题目链接&#xff1a; 礼物的最大价值_牛客题霸_牛客网https://www.nowcoder.com/practice/2237b401eb9347d282310fc1c3adb134?tpId265&tqId39288&ru/exam/oj 2. 算法原理 状态表示&#xff1a;以莫一个位置位置为结尾 d…

安装git-lfs发生报错Could not find Git; can not register Git LFS.解决方案

解决方案&#xff1a; 步骤1.安装Github-Deskop Download GitHub Desktop | GitHub Desktophttps://desktop.github.com/download/ 步骤2.安装 Git&#xff01; Git for WindowsWe bring the awesome Git VCS to Windowshttps://gitforwindows.org/ 这两个安装完成之后即可…