我正在尝试从我的iOS应用程序到后端服务器(Node.js)建立简单的套接字连接(NO
HTTP)。服务器证书已使用我自己创建的自定义CA创建并签名。我相信,为了让iOS信任我的服务器,我将不得不以某种方式将此自定义CA证书添加到用于确定Java
/ Android中TrustStore的工作方式的信任类型的受信任证书列表。
我尝试使用下面的代码进行连接,并且没有错误,但是write()函数似乎未成功。
主视图控制器:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let api: APIClient = APIClient()
api.initialiseSSL("10.13.37.200", port: 8080)
api.write("Hello")
api.deinitialise()
print("Done")
}
APIClient类
class APIClient: NSObject, NSStreamDelegate {
var readStream: Unmanaged<CFReadStreamRef>?
var writeStream: Unmanaged<CFWriteStreamRef>?
var inputStream: NSInputStream?
var outputStream: NSOutputStream?
func initialiseSSL(host: String, port: UInt32) {
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &readStream, &writeStream)
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
inputStream?.delegate = self
outputStream?.delegate = self
inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
let cert: SecCertificateRef? = CreateCertificateFromFile("ca", ext: "der")
if cert != nil {
print("GOT CERTIFICATE")
}
let certs: NSArray = NSArray(objects: cert!)
let sslSettings = [
NSString(format: kCFStreamSSLLevel): kCFStreamSocketSecurityLevelNegotiatedSSL,
NSString(format: kCFStreamSSLValidatesCertificateChain): kCFBooleanFalse,
NSString(format: kCFStreamSSLPeerName): kCFNull,
NSString(format: kCFStreamSSLCertificates): certs,
NSString(format: kCFStreamSSLIsServer): kCFBooleanFalse
]
CFReadStreamSetProperty(inputStream, kCFStreamPropertySSLSettings, sslSettings)
CFWriteStreamSetProperty(outputStream, kCFStreamPropertySSLSettings, sslSettings)
inputStream!.open()
outputStream!.open()
}
func write(text: String) {
let data = [UInt8](text.utf8)
outputStream?.write(data, maxLength: data.count)
}
func CreateCertificateFromFile(filename: String, ext: String) -> SecCertificateRef? {
var cert: SecCertificateRef!
if let path = NSBundle.mainBundle().pathForResource(filename, ofType: ext) {
let data = NSData(contentsOfFile: path)!
cert = SecCertificateCreateWithData(kCFAllocatorDefault, data)!
}
else {
}
return cert
}
func deinitialise() {
inputStream?.close()
outputStream?.close()
}
}
我了解SSL / TLS的工作原理,并且所有这些都是我在同一个应用的Android版本中所做的所有工作。我只是对SSL的iOS实现感到困惑。
我来自Java背景,已经解决了3个星期的问题。任何帮助,将不胜感激。
更喜欢Swift代码中的答案,而不是Objective C,但是如果您只有Obj C也可以:)
好的,我在这个问题上花了8周的时间:(但是我终于设法提出了一个可行的解决方案。我必须说iOS上的SSL /
TLS是个玩笑。Android上的Java会让它死掉。为了这样做,这完全荒谬。评估自签名证书的信任度,您必须完全禁用证书链验证并自己做,这完全荒谬。无论如何,这是使用自签名服务器证书连接到远程套接字服务器(无HTTP)的完全有效的解决方案。编辑此答案以提供更好的答案,因为我还没有添加添加用于发送和接收数据的代码的更改:)
// SecureSocket
//
// Created by snapper26 on 2/9/16.
// Copyright © 2016 snapper26. All rights reserved.
//
import Foundation
class ProXimityAPIClient: NSObject, StreamDelegate {
// Input and output streams for socket
var inputStream: InputStream?
var outputStream: OutputStream?
// Secondary delegate reference to prevent ARC deallocating the NSStreamDelegate
var inputDelegate: StreamDelegate?
var outputDelegate: StreamDelegate?
// Add a trusted root CA to out SecTrust object
func addAnchorToTrust(trust: SecTrust, certificate: SecCertificate) -> SecTrust {
let array: NSMutableArray = NSMutableArray()
array.add(certificate)
SecTrustSetAnchorCertificates(trust, array)
return trust
}
// Create a SecCertificate object from a DER formatted certificate file
func createCertificateFromFile(filename: String, ext: String) -> SecCertificate {
let rootCertPath = Bundle.main.path(forResource:filename, ofType: ext)
let rootCertData = NSData(contentsOfFile: rootCertPath!)
return SecCertificateCreateWithData(kCFAllocatorDefault, rootCertData!)!
}
// Connect to remote host/server
func connect(host: String, port: Int) {
// Specify host and port number. Get reference to newly created socket streams both in and out
Stream.getStreamsToHost(withName:host, port: port, inputStream: &inputStream, outputStream: &outputStream)
// Create strong delegate reference to stop ARC deallocating the object
inputDelegate = self
outputDelegate = self
// Now that we have a strong reference, assign the object to the stream delegates
inputStream!.delegate = inputDelegate
outputStream!.delegate = outputDelegate
// This doesn't work because of arc memory management. Thats why another strong reference above is needed.
//inputStream!.delegate = self
//outputStream!.delegate = self
// Schedule our run loops. This is needed so that we can receive StreamEvents
inputStream!.schedule(in:RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
outputStream!.schedule(in:RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
// Enable SSL/TLS on the streams
inputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: Stream.PropertyKey.socketSecurityLevelKey)
outputStream!.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: Stream.PropertyKey.socketSecurityLevelKey)
// Defin custom SSL/TLS settings
let sslSettings : [NSString: Any] = [
// NSStream automatically sets up the socket, the streams and creates a trust object and evaulates it before you even get a chance to check the trust yourself. Only proper SSL certificates will work with this method. If you have a self signed certificate like I do, you need to disable the trust check here and evaulate the trust against your custom root CA yourself.
NSString(format: kCFStreamSSLValidatesCertificateChain): kCFBooleanFalse,
//
NSString(format: kCFStreamSSLPeerName): kCFNull,
// We are an SSL/TLS client, not a server
NSString(format: kCFStreamSSLIsServer): kCFBooleanFalse
]
// Set the SSL/TLS settingson the streams
inputStream!.setProperty(sslSettings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
outputStream!.setProperty(sslSettings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey)
// Open the streams
inputStream!.open()
outputStream!.open()
}
// This is where we get all our events (haven't finished writing this class)
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.endEncountered:
print("End Encountered")
break
case Stream.Event.openCompleted:
print("Open Completed")
break
case Stream.Event.hasSpaceAvailable:
print("Has Space Available")
// If you try and obtain the trust object (aka kCFStreamPropertySSLPeerTrust) before the stream is available for writing I found that the oject is always nil!
var sslTrustInput: SecTrust? = inputStream! .property(forKey:kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust?
var sslTrustOutput: SecTrust? = outputStream!.property(forKey:kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust?
if (sslTrustInput == nil) {
print("INPUT TRUST NIL")
}
else {
print("INPUT TRUST NOT NIL")
}
if (sslTrustOutput == nil) {
print("OUTPUT TRUST NIL")
}
else {
print("OUTPUT TRUST NOT NIL")
}
// Get our certificate reference. Make sure to add your root certificate file into your project.
let rootCert: SecCertificate? = createCertificateFromFile(filename: "ca", ext: "der")
// TODO: Don't want to keep adding the certificate every time???
// Make sure to add your trusted root CA to the list of trusted anchors otherwise trust evaulation will fail
sslTrustInput = addAnchorToTrust(trust: sslTrustInput!, certificate: rootCert!)
sslTrustOutput = addAnchorToTrust(trust: sslTrustOutput!, certificate: rootCert!)
// convert kSecTrustResultUnspecified type to SecTrustResultType for comparison
var result: SecTrustResultType = SecTrustResultType.unspecified
// This is it! Evaulate the trust.
let error: OSStatus = SecTrustEvaluate(sslTrustInput!, &result)
// An error occured evaluating the trust check the OSStatus codes for Apple at osstatus.com
if (error != noErr) {
print("Evaluation Failed")
}
if (result != SecTrustResultType.proceed && result != SecTrustResultType.unspecified) {
// Trust failed. This will happen if you faile to add the trusted anchor as mentioned above
print("Peer is not trusted :(")
}
else {
// Peer certificate is trusted. Now we can send data. Woohoo!
print("Peer is trusted :)")
}
break
case Stream.Event.hasBytesAvailable:
print("Has Bytes Available")
break
case Stream.Event.errorOccurred:
print("Error Occured")
break
default:
print("Default")
break
}
}
}
问题内容: Swift中是否有代表可以通过计算机的USB插入新设备时让我的班级知道?我想知道何时有新设备可供我的程序使用。 问题答案: 这个答案对我有用但是它需要一些修改,例如创建桥接头以导入某些特定的IOKit部件。 首先,将IOKit.framework添加到您的项目中(在“链接的框架和库”中单击“ +”)。 然后创建一个新的空“ .m”文件,无论其名称如何。然后,Xcode将询问是否应创建“
问题内容: 如何在Swift中连接字符串? 在我们喜欢 要么 但是我想用Swift语言做到这一点。 问题答案: 您可以通过多种方式连接字符串: 您也可以这样做: 我相信还有更多方法。 描述位 创建一个常数。(有点像)。设置后就无法更改其值。您仍然可以将其添加到其他东西并创建新变量。 创建一个变量。(有点像),因此您可以更改其值。 注意 在现实中,并有 很大的不同 ,从和,但它可以帮助类比。
我需要将字符串和Int串联起来,如下所示: 但它没有编译,错误如下: 二进制运算符“”不能应用于“String”和“Int”类型的操作数 连接字符串Int的正确方法是什么?
如果有两个数组在swift中创建,如下所示: 如何将它们合并为< code>[1,2,3,4,5,6]?
我正在为Swift使用框架。我试图通过websockets API连接,我有一个方法,它在的中被调用。我已经全局声明了我的manager和socketClient,我将把方法的代码放在下面: 我面临的问题是没有调用回调,因此无法发出ping消息。以下是日志: 2018-02-18 19:02:20.589916+0530股票-蛋糕[10965:3662189]日志SocketManager:添加引
我从Android获得.ovpn文件,我有用户名和密码,我应该连接到vpn服务器,但我不确定如何做到这一点。我试过这样的东西: 我不知道如何添加证书(in.ovpn)信息以及如何设置它。ovpn如下所示(我只是删除标记中的数据并更改服务器地址: 谢谢你的帮助