iOS12 Network框架 自签名证书认证
概述
详细
需求:
并不是每个SSL/TLS站点都能得到一个全球公认的证书,很多时候需要自行生成自签名证书做为根证书。有了自签名根证书还需要手动地用它去验证服务端证书。
概要:
1.生成自签名概证书,服务端证书
2.做一个使用服务端证书的SSL/TLS的服务
3.做一个使用自签名证书访问服务的客户端
结构:
效果:
初始界面 发送接收后
我们开始吧!
证书生成:
先构建目录:
1.mkdir certs
2.cd certs
3.unzip store.zip
操作之后,目录如下:
生成自签名根证书,在centos上依次执行以下命令:
1.私钥:openssl genrsa -out ca.key 1024
2.公钥:openssl rsa -in ca.key -pubout -out ca.pem
3.证书:openssl req -new -x509 -days 365 -key ca.key -out ca.crt
执行完成在当前目录下产生以下文件:
其中ca.pem就是生成的自签名根证书。
生成服务端证书,在centos上依次执行如下命令:
1.私钥:openssl genrsa -out server.key 1024
2.公钥:openssl rsa -in server.key -pubout -out server.pem
3.请求:openssl req -new -nodes -key server.key -out server.csr
4.签证:openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -config store/openssl.cnf
执行完成后当前目录如下所示:
其中server.pem,server.key分别是服务端的证书和私钥。因为iOS需der格式的证书,我们把根证书ca.pem转换一下。
5.转换:openssl x509 -outform der -in ca.crt -out ca.der
服务端程序:
好了,所需证书都已生成。其中服务端需要server.crt, server.key,需客户端需要ca.der。下面我们先做一个非常简单的服务端,用来配合客户端的连接测试。在centos上创建文件server.go,内容如下:
package main import (
"log"
"io"
"net"
"crypto/tls"
) func main() {
crt, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
log.Fatal(err)
}
conf := &tls.Config{Certificates: []tls.Certificate{crt}}
listener, err := tls.Listen("tcp", ":8080", conf)
if err != nil {
log.Fatal(err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
process(conn)
conn.Close()
}
} func process(conn net.Conn) {
rdata := make([]byte, 2048)
rlen, err := conn.Read(rdata)
if err != nil && err != io.EOF {
log.Println(err)
return
}
_, err = conn.Write(rdata[:rlen])
if err != nil {
log.Println(err)
return
}
}
程序很简单,创建支持tls的服务程序,接收到发送过来的内容,再原样返回出去。
编译:go build server.go
注意:server.crt, server.key与编译出来的server放在同一目录下。然后,执行程序,等待连接到来。
执行:./server
客户端程序:
创建一个iOS工程, 然后把ca.der拖到工程下面:
注意:添加ca.der时,一定要选上Add to targets选项。
Main.storyboard里添加一个Label和一个Button即可,我们毕竟只是演示tls如何工作,没必要搞那么花哨。
在ViewController里添加上如下代码:
import UIKit
import Network class ViewController: UIViewController {
@IBOutlet weak var messageLabel: UILabel! let queue = DispatchQueue(label: "myqueue")
var conn: NWConnection! override func viewDidLoad() {
super.viewDidLoad()
messageLabel.layer.borderWidth = 1
} @IBAction func start(_ sender: Any) {
let host = NWEndpoint.Host("10.21.16.202")
let port = NWEndpoint.Port(integerLiteral: 8080) let options = NWProtocolTLS.Options()
sec_protocol_options_set_verify_block(options.securityProtocolOptions, { (sec_protocol_metadata, sec_trust, sec_protocol_verify_complete) in // 为信任证书链设置自签名根证书
let trust = sec_trust_copy_ref(sec_trust).takeRetainedValue()
if let url = Bundle.main.url(forResource: "ca", withExtension: "der"),
let data = try? Data(contentsOf: url),
let cert = SecCertificateCreateWithData(nil, data as CFData) {
if SecTrustSetAnchorCertificates(trust, [cert] as CFArray) != errSecSuccess {
sec_protocol_verify_complete(false)
return
}
} // 设置验证策略
let policy = SecPolicyCreateSSL(true, "myserver" as CFString)
SecTrustSetPolicies(trust, policy)
SecTrustSetAnchorCertificatesOnly(trust, true) // 验证证书链
var error: CFError?
if SecTrustEvaluateWithError(trust, &error) {
sec_protocol_verify_complete(true) } else {
sec_protocol_verify_complete(false)
print(error!)
}
}, queue) conn = NWConnection(host: host, port: port, using: NWParameters(tls: options))
conn.start(queue: queue) let messge = "hello"
conn.send(content: messge.data(using: .utf8)!, completion: .contentProcessed({ (error) in
if let error = error {
print(error)
self.conn.cancel()
} else {
print("消息已发送:\(messge)")
}
})) conn.receive(minimumIncompleteLength: 1, maximumLength: 1024) { (data, context, isComplete, error) in
if let error = error {
print(error)
self.conn.cancel()
return
} if let data = data {
DispatchQueue.main.async {
self.messageLabel.text = String(data: data, encoding: .utf8)!
} print("消息已收到:\(String(data: data, encoding: .utf8)!)")
} if isComplete {
self.conn.cancel()
self.conn = nil
}
}
}
}
NWConnection需要一个NWParameters类型的选项,当NWConnection建立连接以及收发数据的时候会使用这些选项调整连接的行为。系统默认一个选项是NWParameters.tls,然后这个选项在tls连接建立时验证服务端证书的时候使用的是iOS系统里预置的要证书,这并不满足我们的需求。
我们必须找到一个地方能定制化双方握手时的证书验证形为。我们可以通过配置NWProtocolTLS.Options.SecurityProtocolOptions添加一个验证回调块来达成这个需求。原型如下:
typedef void (^sec_protocol_verify_t)(sec_protocol_metadata_t metadata, sec_trust_t trust_ref, sec_protocol_verify_complete_t complete); API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0))
void
sec_protocol_options_set_verify_block(sec_protocol_options_t options, sec_protocol_verify_t verify_block, dispatch_queue_t verify_block_queue);
回调块的参数metadata,可以从中遍历出对端的证书列表。参数trust_ref,可以从中遍历出信任证书列表(对端的证书列表和对端证书链对应的根证书),当然我们自签名根证书不在iOS系统中,系统不会自动为我们添加上,需要我们手动添加。
通过SecCertificateCreateWithData()我们从ca.der生成要证书对象,然后通过SecTrustSetAnchorCeritificates()把它添加信任证书链表中。接着我们通过SecPolicyCreateSSL()生成一个验证策略,其中"myserver"是服务端证书对应的名字,可以查看服务端证书得到,这里也即限制服务端证书的CN必须为myserver,否则验证失败。SecTrustSetPolicies()为信任证书链添加验证策略,SecTrunstSetAnchorCeritificatesOnly()只信任我们自已添加的根证书来验证服务端证书。
SecTrustEvaluateWithError()来最终验证服务端证书,如若有错,通过打印error知道具体的错误原因。验证的成功否是失败都要通过参数complete回调来告知NWConnection以继续后续的握手操作。
连接建立之后就可以自由的收发消息了。
最后项目结构介绍:
源码目录如下:
其中server.go是服务端的代码, learn.zip是客户端的代码 store.zip是生成证书的时一些配置文件。
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
iOS12 Network框架 自签名证书认证的更多相关文章
- Https自签名证书认证及数据请求的封装
在WWDC 2016开发者大会上,苹果宣布了一个最后期限:到2017年1月1日 App Store中的所有应用都必须启用 App Transport Security安全功能.App Transpor ...
- Let's Encrypt 免费通配 https 签名证书 安装方法2 ,安卓签名无法认证!
Let's Encrypt 免费通配 https 签名证书 安装方法 按照上文 配置完毕后你会发现 在pc浏览器中正常访问,在手机浏览器中无法认证 你只需要安装一个或多个中级证书 1.查看Nginx ...
- SpringBoot服务间使用自签名证书实现https双向认证
SpringBoot服务间使用自签名证书实现https双向认证 以服务server-one和server-two之间使用RestTemplate以https调用为例 一.生成密钥 需要生成server ...
- HTTPS协议、TLS协议、证书认证过程解析
一.HTTPS 协议 HTTPS协议其实就是HTTP over TSL,TSL(Transport Layer Security) 传输层安全协议是https协议的核心. TSL可以理解为SSL (S ...
- tomcat 配置客户端证书认证
在完成配置客户端证书认证后,浏览器以https访问服务器的时候,会提示选择证书,之后,服务器端会验证证书.也就意味着只有拥有有效证书的客户端才能打开该网站. 以下是具体的配置过程. 1. 在服务器端生 ...
- cmd命令生成android签名证书
cmd命令生成android签名证书,有空在写一篇eclipse导出带签名的apk,这里面包括生成新的签名.现在还是讲讲在cmd怎么操作生成签名证书. 1.dos下进入JDK的bin目录 运行如下命令 ...
- iOS开发HTTPS实现之信任SSL证书和自签名证书
iOS开发HTTPS实现之信任SSL证书和自签名证书 转自:http://www.jianshu.com/p/6b9c8bd5005a/comments/5539345 (收录一下供自己学习用的) 字 ...
- AFNetWorking3.0使用 自签名证书的https请求
前几日,项目组出于安全角度的考虑,要求项目中的请求使用https请求,因为是企业内部使用的app,因此使用了自签名的证书,而自签名的证书是不受信任的,所以我们就需要自己来做证书的验证,包括服务器验证客 ...
- mobileconfig文件的签名和认证(signed、verified)
专题:基于IOS上MDM技术相关资料整理及汇总mobileconfig文件的签名和认证(signed.verified) 一.功能描述: 鉴于我们的设备和MDM server之间已经可以通信,并能完成 ...
随机推荐
- Swift3.0:照片选择
一.介绍 图片选择或者拍照功能: 1.选择相册中的图片或是拍照,都是通过UIImagePickerController控制器实例化一个对象,然后通过self.presentViewController ...
- 【VC++积累】之八、PreTranslageMessage;TranslageMessage;GetMessage和PeekMessage的区别
先来看windows消息机制: 首先系统(也就是windows)把来自硬件(鼠标,键盘等消息)和来自应用程序的消息 放到一个系统消息队列中去. 而应用程序需要有自己的消息队列,也就是线程消息队列,每一 ...
- maven项目里,junit的test程序不能访问src/test/resource下面的配置
问题描述 最近在写单元测试,但是不想改动源代码,所以想自己在本test目录下建一个resouces文件夹并添加对应的配置文件,可是发现test程序无法读取这个resouces文件夹下的配置. 问题解决 ...
- go语言之进阶篇recover的使用
1.recover的使用 示例: package main import "fmt" func testa() { fmt.Println("aaaaaaaaaaaaaa ...
- solr4.7配置(ik-analyzer)
环境: windows server 2003 sp2 x86 tomcat8.0 solr-4.7.2 IK Analyzer 2012FF_hf1 ————————————华丽的分割线—————— ...
- [leetcode]Combinations @ Python
原题地址:https://oj.leetcode.com/problems/combinations/ 题意:组合求解问题. 解题思路:这种求组合的问题,需要使用dfs来解决. 代码: class S ...
- VS2008中MFC对话框界面编程Caption中文乱码的解决办法
文章转载自http://blog.csdn.net/ajioy/article/details/6877646 最近在使用VS2008编写一个基于对话框的程序时,在对话框中添加Static控件,编写其 ...
- 持续集成之代码质量管理-Sonar [三]
转载:https://www.abcdocker.com/abcdocker/2053 摘要 Sonar 是一个用于代码质量管理的开放平台.通过插件机制,Sonar 可以集成不同的测试工具,代码分析工 ...
- iredmail安装问题
=================================== 已解决::::(据铭哥说 只有最新版0.9.2才会出现这个问题) 解决办法::(都是IPv6惹的祸) vi /etc/dovec ...
- SNS网站的用户流失率怎么会高得如此惊人?
作者:黄绍麟 原51.com高管 用户典型的SNS体验 甲先生是个普通白领,白天工作使用互联网找资料连络客户,下班后回家偶而会上网闲逛.互联网是他日常接触的媒介,但是在他生命中这个东西并不显得特别重要 ...