2016-11-01 8 views
0

У меня возникли проблемы с установкой соединения SSL/TLS с устройством Ingenico iPP320. Я попробовал решение, предложенное here, но я получаю эту ошибкуПодключение TLS по быстрому рукопожатию iOS вопрос

CFNetwork SSLHandshake failed (-9824 -> -9829) 

Я новичок, используя SSL/TLS соединений и не знаю, как я должен идти о том, чтобы установить соединение. То, что я использую, - это файл p12, защищенный паролем, и сертификат не является самоподписанным. Мне сказали, что сервер должен будет также аутентифицировать клиента, поэтому промежуточный и корневой ЦС, возможно, придется отправить на сервер. Я смог получить аутентификацию, работающую на Android, но я не уверен, как это сделать в iOS.

Ниже приведен код Android, который работает.

public SSLSocket createSSLSocket(String ipAddress, int port) 
{ 
    try 
    { 
     SSLSocket socket = null; 
     String certStorePassword = "password"; 
     String certStoreType = "pkcs12"; 

     InputStream iStream = getResources().openRawResource(R.raw.clientP12File); 

     KeyStore keyStore = KeyStore.getInstance(certStoreType); 
     keyStore.load(iStream, certStorePassword.toCharArray()); 
//   KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); 
     KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
     keyManagerFactory.init(keyStore, certStorePassword.toCharArray()); 

     SSLContext sc = SSLContext.getInstance("TLS"); 
     sc.init(keyManagerFactory.getKeyManagers(), trustAllCerts, new SecureRandom()); 
     SSLContext.setDefault(sc); 
     SSLSocketFactory factory = sc.getSocketFactory(); 
     socket = (SSLSocket) factory.createSocket(ipAddress, port); 
     socket.setEnabledProtocols(new String[] { "TLSv1.2" }); 
     socket.setUseClientMode(true); 
     socket.startHandshake(); 
     return socket; 
    } 
    catch (Exception ex) { 
     Log.e(TAG, "createSSLSocket: ", ex); 
    } 

    return null; 
} 

ответ

0

Для всех, кто пытается подключиться TLS к сертификату P12, это было решение, с которым я столкнулся. Если у кого-то есть лучший способ сделать это, пожалуйста, дайте мне знать спасибо.

// 
// SSLConnection.swift 
// SSLConnection 
// 
// Created by JC Castano on 3/27/17. 
// Copyright © 2017 1stPayGateway. All rights reserved. 
// 

import Foundation 

class SSLConnection: NSObject, StreamDelegate { 

    private static var inputStream:InputStream! 
    private static var outputStream:OutputStream! 
    private var ipAddress:String = "" 
    private var sslEnabled: Bool = false 

