SecCertificate 解析

news2024/12/23 2:04:57

一、SecCertificate

A digital certificate is a collection of data used to securely distribute the public half of a public/private key pair.
数字证书

1. 结构

请添加图片描述

2. 读取和存储

2.1 Identity

var certificate: SecCertificate?
let status = SecIdentityCopyCertificate(identity, &certificate)
guard status == errSecSuccess else { return }

2.2 Der-Encode Data from File

// get data for certificate
let certificate =  a certificate
let certData = SecCertificateCopyData(certificate) as Data

// create  certificate with data
let certificate = SecCertificateCreateWithData(nil, certData as CFData)

2.3 KeyChain

  • add to KeyChain
let addquery: [String: Any] = [
	kSecClass as String: kSecClassCertificate,
	kSecValueRef as String: certificate,
	kSecAttrLabel as String: "My Certificate",
]

var status = SecItemAdd(addquery as CFDictionary, nil)
guard status == errSecSuccess else {
	return
}
  • read from keyChain
let getquery: [String: Any] = [
	kSecClass as String: kSecClassCertificate,
 	kSecAttrLabel as String: "My Certificate",
	kSecReturnRef as String: kCFBooleanTrue,
]

var item: CFTypeRef?
status = SecItemCopyMatching(getquery as CFDictionary, &item)
guard status == errSecSuccess else {
	return
}
let certificate = item as! SecCertificate

3. 属性解析

3.1 官方API: SecCertificateCopy系列函数

SecCertificateCopyKey: 获取公钥
SecCertificateCopyData: DER表示
SecCertificateCopyCommonName: 证书主题的公共名称
SecCertificateCopySubjectSummary: 一个简单的字符串,希望代表一个人可以理解的总结。
注: 官方iOS 平台API 只提供了少量的属性访问

3.2 三方参考解析工程: https://github.com/filom/ASN1Decoder

二、SecKey

SecKey即可以是public key 也可以是 private key.存在以下三种编码方式:

For an RSA key, the function returns data in the PKCS #1 format.

For an elliptic curve public key, the format follows the ANSI X9.63 standard using a byte string of 04 || X || Y.

For an elliptic curve private key, the output is formatted as the public key concatenated with the big endian encoding of the secret scalar, or 04 || X || Y || K.

1. 读取和存储

1.1 An identity

  • load p12 file
func loadP12File() -> Dictionary<String, Any> {
        var url = Bundle(for: P12FileStorageAndParseTests.self).resourceURL!
        url.appendPathComponent("fitchAppleAccount.p12")
        
        let data = try! Data(contentsOf: url)
        
        let password = "******"
        let options = [kSecImportExportPassphrase as String: password]
        
        var rawItems: CFArray?
        // suport DER 和 PEM Encode
        let status = SecPKCS12Import(data as CFData,
                                     options as CFDictionary,
                                     &rawItems)
        
        guard status == errSecSuccess else {
            fatalError("parse p12 file failure")
        }
        // p12 文件可以包含多个证书和私钥
        let items = rawItems! as! Array<Dictionary<String, Any>>
        let firstItem = items[0]
        return firstItem
    }
  • get SecIdentity from p12Attrs
func testParseP12File() {
        let p12Attrs = loadP12File()

        // parse p12 file
        let identity = p12Attrs[kSecImportItemIdentity as String] as! SecIdentity

    }
  • add to key chain
let persistentRef = addToKeyChain() as! NSData
    
// 一旦存储成功, 需要将这个唯一标识符进行永久性存储    
UserDefaults.standard.set(persistentRef, forKey: "kSecReturnPersistentRef")
func addToKeyChain() -> CFTypeRef? {
        let p12Attrs = loadP12File()
        
        // parse p12 file
        let identity = p12Attrs[kSecImportItemIdentity as String] as! SecIdentity
        
        var addResult: CFTypeRef?
        let addquery: [String: Any] = [
            kSecValueRef as String: identity,
            kSecReturnPersistentRef as String: true,
            ]

        let status = SecItemAdd(addquery as CFDictionary, &addResult)
        guard status == errSecSuccess else {
            print("addToKeyChain failure: \(status)")
            return nil
        }
        
	return addResult
}
  • load from key chain
