发布时间: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. Swift3.0:照片选择

    一.介绍 图片选择或者拍照功能: 1.选择相册中的图片或是拍照,都是通过UIImagePickerController控制器实例化一个对象,然后通过self.presentViewController ...

  2. 【VC++积累】之八、PreTranslageMessage;TranslageMessage;GetMessage和PeekMessage的区别

    先来看windows消息机制: 首先系统(也就是windows)把来自硬件(鼠标,键盘等消息)和来自应用程序的消息 放到一个系统消息队列中去. 而应用程序需要有自己的消息队列,也就是线程消息队列,每一 ...

  3. maven项目里,junit的test程序不能访问src/test/resource下面的配置

    问题描述 最近在写单元测试,但是不想改动源代码,所以想自己在本test目录下建一个resouces文件夹并添加对应的配置文件,可是发现test程序无法读取这个resouces文件夹下的配置. 问题解决 ...

  4. go语言之进阶篇recover的使用

    1.recover的使用 示例: package main import "fmt" func testa() { fmt.Println("aaaaaaaaaaaaaa ...

  5. solr4.7配置(ik-analyzer)

    环境: windows server 2003 sp2 x86 tomcat8.0 solr-4.7.2 IK Analyzer 2012FF_hf1 ————————————华丽的分割线—————— ...

  6. [leetcode]Combinations @ Python

    原题地址:https://oj.leetcode.com/problems/combinations/ 题意:组合求解问题. 解题思路:这种求组合的问题,需要使用dfs来解决. 代码: class S ...

  7. VS2008中MFC对话框界面编程Caption中文乱码的解决办法

    文章转载自http://blog.csdn.net/ajioy/article/details/6877646 最近在使用VS2008编写一个基于对话框的程序时,在对话框中添加Static控件,编写其 ...

  8. 持续集成之代码质量管理-Sonar [三]

    转载:https://www.abcdocker.com/abcdocker/2053 摘要 Sonar 是一个用于代码质量管理的开放平台.通过插件机制,Sonar 可以集成不同的测试工具,代码分析工 ...

  9. iredmail安装问题

    =================================== 已解决::::(据铭哥说 只有最新版0.9.2才会出现这个问题) 解决办法::(都是IPv6惹的祸) vi /etc/dovec ...

  10. SNS网站的用户流失率怎么会高得如此惊人?

    作者:黄绍麟 原51.com高管 用户典型的SNS体验 甲先生是个普通白领,白天工作使用互联网找资料连络客户,下班后回家偶而会上网闲逛.互联网是他日常接触的媒介,但是在他生命中这个东西并不显得特别重要 ...