    public func connectToIngenico(address:String, sslEnabled: Bool) { 

     // TODO: Create dispatch queue to handle Ingenico connection 
     //  initIngenicoQueue() 

     self.ipAddress = address 

     var readStream: Unmanaged<CFReadStream>? 
     var writeStream: Unmanaged<CFWriteStream>? 

     CFStreamCreatePairWithSocketToHost(nil, address as CFString!,12000, &readStream, &writeStream) 

     // Documentation suggests readStream and writeStream can be assumed to 
     // be non-nil. If you believe otherwise, you can test if either is nil 
     // and implement whatever error-handling you wish. 

     SSLConnection.inputStream = readStream!.takeRetainedValue() 
     SSLConnection.outputStream = writeStream!.takeRetainedValue() 

     SSLConnection.inputStream.delegate = self 
     SSLConnection.outputStream.delegate = self 

     SSLConnection.inputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) 
     SSLConnection.outputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) 

     if sslEnabled { 

      // Enable SSL/TLS on the streams 
      SSLConnection.inputStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL, forKey: Stream.PropertyKey.socketSecurityLevelKey) 
      SSLConnection.outputStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL, forKey: Stream.PropertyKey.socketSecurityLevelKey) 

      let sslSettings = [ 

       // 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, 

       // We are an SSL/TLS client, not a server 
       NSString(format: kCFStreamSSLIsServer): kCFBooleanFalse, 

       // Get the key chain items and add it to ssl settings 
       NSString(format: kCFStreamSSLCertificates): getKeyChain(fileName: "CLIENT", ofType: "p12", password: "password") 
      ] as [NSString : Any] 

      SSLConnection.inputStream.setProperty(sslSettings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey) 
      SSLConnection.outputStream.setProperty(sslSettings, forKey: kCFStreamPropertySSLSettings as Stream.PropertyKey) 

     } 

     SSLConnection.inputStream.open() 
     SSLConnection.outputStream.open() 
    } 

    func getKeyChain(fileName: String, ofType type: String, password: String) -> CFArray { 

     let mainBundle = Bundle.main 
     let thePath = mainBundle.path(forResource: fileName, ofType: type)! 

     let PKCS12Data: NSData = NSData(contentsOfFile: thePath)! 

     var items: CFArray? 
     let optionDict: NSMutableDictionary = [kSecImportExportPassphrase as NSString: password] 
     let sanityCheck = SecPKCS12Import(PKCS12Data, optionDict, &items) 

     if sanityCheck == errSecSuccess && CFArrayGetCount(items) > 0 { 
      return parseKeyChainItems(items!) 
     } else { 
      switch sanityCheck { 
      case errSecSuccess: 
       print("Error importing p12: errSecSuccess") 
      case errSecUnimplemented: 
       print("Error importing p12: errSecUnimplemented") 
      case errSecIO: 
       print("Error importing p12: errSecIO") 
      case errSecOpWr: 
       print("Error importing p12: errSecOpWr") 
      case errSecParam: 
       print("Error importing p12: errSecParam") 
      case errSecAllocate: 
       print("Error importing p12: errSecAllocate") 
      case errSecUserCanceled: 
       print("Error importing p12: errSecUserCanceled") 
      case errSecBadReq: 
       print("Error importing p12: errSecBadReq") 
      case errSecInternalComponent: 
       print("Error importing p12: errSecInternalComponent") 
      case errSecNotAvailable: 
       print("Error importing p12: errSecNotAvailable") 
      case errSecDuplicateItem: 
       print("Error importing p12: errSecDuplicateItem") 
      case errSecItemNotFound: 
       print("Error importing p12: errSecItemNotFound") 
      case errSecInteractionNotAllowed: 
       print("Error importing p12: errSecInteractionNotAllowed") 
      case errSecDecode: 
       print("Error importing p12: errSecDecode") 
      case errSecAuthFailed: 
       print("Error importing p12: errSecAuthFailed") 
      default: 
       print("Error importing p12: Unknown items: \(items)") 
       break 
      } 
     } 
     return [] as CFArray 
    } 

    func parseKeyChainItems(_ keychainArray: NSArray) -> CFArray { 
     print("Key chain array: \(keychainArray)") 
     let dict = keychainArray[0] as! Dictionary<String,AnyObject> 
     let key = String(kSecImportItemIdentity) 
     let identity = dict[key] as! SecIdentity? 

     let certArray:[AnyObject] = dict["chain"] as! [SecCertificate] 

     var certChain:[AnyObject] = [identity!] 

     for item in certArray { 
      certChain.append(item) 
     } 
     return certChain as CFArray 
    } 

    func stream(_ aStream: Stream, handle eventCode: Stream.Event) { 
     let streamName = getStreamName(aStream) 

     switch eventCode { 
     case Stream.Event.openCompleted: 
      print("\(streamName).OpenCompleted") 
      break 
     case Stream.Event.hasBytesAvailable: 
      print("\(streamName).HasBytesAvailable") 
     case Stream.Event.hasSpaceAvailable: 
      print("\(streamName).HasSpaceAvailable") 
      break 
     case Stream.Event.endEncountered: 
      print("\(streamName).EndEncountered") 
      break 
     case Stream.Event.errorOccurred: 
      print("\(streamName).ErrorOccurred") 
      break 
     default: 
      print("\(streamName) unknown event") 
      break 
     } 
    } 

    func getStreamName(_ aStream: Stream) -> String { 

     if comparedStreamEqual(aStream, bStream: SSLConnection.inputStream) { 
      return "InputStream" 
     } else if comparedStreamEqual(aStream, bStream: SSLConnection.outputStream) { 
      return "OutputStream" 
     } 
     return "UnknownStream" 
    } 

    func comparedStreamEqual(_ aStream: Stream? , bStream: Stream?) -> Bool { 
     if aStream != nil && bStream != nil { 
      if aStream == bStream { 
       return true 
      } 
     } 
     return false 
    } 

}