UserDefaults.standard.set(persistentRef, forKey: "kSecReturnPersistentRef")

        
        let identity = queryItem(persistentRef: persistentRef)!
        
        // get  private key
        var privateKey: SecKey?
        var status = SecIdentityCopyPrivateKey(identity, &privateKey)
        
        XCTAssert(status == noErr)
        XCTAssert(privateKey != nil)
        
        // get public key
        var certificate: SecCertificate?
        status = SecIdentityCopyCertificate(identity, &certificate)
        
        XCTAssert(status == noErr)
        XCTAssert(certificate != nil)
        let publicKey = SecCertificateCopyKey(certificate!)
        XCTAssert(publicKey != nil)

    func queryItem(persistentRef: NSData) -> SecIdentity? {
        let getquery: [String: Any] = [
            kSecReturnRef as String: kCFBooleanTrue,
            kSecValuePersistentRef as String: persistentRef,
            ]
        
        var item: CFTypeRef?
        let status = SecItemCopyMatching(getquery as CFDictionary, &item)
        guard status == errSecSuccess else {
           
            print("queryItem failure \(status)")
            return nil
        }
        return item as! SecIdentity
    }

1.2 A trust

// 获取SecTrust 的 leaf cert public key
let publicKey = SecTrustCopyPublicKey(trust)

1.3 Another key.

//通过 privateKey 计算 publicKey
let publicKey = SecKeyCopyPublicKey(privateKey)

1.4 SecCertificate

    private static func publicKey(_ certificate: SecCertificate) -> SecKey? {
        var publicKey: SecKey?

        let policy = SecPolicyCreateBasicX509()
        var trust: SecTrust?
        let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &trust)

        if let trust = trust, trustCreationStatus == errSecSuccess {
            publicKey = SecTrustCopyPublicKey(trust)
        }

        return publicKey
    }

1.5 generate Data

  • generate Data from SecKey
let key = <# a key #>
var error: Unmanaged<CFError>?
guard let data = SecKeyCopyExternalRepresentation(key, &error) as Data else {
    throw error!.takeRetainedValue() as Error
}
  • generate SecKey from Data
let options: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
                              kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
                              kSecAttrKeySizeInBits as String : 2048]
var error: Unmanaged<CFError>?
guard let key = SecKeyCreateWithData(data as CFData,
                                     options as CFDictionary,
                                     &error) else {
                                        throw error!.takeRetainedValue() as Error
}

注意

使用苹果官方API生成的PublicData和使用OpenSSL 生成的PublicData 存在一些差异,苹果的缺少头部信息, OpenSSL拥有头部信息

解决方案:
对苹果API生成的PublicKeyData拼接额外的头部信息
对OpenSSL生成的PublicKeyData,去除头部信息

三、SecPolicy

证书评估策略

  • func SecPolicyCreateBasicX509() -> SecPolicy ,通常用于创建 SecTrust
  • func SecPolicyCreateRevocation(_ revocationFlags: CFOptionFlags) -> SecPolicy?
  • func SecPolicyCreateSSL(_ server: Bool, _ hostname: CFString?) -> SecPolicy, 用于SSL 证书认证

四、SecTrust

用于证书评估

1. 创建

let policy = SecPolicyCreateBasicX509()
var optionalTrust: SecTrust?
var status = SecTrustCreateWithCertificates(certArray as AnyObject,
                                            policy,
                                            &optionalTrust)

2. 证书评估以及解析结果

