发布时间:2018-09-21
 
技术:iOS12 xcode10 golang1.11
 

概述

iOS12 苹果发布了新的网络框架Network,可以更方便地操作底层网络通信了。使用TLS也很方便,但默认是使用系统安装的根证书验证网站证书的,如果使用自签名根证书来验证自架的网站证书,则麻烦一些,这里给大家演示一下。

详细

需求:

并不是每个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框架 自签名证书认证的更多相关文章

  1. Https自签名证书认证及数据请求的封装

    在WWDC 2016开发者大会上,苹果宣布了一个最后期限:到2017年1月1日 App Store中的所有应用都必须启用 App Transport Security安全功能.App Transpor ...

  2. Let's Encrypt 免费通配 https 签名证书 安装方法2 ,安卓签名无法认证!

    Let's Encrypt 免费通配 https 签名证书 安装方法 按照上文 配置完毕后你会发现 在pc浏览器中正常访问,在手机浏览器中无法认证 你只需要安装一个或多个中级证书 1.查看Nginx ...

  3. SpringBoot服务间使用自签名证书实现https双向认证

    SpringBoot服务间使用自签名证书实现https双向认证 以服务server-one和server-two之间使用RestTemplate以https调用为例 一.生成密钥 需要生成server ...

  4. HTTPS协议、TLS协议、证书认证过程解析

    一.HTTPS 协议 HTTPS协议其实就是HTTP over TSL,TSL(Transport Layer Security) 传输层安全协议是https协议的核心. TSL可以理解为SSL (S ...

  5. tomcat 配置客户端证书认证

    在完成配置客户端证书认证后,浏览器以https访问服务器的时候,会提示选择证书,之后,服务器端会验证证书.也就意味着只有拥有有效证书的客户端才能打开该网站. 以下是具体的配置过程. 1. 在服务器端生 ...

  6. cmd命令生成android签名证书

    cmd命令生成android签名证书,有空在写一篇eclipse导出带签名的apk,这里面包括生成新的签名.现在还是讲讲在cmd怎么操作生成签名证书. 1.dos下进入JDK的bin目录 运行如下命令 ...

  7. iOS开发HTTPS实现之信任SSL证书和自签名证书

    iOS开发HTTPS实现之信任SSL证书和自签名证书 转自:http://www.jianshu.com/p/6b9c8bd5005a/comments/5539345 (收录一下供自己学习用的) 字 ...

  8. AFNetWorking3.0使用 自签名证书的https请求

    前几日,项目组出于安全角度的考虑,要求项目中的请求使用https请求,因为是企业内部使用的app,因此使用了自签名的证书,而自签名的证书是不受信任的,所以我们就需要自己来做证书的验证,包括服务器验证客 ...

  9. mobileconfig文件的签名和认证(signed、verified)

    专题:基于IOS上MDM技术相关资料整理及汇总mobileconfig文件的签名和认证(signed.verified) 一.功能描述: 鉴于我们的设备和MDM server之间已经可以通信,并能完成 ...

随机推荐

  1. C#中的自动赋值

    工作中用到对同一个类型的对象的赋值,需要逐个属性的赋值赋过去,在网上找了很久没发觉合适的,就自己动手写了个,以做备忘用. protected void AutoAssign(object from , ...

  2. iOS:UICollectionView的扩展应用

    一.介绍 CollectionView是iOS中一个非常重要的控件,它可以实现很多的炫酷的效果,例如轮播图.瀑布流.相册浏览等.其实它和TableView很相似,都是对cell进行复用,提高系统性能. ...

  3. 南阳ACM8-一种排序

    /* 一种排序 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复:还知道这个长方形的宽和长,编号.长.宽 都是 ...

  4. iOS蓝牙空中升级(固件升级)

    空中升级又叫固件升级,指你手机从服务器下载下来的包或者数据,通过蓝牙传输给你的外设升级固件.如果你能把蓝牙的基础搞懂,其实也并不是很难,我在这里只不过提供一下思路. 空中升级略难的地方在于数据处理和交 ...

  5. JavaScript Math和Number对象研究

    1. Math 对象 1.1 介绍   Math 对象,是数学对象,提供对数据的数学计算,如:获取绝对值.向上取整等.无构造函数,无法被初始化,只提供静态属性和方法.   1.2 构造函数   无 : ...

  6. 论文分享|《Universal Language Model Fine-tuning for Text Classificatio》

    https://www.sohu.com/a/233269391_395209 本周我们要分享的论文是<Universal Language Model Fine-tuning for Text ...

  7. Altium Designer 基本封装

    1. 按键的绘制和封装怎么画?如下图: 回答:注意元件的画法不要看错了,封装采用Miscellaneous Devices.IntLib[Footprint View]中的DPST-4 2.蜂鸣器的绘 ...

  8. oauth2-server-php-docs 集成3

    Yii集成 对于Yii集成,请通过Filsh查看Yii OAuth2服务器资源库 CakePHP的 有关CakePHP中集成的这个库的示例,请参阅Qsoomro CakePHP OAuth2 Demo ...

  9. php+C#.net混合开发

    php+C#.net混合开发 上图一张,左右是php语言,右边是C#语言,解决方案中的php项目是红色的小标识

  10. WIN7系统开题提示loli.vbs 操作超时怎么办

    这个是魔兽争霸的一个病毒,但是该病毒没有任何危害性,只是作为检测进入房间的地图是否含有作弊脚本,主动提供了清除工具   搜索loli,删除所有bat和exe,vbs文件   如果魔兽争霸3安装目录存在 ...