Swift中的iOS SSL连接

用户名

我正在尝试从我的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
        }
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

SSL套接字连接iOS

来自分类Dev

iOS webview SSL连接(kCFStreamErrorDomainSSL,-9843)

来自分类Dev

Android WebSocket中的SSL连接错误

来自分类Dev

连接中的未知SSL协议错误

来自分类Dev

Java中的密钥SSL套接字连接

来自分类Dev

在Python中打开SSL套接字连接

来自分类Dev

SSL连接读取中的垃圾值

来自分类Dev

httr / curl中的SSL连接错误

来自分类Dev

SSL HttpClient连接中的会话过期错误

来自分类Dev

Android Websocket中的SSL连接错误

来自分类Dev

无法连接(尝试在ubuntu中设置SSL)

来自分类Dev

Java中MQTT的TLS / SSL连接

来自分类Dev

如何连接使用 QT 中的 SSL Websocket

来自分类Dev

在iOS中使用SSL连接到Twitter API

来自分类Dev

NodeJS中的AWS RDS SSL中的连接错误

来自分类Dev

如何验证SSL中PDO中的连接是否安全?

来自分类Dev

fopen():SSL:php中的对等错误重置连接

来自分类Dev

在给定的Java代码中禁用SSL连接

来自分类Dev

在C ++中通过SSL进行简单的数据库连接

来自分类Dev

连接到Google Analytics API时Java中的SSL例外

来自分类Dev

JAVA中的SSL套接字连接池

来自分类Dev

Ubuntu linux 上的 R 和 SSL/curl:在 R 中 SSL 连接失败,但在 curl 中有效

来自分类常见问题

iOS9收到错误“发生SSL错误,无法建立与服务器的安全连接”

来自分类Dev

iOS-推送通知,连接到Apple APNS服务器的SSL错误

来自分类Dev

iOS NSURL与带有https://的NSURL的连接正在使用TLS或SSL

来自分类Dev

iOS-推送通知,连接到Apple APNS服务器的SSL错误

来自分类Dev

使用 alamofire 通过 iOS 应用程序连接到 Windows SSL 服务器

来自分类Dev

在Codeigniter中无法发送电子邮件-fsockopen():无法连接到ssl://smtp.gmail.com:465(连接被拒绝)

来自分类Dev

Google Apps脚本中JDBC连接的URL参数中的SSL属性

Related 相关文章

  1. 1

    SSL套接字连接iOS

  2. 2

    iOS webview SSL连接(kCFStreamErrorDomainSSL,-9843)

  3. 3

    Android WebSocket中的SSL连接错误

  4. 4

    连接中的未知SSL协议错误

  5. 5

    Java中的密钥SSL套接字连接

  6. 6

    在Python中打开SSL套接字连接

  7. 7

    SSL连接读取中的垃圾值

  8. 8

    httr / curl中的SSL连接错误

  9. 9

    SSL HttpClient连接中的会话过期错误

  10. 10

    Android Websocket中的SSL连接错误

  11. 11

    无法连接(尝试在ubuntu中设置SSL)

  12. 12

    Java中MQTT的TLS / SSL连接

  13. 13

    如何连接使用 QT 中的 SSL Websocket

  14. 14

    在iOS中使用SSL连接到Twitter API

  15. 15

    NodeJS中的AWS RDS SSL中的连接错误

  16. 16

    如何验证SSL中PDO中的连接是否安全?

  17. 17

    fopen():SSL:php中的对等错误重置连接

  18. 18

    在给定的Java代码中禁用SSL连接

  19. 19

    在C ++中通过SSL进行简单的数据库连接

  20. 20

    连接到Google Analytics API时Java中的SSL例外

  21. 21

    JAVA中的SSL套接字连接池

  22. 22

    Ubuntu linux 上的 R 和 SSL/curl:在 R 中 SSL 连接失败,但在 curl 中有效

  23. 23

    iOS9收到错误“发生SSL错误,无法建立与服务器的安全连接”

  24. 24

    iOS-推送通知,连接到Apple APNS服务器的SSL错误

  25. 25

    iOS NSURL与带有https://的NSURL的连接正在使用TLS或SSL

  26. 26

    iOS-推送通知,连接到Apple APNS服务器的SSL错误

  27. 27

    使用 alamofire 通过 iOS 应用程序连接到 Windows SSL 服务器

  28. 28

    在Codeigniter中无法发送电子邮件-fsockopen():无法连接到ssl://smtp.gmail.com:465(连接被拒绝)

  29. 29

    Google Apps脚本中JDBC连接的URL参数中的SSL属性

热门标签

归档