if status == errSecSuccess {
    let trust = optionalTrust!    // Safe to force unwrap now
    SecTrustEvaluateAsync(trust, DispatchQueue.global()) {
        _, trustResult in
        switch trustResult {
        case .proceed, .unspecified:
            let publicKey = SecTrustCopyPublicKey(trust)
            
            // Use key . . .
        case .recoverableTrustFailure:
            print("Trust failed recoverably")
        default:
            print("Trust failed absolutely")
        }
    }
}

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

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

相关文章

12.分布式事务流程与事务消息源码分析

highlight: arduino-light Rocket事务流程&源码分析 Rocket解决分布式事务流程 事务消息分 2 个阶段&#xff1a; ① 正常事务消息的发送与提交&#xff1a; a.发送消息(half 消息) b.服务响应消息写入结果 c.根据发送结果执行本地事务(如果写入失败&#xff0c;此时half消…

Midjourney使用教程:三 图片风格提示

这里我根据现在的官方文档来继续我们的Midjourney的教程&#xff0c;看到这里如果你去实践的话&#xff0c;估计你已经有了好多张属于自己的图片。 这时候你不在满足简单的提示生成的Midjourney的默认风格图片&#xff0c;实际上你可以通过一些关键词做提示&#xff0c;来改变…

初始网络原理

目录 网络发展史 独立模式 网络互连 局域网LAN 广域网WAN 网络通信基础 IP地址 端口号 认识协议 五元组 协议分层 OSI七层模型 TCP/IP五层&#xff08;或四层&#xff09; 网络设备所在分层 封装和分用 网络发展史 独立模式 独立模式&#xff1a;计算机之间相互…

第八十三天学习记录:计算机硬件技术基础:汇编语言程序设计

一、汇编语言指令 汇编语言的语句是在指令系统的基础上形成的&#xff0c;按其作用与编译情况分为两大类&#xff1a;指令性语句&#xff08;符号指令&#xff09;和指示性语句&#xff08;伪指令&#xff09;。 指令性语句是可执行语句&#xff0c;与机器指令相对应&#xff…

USB转换方案介绍

随着科技的不断发展&#xff0c;我们的生活中出现了越来越多的电子设备。然而&#xff0c;这些设备通常具有不同的连接端口和协议&#xff0c;这可能会使它们之间的连接变得困难。这时候&#xff0c;使用USB转换就成为了一种非常方便和实用的解决方法。 无论是在家庭、办公室还…

自动化测试——处理场景自动化测试场景详细,跟着上高速

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、定位一组对象 …

城市消防应急通信三级作战网构建

项目背景 随着我国《消防信息化“十三五”总体规划》对消防信息化的发展规划做了统一部署&#xff0c;以城市为代表的消防通信成为专网通信行业重点关注的领域之一。目前&#xff0c;我国城市化发展面临高层建筑林立、地铁、人防工程分布密集&#xff0c;大型综合体不断涌现&a…

【运维】服务器系统安装 -- 服务器版

目录 一、环境 二、ubuntu 三、启动u盘制作 Stage 1&#xff1a;下载balena&#xff0c;制作U盘启动工具 Stage 2&#xff1a;下载Ubuntu 系统镜像&#xff08;参考上一节&#xff1a;Ubuntu 22.04.2 LTS &#xff09; Stage 3&#xff1a;将镜像写入到U盘 四、设置开启…

FUZZ工具—Boofuzz框架实际使用

接着上一篇文章FUZZ工具—Boofuzz框架来对框架进行实际的使用&#xff1b; 官方提供了很多案例模板&#xff0c;且网上关于boofuzz的使用介绍很多&#xff0c;也比较成熟&#xff0c;在各个领域都有&#xff0c;可以通过官方提供的案例也看得出来&#xff0c;然后覆盖的面也非常…

西门子变频器G120XA的快速调试方法分享

以西门子变频器G120XA为例&#xff0c;接着为大家介绍一下G120X和G120XA系列变频器的快速调试方法。 西门子发布的Sinamics G120X和G120XA系列变频器&#xff0c;专为风机和泵的应用而设计&#xff0c;实现高效节能、可靠稳定和简单易用。以G120XA为例&#xff0c;通过下面的调…

