我在使用Ingenico iPP320设备建立SSL / TLS连接时遇到问题。我尝试过建议here的解决方案,但我收到此错误
CFNetwork SSLHandshake failed (-9824 -> -9829)
我是使用SSL / TLS连接的新手,不知道如何建立连接。我正在使用的是受密码保护的p12文件,证书也不是自签名的。我被告知服务器也必须对客户端进行身份验证,因此可能必须将中间CA和根CA发送到服务器。我能够在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 :(得分:0)
对于其他试图使用P12证书进行TLS连接的人来说,这就是我提出的解决方案。如果有人有更好的方法,请让我知道谢谢。
//
// 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
}
}