Swift中的iOS SSL连接

前端之家收集整理的这篇文章主要介绍了Swift中的iOS SSL连接前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试从我的iOS应用程序到我的后端服务器(Node.js)建立一个简单的套接字连接(无HTTP).已使用我自己创建的自定义CA创建并签署了服务器证书.我相信,为了让iOS信任我的服务器,我必须以某种方式将这个自定义CA证书添加到可信证书列表中,这些证书用于确定Java / Android中的TrustStore如何工作的信任类型.

我尝试使用下面的代码进行连接,但没有错误,但write()函数似乎没有成功.

主视图控制器:

  1. override func viewDidLoad() {
  2. super.viewDidLoad()
  3. // Do any additional setup after loading the view,typically from a nib.
  4.  
  5. let api: APIClient = APIClient()
  6.  
  7. api.initialiseSSL("10.13.37.200",port: 8080)
  8.  
  9. api.write("Hello")
  10.  
  11. api.deinitialise()
  12.  
  13. print("Done")
  14. }

APIClient类

  1. class APIClient: NSObject,NSStreamDelegate {
  2.  
  3. var readStream: Unmanaged<CFReadStreamRef>?
  4. var writeStream: Unmanaged<CFWriteStreamRef>?
  5.  
  6. var inputStream: NSInputStream?
  7. var outputStream: NSOutputStream?
  8.  
  9. func initialiseSSL(host: String,port: UInt32) {
  10. CFStreamCreatePairWithSocketToHost(kcfAllocatorDefault,host,port,&readStream,&writeStream)
  11.  
  12. inputStream = readStream!.takeRetainedValue()
  13. outputStream = writeStream!.takeRetainedValue()
  14.  
  15. inputStream?.delegate = self
  16. outputStream?.delegate = self
  17.  
  18. inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(),forMode: NSDefaultRunLoopMode)
  19. outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(),forMode: NSDefaultRunLoopMode)
  20.  
  21. let cert: SecCertificateRef? = CreateCertificateFromFile("ca",ext: "der")
  22.  
  23. if cert != nil {
  24. print("GOT CERTIFICATE")
  25. }
  26.  
  27. let certs: NSArray = NSArray(objects: cert!)
  28.  
  29. let sslSettings = [
  30. NSString(format: kcfStreamSSLLevel): kcfStreamSocketSecurityLevelNegotiatedSSL,NSString(format: kcfStreamSSLValidatesCertificateChain): kcfBooleanFalse,NSString(format: kcfStreamSSLPeerName): kcfNull,NSString(format: kcfStreamSSLCertificates): certs,NSString(format: kcfStreamSSLIsServer): kcfBooleanFalse
  31. ]
  32.  
  33. CFReadStreamSetProperty(inputStream,kcfStreamPropertySSLSettings,sslSettings)
  34. CFWriteStreamSetProperty(outputStream,sslSettings)
  35.  
  36. inputStream!.open()
  37. outputStream!.open()
  38. }
  39.  
  40. func write(text: String) {
  41. let data = [UInt8](text.utf8)
  42.  
  43. outputStream?.write(data,maxLength: data.count)
  44. }
  45.  
  46. func CreateCertificateFromFile(filename: String,ext: String) -> SecCertificateRef? {
  47. var cert: SecCertificateRef!
  48.  
  49. if let path = NSBundle.mainBundle().pathForResource(filename,ofType: ext) {
  50.  
  51. let data = NSData(contentsOfFile: path)!
  52.  
  53. cert = SecCertificateCreateWithData(kcfAllocatorDefault,data)!
  54. }
  55. else {
  56.  
  57. }
  58.  
  59. return cert
  60. }
  61.  
  62. func deinitialise() {
  63. inputStream?.close()
  64. outputStream?.close()
  65. }

}

我理解SSL / TLS是如何工作的,因为我在同一个应用程序的Android版本中完成了这一切.我只是对SSL的iOS实现感到困惑.

我来自Java背景,已经解决了这个问题3周.任何帮助,将不胜感激.

喜欢Swift代码中的答案,而不是目标C,但如果你只有Obj C那也可以:)

好吧,我在这个问题上花了8个星期:(但我终于设法组建了一个有效的解决方案.我必须说iOS上的SSL / TLS是一个笑话.Java Android上的Java让它死了.这是完全荒谬的,为了评估自签名证书的信任,您必须完全禁用证书链验证并自行完成.完全荒谬.无论如何,这是使用自签名服务器证书连接到远程套接字服务器(无HTTP)的完全可用的解决方案.编辑这个答案以提供更好的答案,因为我还没有更改添加发送和接收数据的代码:)
  1. // SecureSocket
  2. //
  3. // Created by snapper26 on 2/9/16.
  4. // Copyright © 2016 snapper26. All rights reserved.
  5. //
  6. import Foundation
  7.  
  8. class ProXimityAPIClient: NSObject,StreamDelegate {
  9.  
  10. // Input and output streams for socket
  11. var inputStream: InputStream?
  12. var outputStream: OutputStream?
  13.  
  14. // Secondary delegate reference to prevent ARC deallocating the NSStreamDelegate
  15. var inputDelegate: StreamDelegate?
  16. var outputDelegate: StreamDelegate?
  17.  
  18. // Add a trusted root CA to out SecTrust object
  19. func addAnchorToTrust(trust: SecTrust,certificate: SecCertificate) -> SecTrust {
  20. let array: NSMutableArray = NSMutableArray()
  21.  
  22. array.add(certificate)
  23.  
  24. SecTrustSetAnchorCertificates(trust,array)
  25.  
  26. return trust
  27. }
  28.  
  29. // Create a SecCertificate object from a DER formatted certificate file
  30. func createCertificateFromFile(filename: String,ext: String) -> SecCertificate {
  31. let rootCertPath = Bundle.main.path(forResource:filename,ofType: ext)
  32.  
  33. let rootCertData = NSData(contentsOfFile: rootCertPath!)
  34.  
  35. return SecCertificateCreateWithData(kcfAllocatorDefault,rootCertData!)!
  36. }
  37.  
  38. // Connect to remote host/server
  39. func connect(host: String,port: Int) {
  40. // Specify host and port number. Get reference to newly created socket streams both in and out
  41. Stream.getStreamsToHost(withName:host,port: port,inputStream: &inputStream,outputStream: &outputStream)
  42.  
  43. // Create strong delegate reference to stop ARC deallocating the object
  44. inputDelegate = self
  45. outputDelegate = self
  46.  
  47. // Now that we have a strong reference,assign the object to the stream delegates
  48. inputStream!.delegate = inputDelegate
  49. outputStream!.delegate = outputDelegate
  50.  
  51. // This doesn't work because of arc memory management. Thats why another strong reference above is needed.
  52. //inputStream!.delegate = self
  53. //outputStream!.delegate = self
  54.  
  55. // Schedule our run loops. This is needed so that we can receive StreamEvents
  56. inputStream!.schedule(in:RunLoop.main,forMode: RunLoopMode.defaultRunLoopMode)
  57. outputStream!.schedule(in:RunLoop.main,forMode: RunLoopMode.defaultRunLoopMode)
  58.  
  59. // Enable SSL/TLS on the streams
  60. inputStream!.setProperty(kcfStreamSocketSecurityLevelNegotiatedSSL,forKey: Stream.PropertyKey.socketSecurityLevelKey)
  61. outputStream!.setProperty(kcfStreamSocketSecurityLevelNegotiatedSSL,forKey: Stream.PropertyKey.socketSecurityLevelKey)
  62.  
  63. // Defin custom SSL/TLS settings
  64. let sslSettings : [NSString: Any] = [
  65. // 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.
  66. NSString(format: kcfStreamSSLValidatesCertificateChain): kcfBooleanFalse,//
  67. NSString(format: kcfStreamSSLPeerName): kcfNull,// We are an SSL/TLS client,not a server
  68. NSString(format: kcfStreamSSLIsServer): kcfBooleanFalse
  69. ]
  70.  
  71. // Set the SSL/TLS settingson the streams
  72. inputStream!.setProperty(sslSettings,forKey: kcfStreamPropertySSLSettings as Stream.PropertyKey)
  73. outputStream!.setProperty(sslSettings,forKey: kcfStreamPropertySSLSettings as Stream.PropertyKey)
  74.  
  75. // Open the streams
  76. inputStream!.open()
  77. outputStream!.open()
  78. }
  79.  
  80. // This is where we get all our events (haven't finished writing this class)
  81. func stream(_ aStream: Stream,handle eventCode: Stream.Event) {
  82. switch eventCode {
  83. case Stream.Event.endEncountered:
  84. print("End Encountered")
  85. break
  86. case Stream.Event.openCompleted:
  87. print("Open Completed")
  88. break
  89. case Stream.Event.hasSpaceAvailable:
  90. print("Has Space Available")
  91.  
  92. // 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!
  93. var sslTrustInput: SecTrust? = inputStream! .property(forKey:kcfStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust?
  94. var sslTrustOutput: SecTrust? = outputStream!.property(forKey:kcfStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust?
  95.  
  96. if (sslTrustInput == nil) {
  97. print("INPUT TRUST NIL")
  98. }
  99. else {
  100. print("INPUT TRUST NOT NIL")
  101. }
  102.  
  103. if (sslTrustOutput == nil) {
  104. print("OUTPUT TRUST NIL")
  105. }
  106. else {
  107. print("OUTPUT TRUST NOT NIL")
  108. }
  109.  
  110. // Get our certificate reference. Make sure to add your root certificate file into your project.
  111. let rootCert: SecCertificate? = createCertificateFromFile(filename: "ca",ext: "der")
  112.  
  113. // TODO: Don't want to keep adding the certificate every time???
  114. // Make sure to add your trusted root CA to the list of trusted anchors otherwise trust evaulation will fail
  115. sslTrustInput = addAnchorToTrust(trust: sslTrustInput!,certificate: rootCert!)
  116. sslTrustOutput = addAnchorToTrust(trust: sslTrustOutput!,certificate: rootCert!)
  117.  
  118. // convert kSecTrustResultUnspecified type to SecTrustResultType for comparison
  119. var result: SecTrustResultType = SecTrustResultType.unspecified
  120.  
  121. // This is it! Evaulate the trust.
  122. let error: OSStatus = SecTrustEvaluate(sslTrustInput!,&result)
  123.  
  124. // An error occured evaluating the trust check the OSStatus codes for Apple at osstatus.com
  125. if (error != noErr) {
  126. print("Evaluation Failed")
  127. }
  128.  
  129. if (result != SecTrustResultType.proceed && result != SecTrustResultType.unspecified) {
  130. // Trust Failed. This will happen if you faile to add the trusted anchor as mentioned above
  131. print("Peer is not trusted :(")
  132. }
  133. else {
  134. // Peer certificate is trusted. Now we can send data. Woohoo!
  135. print("Peer is trusted :)")
  136. }
  137.  
  138. break
  139. case Stream.Event.hasBytesAvailable:
  140. print("Has Bytes Available")
  141. break
  142. case Stream.Event.errorOccurred:
  143. print("Error Occured")
  144. break
  145. default:
  146. print("Default")
  147. break
  148. }
  149. }
  150. }

猜你在找的Swift相关文章