locust学习教程(9)- event 事件

目录 1、对请求的测试前置、后置处理 2、在web界面添加新内容 3、监听测试的失败率或阀值 4、汇总总结 ​&#x1f381;更多干货 1、对请求的测试前置、后置处理 请求有一个上下文参数&#xff0c;通过数据有关的请求&#xff08;之类的用户名&#xff0c;标签等&#xff…

双路高速 DA 实验

目录 双路高速 DA 实验 1、简介 2、实验任务 3、程序设计 3.1、hs_dual_da顶层模块代码 3.2、ROM 波形存储模块&#xff08;rom_1024x10b&#xff09; 创建单端口 ROM IP核 3.2、DA 数据发送模块&#xff08;da_wave_send&#xff09;代码 4、硬件设计 4.1、添加.xdc…

MongoDB数据库安装

MongoDB数据库 MongoDB数据的特点&#xff1a; 面相文档存储的分布式数据库 具有很强的扩展性 支持丰富的查询表达式&#xff0c;很接近于关系性数据库 使用类似于json的结构保存数据&#xff0c;可以轻易的查询到文档中内嵌的对象及数组 下载安装包 首先去官网下载安装…

用JAVA写一个下载器第2集

文章目录 一、开发环境及工具二、包名概览三、项目结构四、使用步骤1.编写代码Constant.java&#xff1a;Downloader.javaDownloaderTask.javaDownloadInfoThread.javaFileUtils.javaHttpUtils.javaLogUtils.javaMain.java 2.运行程序 总结 一、开发环境及工具 开发环境及工具…

如果开发说这不是Bug,你会怎么处理?

在项目过程中&#xff0c;如果开发说这个不是Bug&#xff0c;你的第一反应是什么&#xff1f; 不同的人有不同的处理方式&#xff0c;也许是如下几点&#xff1a;相信开发说的&#xff0c;开发说什么就是什么&#xff0c;问题关闭&#xff1b;自己不能决定&#xff0c;啥都上升…

GP232RNL——USB到UART桥接控制器

GP232RNL是一款高度集成的USB到UART桥接控制器&#xff0c;提供了一种简单的解决方案&#xff0c;可以使用最少的元器件和PCB空间&#xff0c;将RS232接口转换为USB接口。GP232RNL包括一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带有完整的调制解调器控制信号的异…

日撸java三百行day69-70

文章目录 说明day69-70 矩阵分界1.基于矩阵分解的推荐系统&#xff08;Funk-SVD算法&#xff09;2.随机梯度下降&#xff08;SGD&#xff09;2.1 导数2.2 偏导数2.3 方向导数2.4 梯度2.5 随机梯度下降&#xff0c;与损失函数之间的关系 3.代码理解3.1 train() 方法3.2 mae方法&…

神经网络原理(2)

斯坦福大学的印度学生、机器学习爱好者 PararthShah 在2012年12月22日的使用买芒果的例子解释了神经网络&#xff0c;简单来说就是&#xff1a;如果你需要选芒果&#xff0c;但不知道什么样的芒果最好吃&#xff0c;一个简单粗暴的方法是尝遍所有的芒果&#xff0c;然后总结出个…

窗口函数之-前后函数(lag/lead)

窗口函数之-前后函数 应用&#xff1a;求同比增长、环比增长 lead(expression,n):返回当前行的后n行 > shift(-n) 数据超前n阶&#xff0c;与之对齐的就是后n行的数据lag(expression,n):返回当前行的前n行> shift(n)数据滞后n阶&#xff0c;与之对齐的就是前n行的数据 …

人工智能轨道交通行业周刊-第49期(2023.6.12-6.25)

本期关键词&#xff1a;设备智能维修、故障诊断、无人机巡查、车站联锁、LangChain、腾讯大模型 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMe…